ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

交通标志识别工业级方案:YOLOv5s轻量化+双路径分类

交通标志识别工业级方案:YOLOv5s轻量化+双路径分类 简介这是一套面向高校计算机、人工智能等专业学生的交通标志智能检测与识别毕业设计项目基于Python实现端到端图像识别流程覆盖数据预处理、模型训练、推理部署等核心环节适用于课程设计、综合实验及毕设实践。资源包共298个文件含29个核心Python源码含主程序、训练脚本、评估模块、63组TensorFlow模型权重文件data/meta/index用于加载已验证模型、10个checkpoint保障训练可续性以及jpg样本图、txt标注说明、md项目文档和预处理数据集整体压缩包54.96MB结构完整、即下即用。目前已有40人学习下载资源经导师指导并获评优秀附带详尽技术文档与可复现代码帮助学习者深入理解YOLO或CNN类模型在交通场景中的实际应用逻辑、数据组织方式及常见调试要点。1. 为什么交通标志识别不能只靠OpenCV阈值分割这套Python源码给出了工业级答案在校园路口部署一个能实时识别“禁止左转”“限速40”标志的系统很多同学第一反应是用OpenCV做颜色形状匹配——结果在阴天、逆光、雨雾或夜间几乎全军覆没。这套毕业设计级的Python交通标志智能检测与识别系统恰恰绕开了传统图像处理的脆弱性陷阱它用YOLOv5s作为检测 backbone配合自训练的轻量级CNN分类器在德国GTSRB数据集上达到98.2% mAP0.5更关键的是它把模型剪枝、TensorRT加速、OpenCV视频流解码与推理调度全部封装进可直接运行的main.py中。整套代码不依赖CUDA环境CPU模式下仍可3.2 FPS预置了从原始图片到标注文件生成、模型微调、导出ONNX再到嵌入式部署的完整链路。适合计算机/人工智能专业学生做毕设、课程设计也适合作为视觉类综合实验的基准项目——不是玩具Demo而是经导师验收、带测试报告、含数据清洗脚本的真实工程切片。2. YOLOv5s检测模块的轻量化改造与数据增强策略交通标志尺寸小、类别多、背景干扰强直接套用YOLOv5官方权重会导致漏检率高、误报频繁。本项目对检测模块进行了三处关键改造全部体现在models/yolov5s_custom.yaml和train.py中而非简单调参。2.1 检测头结构适配小目标增加P2层输出分支标准YOLOv5s输出三个尺度特征图P3/P4/P5但交通标志在640×480输入下常仅占20×20像素P380×60已接近分辨率下限。项目在yolov5s_custom.yaml中新增P2层160×120输出分支# models/yolov5s_custom.yaml 片段 backbone: # ... 原始backbone定义 head: - [-1, 1, Conv, [512, 3, 2]] # P2 downsample - [[-1, 6], 1, Concat, [1]] # concat P2 with original P2 route - [-1, 3, C3, [512, False]] # new P2 head - [-1, 1, Conv, [256, 3, 1]] - [-1, 1, nn.Upsample, [None, 2, nearest]] - [[-1, 4], 1, Concat, [1]] - [-1, 3, C3, [256, False]] # P3 head (original) # ... 后续P4/P5保持不变提示P2分支使小目标召回率提升12.7%但会增加约18%推理耗时。若部署在树莓派4B上需在detect.py中设置--img-size 320并关闭P2分支注释掉对应head层此时mAP下降至95.1%但FPS升至5.8。2.2 针对交通标志的数据增强组合MosaicHSV仿射扰动GTSRB原始数据集存在光照单一、角度固定问题。项目在datasets/traffic_sign_dataset.py中实现定制化增强流水线# datasets/traffic_sign_dataset.py 中的 __getitem__ 方法片段 def augment_hsv(img, hgain0.015, sgain0.7, vgain0.4): r np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] 1 hue, sat, val cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV)) dtype img.dtype x np.arange(0, 256, dtypenp.int16) lut_hue ((x * r[0]) % 180).astype(dtype) lut_sat np.clip(x * r[1], 0, 255).astype(dtype) lut_val np.clip(x * r[2], 0, 255).astype(dtype) img_hsv cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))) return cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR) def random_perspective(img, targets, degrees10, translate0.1, scale0.1, shear10): # 仿射变换参数旋转±10°、平移±10%、缩放±10%、错切±10° # 关键仅对bounding box应用相同变换避免标签偏移 M cv2.getRotationMatrix2D((img.shape[1]/2, img.shape[0]/2), np.random.uniform(-degrees, degrees), 1.0 np.random.uniform(-scale, scale)) # ... 省略完整矩阵计算实际代码含bbox坐标同步变换逻辑表增强策略对各类别漏检率的影响测试集统计类别原始增强漏检率本项目增强漏检率下降幅度限速308.2%2.1%6.1%注意行人15.7%4.3%11.4%禁止停车12.4%3.8%8.6%左转箭头22.9%7.5%15.4%2.3 标签格式统一与自动校验解决GTSRB标注不一致问题GTSRB提供两种标注格式CSV坐标 vs. bounding box文件且部分样本存在坐标越界、宽高为0等错误。项目在utils/preprocess_gtsrb.py中内置校验逻辑# utils/preprocess_gtsrb.py def validate_bbox(xmin, ymin, xmax, ymax, img_w, img_h): 强制修正越界bbox返回归一化xywh格式 xmin max(0, min(xmin, img_w - 1)) ymin max(0, min(ymin, img_h - 1)) xmax max(xmin 1, min(xmax, img_w)) ymax max(ymin 1, min(ymax, img_h)) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h return [x_center, y_center, width, height] # 执行校验并生成YOLO格式label文件 for img_path in glob.glob(gtsrb/train/*/*.ppm): label_path img_path.replace(.ppm, .txt) with open(label_path, r) as f: raw f.readline().strip().split(;) # GTSRB CSV格式filename;class_id;xmin;ymin;width;height _, cls_id, xmin, ymin, w, h raw xmin, ymin, w, h map(int, [xmin, ymin, w, h]) xmax, ymax xmin w, ymin h norm_bbox validate_bbox(xmin, ymin, xmax, ymax, 1360, 800) # GTSRB原始分辨率 with open(flabels/{Path(img_path).stem}.txt, w) as out: out.write(f{cls_id} { .join(map(str, norm_bbox))}\n)注意该脚本会自动跳过所有宽高比0.2或5.0的异常框如误标为整张图的噪声并在logs/preprocess_report.txt中记录被过滤样本ID避免静默丢弃导致类别不平衡。3. 分类模块的双路径设计与模型蒸馏实践检测框输出后传统做法是裁剪ROI送入独立CNN分类器。但本项目发现当标志被遮挡如树枝半挡、低分辨率监控远摄或极端角度时单次裁剪分类准确率骤降至73.5%。为此项目采用“检测框全局上下文”双路径输入策略并引入知识蒸馏提升小模型性能。3.1 双路径CNN架构Local-Global Feature Fusion分类网络定义于models/classifier.py核心是Local Path裁剪区域与Global Path整图缩放的特征拼接# models/classifier.py class TrafficSignClassifier(nn.Module): def __init__(self, num_classes43, local_size64, global_size224): super().__init__() # Local Path: 处理64×64裁剪图 self.local_backbone torchvision.models.resnet18(pretrainedFalse) self.local_backbone.conv1 nn.Conv2d(3, 64, 3, 1, 1) # 修改首层适配小图 self.local_backbone.fc nn.Identity() # Global Path: 处理224×224整图保留场景信息 self.global_backbone torchvision.models.mobilenet_v2(pretrainedTrue) self.global_backbone.classifier nn.Identity() # 特征融合层 self.fusion nn.Sequential( nn.Linear(512 1280, 512), # resnet18 fc512, mobilenet_v2 last layer1280 nn.ReLU(), nn.Dropout(0.3), nn.Linear(512, num_classes) ) def forward(self, local_img, global_img): local_feat self.local_backbone(local_img) # [B, 512] global_feat self.global_backbone(global_img) # [B, 1280] fused torch.cat([local_feat, global_feat], dim1) return self.fusion(fused)表双路径vs单路径在挑战场景下的准确率对比测试集子集场景类型单路径裁剪双路径LocalGlobal提升正常光照96.8%97.1%0.3%部分遮挡73.5%89.2%15.7%远距离小目标68.4%84.6%16.2%强逆光52.1%76.3%24.2%3.2 使用YOLO检测器作为教师模型进行知识蒸馏为压缩分类器体积便于树莓派部署项目用YOLOv5s的cls_confidence输出作为软标签指导轻量级分类器学习# train_classifier.py 中的蒸馏损失计算 def distillation_loss(student_logits, teacher_probs, temperature3.0, alpha0.7): student_logits: 学生模型原始logits (B, 43) teacher_probs: 教师模型softmax输出 (B, 43)已用temperature缩放 alpha: 蒸馏损失权重0~1剩余部分用真实标签交叉熵 soft_student F.log_softmax(student_logits / temperature, dim1) soft_teacher torch.log(teacher_probs 1e-8) # 防止log(0) kd_loss F.kl_div(soft_student, soft_teacher, reductionbatchmean) * (temperature ** 2) ce_loss F.cross_entropy(student_logits, true_labels) return alpha * kd_loss (1 - alpha) * ce_loss # 在训练循环中调用 with torch.no_grad(): # 获取YOLO检测器对同一batch的cls confidence已归一化 teacher_preds yolov5_model(batch_images)[cls_probs] # [B, 43] loss distillation_loss(student_output, teacher_preds, temperature3.0, alpha0.5)提示蒸馏温度T3.0使教师模型输出更平滑突出类别间相对关系α0.5平衡知识迁移与真实标签监督。实测蒸馏后模型参数量减少37%Top-1准确率仅下降0.9%但推理速度提升2.3倍。4. 视频流实时推理的Pipeline调度与资源管控main.py不是简单调用cv2.VideoCapturemodel.predict()而是构建了带帧缓冲、异步推理、结果缓存的生产级Pipeline解决USB摄像头卡顿、GPU显存溢出、多标志重叠判定等实际问题。4.1 基于队列的生产者-消费者模式解耦采集与推理# main.py 核心调度逻辑 class InferencePipeline: def __init__(self, model_pathweights/best.pt, max_queue_size4): self.frame_queue queue.Queue(maxsizemax_queue_size) self.result_queue queue.Queue(maxsizemax_queue_size) self.model torch.hub.load(ultralytics/yolov5, custom, pathmodel_path) self.model.conf 0.4 # 置信度阈值 self.model.iou 0.5 # NMS IOU阈值 def capture_thread(self): cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) while True: ret, frame cap.read() if not ret: break # 丢弃旧帧保证队列最新 if self.frame_queue.full(): try: self.frame_queue.get_nowait() except queue.Empty: pass self.frame_queue.put(frame) def inference_thread(self): while True: try: frame self.frame_queue.get(timeout1) # GPU推理若可用或CPU推理 results self.model(frame, size640, augmentFalse) # 解析结果并缓存 detections [] for *xyxy, conf, cls in results.xyxy[0].cpu().numpy(): if conf 0.5: # 二次过滤 detections.append({ bbox: [int(x) for x in xyxy], conf: float(conf), class_id: int(cls), class_name: self.model.names[int(cls)] }) self.result_queue.put({frame: frame, detections: detections}) except queue.Empty: continue def display_thread(self): while True: try: data self.result_queue.get(timeout1) frame data[frame] for det in data[detections]: x1, y1, x2, y2 det[bbox] cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, f{det[class_name]} {det[conf]:.2f}, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2) cv2.imshow(Traffic Sign Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break except queue.Empty: continue4.2 显存与CPU资源动态调控策略当检测到GPU显存占用90%时自动切换至CPU推理并降低输入分辨率# utils/resource_monitor.py def get_gpu_memory_usage(): try: result subprocess.run([nvidia-smi, --query-gpumemory.used, --formatcsv,noheader,nounits], capture_outputTrue, textTrue) used_mem int(result.stdout.strip()) result subprocess.run([nvidia-smi, --query-gpumemory.total, --formatcsv,noheader,nounits], capture_outputTrue, textTrue) total_mem int(result.stdout.strip()) return used_mem / total_mem except: return 0.0 # 在inference_thread中调用 if get_gpu_memory_usage() 0.9: print(GPU memory high, switching to CPU mode...) self.model self.model.cpu() self.model.to(cpu) # 同时降低推理分辨率 results self.model(frame, size320, devicecpu)注意该策略在Jetson Nano上实测有效当GPU温度65°C时触发降频避免热节流导致FPS暴跌。日志会记录每次切换时间点及对应帧率存于logs/resource_log.csv。5. 模型部署验证与跨平台兼容性调试技巧完成训练后不能只看test.py的mAP数值就认为系统可用。本项目提供三类验证手段覆盖从开发机到边缘设备的全链路。5.1 ONNX导出与TensorRT引擎生成含版本兼容清单export_onnx.py脚本支持导出不同精度的ONNX模型并自动生成TensorRT引擎# 导出FP16精度ONNX推荐Jetson设备 python export_onnx.py --weights weights/best.pt --img-size 640 --half # 生成TensorRT引擎需安装tensorrt8.2.5 trtexec --onnxweights/best_fp16.onnx \ --saveEngineweights/best_fp16.engine \ --fp16 \ --workspace2048 \ --minShapesinput:1x3x640x640 \ --optShapesinput:4x3x640x640 \ --maxShapesinput:8x3x640x640表不同平台推理性能实测单位ms/帧平台模型格式输入尺寸FPS平均延迟备注RTX 3090PyTorch640×6408212.2ms默认CUDAJetson Xavier NXTensorRT640×6402441.7msFP16精度Raspberry Pi 4BONNX CPU320×2403.8263msOpenVINO加速未启用Intel i5-8250UONNX CPU320×2405.2192ms开启OMP_NUM_THREADS45.2 标签映射一致性校验防止部署时类别错位GTSRB类别ID与YOLO训练ID不一致是常见坑点。项目在data/traffic_sign.yaml中明确定义映射# data/traffic_sign.yaml train: ../datasets/traffic_sign/images/train val: ../datasets/traffic_sign/images/val nc: 43 names: [speed_limit_20, speed_limit_30, speed_limit_50, ... , priority_road] # 关键按GTSRB官方顺序排列索引即为GTSRB class_id # 因此names[0]对应GTSRB class_id0无需额外映射表验证脚本verify_label_mapping.py会比对datasets/gtsrb/Train/00/目录下所有图片的CSV标注class_idlabels/目录下对应txt文件的第一列数字data/traffic_sign.yaml中names列表索引若发现不一致立即报错并输出冲突样本路径避免模型训完才发现类别全乱。5.3 USB摄像头兼容性调试解决V4L2驱动丢帧问题在Ubuntu 20.04上某些罗技C920摄像头会因V4L2缓冲区不足导致cv2.VideoCapture.read()返回空帧。项目提供fix_camera_buffer.sh一键修复#!/bin/bash # fix_camera_buffer.sh echo Setting V4L2 buffer size for /dev/video0... sudo v4l2-ctl -d /dev/video0 -c video_bitrate10000000 sudo v4l2-ctl -d /dev/video0 -c repeat_sequence0 # 增加内核缓冲区 echo 1024 | sudo tee /sys/module/uvcvideo/parameters/nobuffer echo Restarting uvcvideo module... sudo modprobe -r uvcvideo sudo modprobe uvcvideo提示执行后需重启main.py且必须在cv2.VideoCapture创建前运行。该脚本已集成到run.sh启动脚本中首次运行自动检测并修复。本文还有配套的精品资源点击获取
返回列表