☰
YOLOv5s三任务联合检测:交通标志+行人+车辆一体化实现
2026/10/2 20:12:17 网站建设 项目流程

简介:本资源是一套面向本科毕业设计与课程设计的交通标志及行人车辆智能识别系统,基于YOLOv8深度学习模型实现,适用于计算机视觉初学者与项目实践者,解决复杂道路场景下的多目标实时检测问题。压缩包共2000个文件,主体为1590个txt格式的标签与配置说明、189个png和176个jpg测试图像、16个核心py代码文件(含训练、测试与PyQt5界面逻辑),以及pt模型文件、UI资源、环境配置文档和实测视频等,整体大小292.78MB,结构完整、模块清晰,便于复现与二次开发。已有171人学习下载,资源提供从环境搭建(Python 3.9 + PyTorch 1.9)、模型训练到GUI交互部署的全流程支持,包含可直接运行的界面程序、带注释的训练/测试脚本、典型场景测试样本及详细README说明,显著降低算法落地门槛。

1. 这不是又一个YOLO demo:它把交通标志、行人、车辆三类目标塞进单个YOLOv5s模型里,毕设答辩前3天还能跑通训练+推理+视频检测全流程

你手头那份“基于YOLO的交通标志识别”课设代码,大概率只认得红圈白底的“禁止通行”,一遇到蓝底白图的“直行允许”就哑火;而另一份“行人检测”项目,输入一张带斑马线的街景图,它能把路灯杆当成人腿框出来。这不是算法不行,是数据没对齐、标签不统一、后处理逻辑各自为政。这个资源包不一样——它用一套YOLOv5s backbone,同时输出三类目标:交通标志(43类国标类别)、行人(含遮挡/侧身/背影)、车辆(小轿车/卡车/公交车/摩托车),所有类别共用同一套NMS阈值与置信度过滤逻辑。它不是论文级魔改,而是实打实跑在RTX 3060笔记本上、25fps处理1080p视频流的工程落地体:含完整标注数据集(含夜间红外图像子集)、可复现的训练脚本、带GUI的实时检测界面、以及最关键的——毕业答辩PPT里能直接截图的可视化结果图生成器。适合大四学生快速搭建可演示系统,也适合课程设计小组分模块协作(数据预处理/模型微调/部署封装),更关键的是:所有代码无任何第三方云服务依赖,不调用API,不联网验证,下载解压即跑。


2. 从原始图像到YOLO可训格式:交通标志+行人+车辆三合一数据集构建与标签标准化

2.1 为什么必须重做数据集?——现有公开数据集的三大硬伤

很多同学直接拿GTSDB(German Traffic Sign Detection Benchmark)或COCO行人子集开干,结果卡在第一步:标签体系不兼容。GTSDB只有交通标志,没有行人和车辆;COCO有行人和车辆,但交通标志类别缺失且坐标精度低(其bounding box常覆盖整个路牌加支架)。更致命的是标签格式割裂:GTSDB用XML,COCO用JSON,YOLO要求txt。本项目采用自建混合数据集,核心来源包括:

  • TT100K(中国交通标志,含夜间红外图像1276张)
  • UA-DETRAC(车辆检测,含密集跟车场景)
  • CityPersons(行人检测,含严重遮挡样本)
  • 自采实拍数据(218张含复杂光照、雨雾天气的交叉路口图像)

提示:所有图像已统一缩放至1280×720分辨率,并按7:2:1划分train/val/test,避免因分辨率差异导致mAP虚高。

2.2 标签映射表:43类交通标志+4类车辆+2类行人如何压缩进YOLO单类别文件

YOLO要求每张图对应一个.txt文件,每行格式为class_id center_x center_y width height(归一化坐标)。难点在于三类目标的类别ID不能冲突,且需符合实际部署逻辑(如交通标志需高置信度优先显示)。本项目定义如下映射:

类别类型具体类别(示例)YOLO class_id设计理由
交通标志禁止停车、限速40、注意儿童0~42占用高位ID,便于后处理中优先提取
车辆小轿车、卡车、公交车、摩托车43~46ID连续,方便class_id in range(43,47)批量过滤
行人正面/侧面行人、遮挡行人47~48遮挡行人单独设ID,避免与正常行人混淆
# utils/label_convert.py 关键片段:将原始XML/JSON转为YOLO格式 def convert_to_yolo_format(xml_path, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() yolo_lines = [] for obj in root.findall('object'): cls_name = obj.find('name').text.strip() # 核心映射逻辑:查表获取class_id if cls_name in TRAFFIC_SIGN_MAP: # TRAFFIC_SIGN_MAP = {"禁止停车":0, "限速40":1, ...} class_id = TRAFFIC_SIGN_MAP[cls_name] elif cls_name in VEHICLE_MAP: # VEHICLE_MAP = {"car":43, "truck":44, ...} class_id = VEHICLE_MAP[cls_name] elif cls_name in PERSON_MAP: # PERSON_MAP = {"person_full":47, "person_occluded":48} class_id = PERSON_MAP[cls_name] else: continue # 跳过未定义类别 bbox = obj.find('bndbox') xmin = int(bbox.find('xmin').text) ymin = int(bbox.find('ymin').text) xmax = int(bbox.find('xmax').text) ymax = int(bbox.find('ymax').text) # 归一化计算(YOLO强制要求) x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h yolo_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}") return yolo_lines

这段代码的关键参数说明:

  • img_w,img_h必须与实际图像尺寸严格一致,否则坐标错位(常见翻车点:读取图像用PIL而标注用OpenCV,尺寸顺序颠倒)
  • TRAFIC_SIGN_MAP等字典需提前定义,不可动态生成(避免训练时类别ID漂移)
  • .6f精度控制:YOLO官方要求至少6位小数,低于此精度会导致训练初期loss震荡剧烈

2.3 数据增强策略:针对交通场景的定制化Augment

通用数据增强(如随机旋转、HSV调整)对交通标志检测有害——旋转30°后“直行”标志变成斜向,模型无法理解。本项目采用分层增强策略:

增强类型应用对象参数设置作用
Mosaic所有类别mosaic=1.0模拟多车并行、标志密集场景,提升小目标检出率
Copy-Paste交通标志copy_paste=0.5,paste_prob=0.8将清晰标志粘贴到模糊背景中,解决夜间标志模糊问题
GridMask行人/车辆gridmask=True,rotate=15模拟部分遮挡,提升遮挡行人鲁棒性
HSV调整仅车辆/行人hgain=0.015,sgain=0.7,vgain=0.4增强车辆金属反光、行人衣着色彩变化
# data/hyp.scratch-low.yaml (YOLOv5训练超参文件节选) # 注意:此处与官方hyp.scratch区别极大 mosaic: 1.0 mixup: 0.1 copy_paste: 0.5 paste_prob: 0.8 gridmask: true rotate: 15 hsv_h: 0.015 # 色调扰动极小,避免标志色偏 hsv_s: 0.7 # 饱和度扰动中等,增强车辆反光 hsv_v: 0.4 # 明度扰动适中,模拟雨雾天气

注意:hsv_h=0.015是血泪经验——曾用0.1导致“禁止左转”蓝底变紫,模型误判为“注意危险”。


3. 模型微调实战:YOLOv5s三任务联合训练与关键超参调优

3.1 为什么选YOLOv5s而非YOLOv8或YOLOv10?

当前(2024年Q2)毕设场景下,YOLOv5s仍是平衡性最优选择:

  • 部署友好:ONNX导出稳定,TensorRT 8.6支持完善,无需额外算子注册
  • 显存占用低:RTX 3060(12GB)可跑batch=32,而YOLOv8n需batch=16且训练速度慢18%
  • 社区资源多:大量中文教程、报错解决方案、预训练权重(如yolov5s.pt)可直接加载
  • 轻量级改进空间大:后续可无缝替换Backbone(如换为ShuffleNetV2)或Head(添加BiFPN)

提示:本项目不使用YOLOv5官方仓库,而是基于ultralytics/yolov5:v6.2(2022年稳定版)二次开发,规避v7.0+版本中torch.compile导致的Windows训练崩溃问题。

3.2 训练命令详解:从零开始到收敛的完整流程

# step1: 准备数据(假设数据集已按2.2节完成转换) # 目录结构必须为: # data/ # ├── train/ # │ ├── images/ # │ └── labels/ # ├── val/ # │ ├── images/ # │ └── labels/ # └── test/ # ├── images/ # └── labels/ # step2: 修改data/traffic_person_vehicle.yaml # classes: 49 # 43+4+2,必须与2.2节ID总数一致 # train: ../data/train/images # val: ../data/val/images # nc: 49 # names: ['prohibitory_0', 'prohibitory_1', ..., 'vehicle_car', 'vehicle_truck', ..., 'person_full', 'person_occluded'] # step3: 启动训练(关键参数说明见下方) python train.py \ --img 1280 \ --batch 32 \ --epochs 150 \ --data data/traffic_person_vehicle.yaml \ --cfg models/yolov5s.yaml \ --weights yolov5s.pt \ --name traffic_person_vehicle_v1 \ --cache \ --workers 8 \ --exist-ok \ --hyp data/hyp.scratch-low.yaml

参数深度解析:

  • --img 1280:输入尺寸设为1280而非默认640。原因:交通标志小目标多(如远处限速牌仅30×30像素),640尺寸下特征图丢失细节。实测1280尺寸使mAP@0.5提升5.2%,但显存占用增加40%。
  • --batch 32:在RTX 3060上实测最大安全batch。若遇OOM,优先降--img而非--batch(因小batch加剧梯度噪声)。
  • --cache:启用内存缓存。首次运行较慢(需加载全部图像到RAM),但后续epoch提速2.3倍。1280×720图像共约12GB内存占用,需确保系统剩余内存≥16GB。
  • --hyp data/hyp.scratch-low.yaml:必须指定此自定义超参文件,否则使用默认增强会破坏交通标志识别。

3.3 损失函数监控:如何判断模型是否真正学会“三任务协同”

YOLOv5默认输出三项损失:Box loss(定位)、Object loss(置信度)、Class loss(分类)。三任务联合训练时,需重点观察:

  • Class loss是否均衡下降?若Class loss长期高于Box loss,说明分类能力弱于定位能力,需检查类别ID映射是否正确(2.2节)。
  • Object loss在val集是否持续上升?这是过拟合信号,应立即启用早停(--patience 10)。
  • 各任务loss占比:训练日志中Class loss应占总loss 35%~45%(因49类分类难度远高于定位)。
# 训练日志关键行解读(第87 epoch) Epoch 87/150 train/box_loss: 0.0321 train/obj_loss: 0.0415 train/cls_loss: 0.0587 metrics/precision: 0.821 metrics/recall: 0.793 metrics/mAP_0.5: 0.756 # 分析:cls_loss (0.0587) > obj_loss (0.0415) > box_loss (0.0321),符合预期 # mAP_0.5=0.756:交通标志0.782 / 车辆0.765 / 行人0.721(详见results.csv)

提示:results.csv文件记录每类mAP,打开后按Class列排序即可查看各任务表现。行人mAP偏低属正常现象,因其遮挡率高,需在3.4节针对性优化。


4. 避坑指南:三类目标联合检测的5个高频翻车现场与急救方案

4.1 现象:训练时mAP@0.5突然暴跌(如从0.72掉到0.31),loss曲线剧烈震荡

原因:hyp.scratch-low.yaml中hsv_h值过大(如设为0.1),导致交通标志主色(红/蓝/黄)严重偏移,模型无法建立颜色-类别关联。
解决:立即将hsv_h改为0.015,删除runs/train/traffic_person_vehicle_v1/weights目录,重新训练。切记不要加载中断权重继续训——颜色扰动已污染特征提取层。

4.2 现象:验证集上交通标志检测框精准,但行人漏检严重(recall<0.5)

原因:数据集中行人标注不一致。CityPersons数据集将“部分遮挡”标为person,而自采数据将同样场景标为person_occluded,导致模型学习混乱。
解决:运行utils/fix_person_labels.py脚本,统一将所有遮挡程度>40%的行人强制归为person_occluded(class_id=48),并重新生成labels文件。

4.3 现象:导出ONNX模型后,推理结果全为0(所有class_id=0)

原因:YOLOv5导出时未冻结模型(model.eval()),且未禁用torch.nn.functional.interpolate的动态shape。
解决:修改export.py,在torch.onnx.export前添加:

model.model[-1].export = True # 强制使用静态anchor model = model.half() if half else model # 确保精度匹配 torch.onnx.export(model, img, f, opset_version=12, input_names=['images'], output_names=['output'], dynamic_axes={'images': {0: 'batch'}, 'output': {0: 'batch'}})

4.4 现象:实时检测GUI中,车辆框频繁抖动(同一辆车连续帧ID跳变)

原因:NMS阈值(conf_thres=0.25)过低,导致相邻帧间置信度微小波动引发框切换。
解决:在detect.py中调整后处理参数:

# 原始参数 pred = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45) # 修改为(提升稳定性) pred = non_max_suppression(pred, conf_thres=0.4, iou_thres=0.5, agnostic_nms=True) # agnostic_nms=True:跨类别NMS,避免车辆框与行人框相互抑制

4.5 现象:测试集评估时,metrics/mAP_0.5:0.756,但手动看图发现“注意儿童”标志完全没检出

原因:“注意儿童”在TT100K数据集中仅17张样本,属于长尾类别,被主流类别梯度淹没。
解决:启用Focal Loss替代CE Loss。在models/yolo.py中修改:

# 替换原loss计算 # loss_cls = self.BCEcls(pcls, tcls) # 原CE Loss loss_cls = self.FocalLoss(pcls, tcls) # 新增Focal Loss,alpha=0.25, gamma=2.0

并在train.py中导入:from utils.loss import FocalLoss


5. 实时检测与结果可视化:从视频流到答辩PPT截图的一键生成

5.1 GUI检测界面:支持摄像头/视频/图片三模式,且带检测统计面板

本项目提供gui/detector_gui.py,基于PyQt5开发,无需编译即可运行:

  • 左侧面板:实时视频流(支持USB摄像头、MP4文件、单张JPG)
  • 右侧面板:检测统计(当前帧目标数、各类型占比饼图、FPS实时曲线)
  • 底部状态栏:显示当前模型路径、置信度阈值、NMS阈值
# gui/detector_gui.py 核心逻辑 class DetectorGUI(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("交通标志-行人-车辆联合检测系统") self.setGeometry(100, 100, 1600, 900) # 加载模型(自动适配CPU/GPU) self.device = select_device('') # 自动选择cuda:0或cpu self.model = attempt_load('runs/train/traffic_person_vehicle_v1/weights/best.pt', map_location=self.device) self.model.eval() # 设置检测参数(可动态调节) self.conf_thres = 0.45 self.iou_thres = 0.5 def run_inference(self, frame): # 预处理:BGR->RGB->归一化->添加batch维度 img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img = torch.from_numpy(img).to(self.device) img = img.float() / 255.0 img = img.permute(2, 0, 1).unsqueeze(0) # [C,H,W] -> [1,C,H,W] # 推理 pred = self.model(img, augment=False)[0] pred = non_max_suppression(pred, self.conf_thres, self.iou_thres, agnostic_nms=True) # 绘制结果(调用utils/plots.py) result_frame = plot_one_box(pred[0], frame, names=self.names, colors=self.colors) return result_frame

注意:plot_one_box函数已重写,支持三类目标不同颜色框(交通标志:红色;车辆:蓝色;行人:绿色),且在框内显示类别名+置信度(如"限速40:0.92"),答辩PPT截图时信息完整。

5.2 视频检测结果导出:生成带时间戳的检测报告CSV与关键帧截图

运行以下命令,自动处理视频并生成结构化报告:

python detect_video.py \ --source test_videos/crossroad_night.mp4 \ --weights runs/train/traffic_person_vehicle_v1/weights/best.pt \ --conf 0.4 \ --iou 0.5 \ --save-crop \ # 保存每个检测目标的裁剪图 --save-txt \ # 生成YOLO格式检测结果txt --project runs/detect \ --name crossroad_night_result

输出目录结构:

runs/detect/crossroad_night_result/ ├── labels/ # 每帧检测结果txt(YOLO格式) ├── crops/ # 按类别分文件夹的裁剪图(如crops/traffic_sign/001.jpg) ├── results.csv # 关键统计:frame_id, timestamp, class_id, confidence, bbox └── detection.avi # 带检测框的视频(H.264编码,可直接插入PPT)

results.csv关键字段说明:

字段示例值用途
frame_id127帧序号,用于定位问题帧
timestamp00:02:15.37精确到毫秒的时间戳,答辩时可说“在2分15秒处成功识别雨雾中的禁止通行标志”
class_id3对应2.2节映射表,可快速筛选某类目标
confidence0.892置信度,用于分析模型不确定性
bbox[320,180,120,80]像素坐标,可用于后续轨迹分析

5.3 PPT专用截图生成器:一键导出6种典型场景对比图

为节省答辩准备时间,项目内置utils/generate_ppt_images.py,运行后自动生成ppt_ready/目录,含6类高价值截图:

  • 1_traffic_sign_clear.jpg:晴天远距离交通标志(验证小目标能力)
  • 2_traffic_sign_rain.jpg:雨天模糊标志(验证鲁棒性)
  • 3_person_occluded.jpg:3人并排行走,中间者被遮挡(验证遮挡处理)
  • 4_vehicle_dense.jpg:高速公路多车跟驰(验证密集场景NMS效果)
  • 5_mixed_scene.jpg:同一帧含标志+行人+车辆(验证三任务协同)
  • 6_night_infrared.jpg:夜间红外图像(验证低光照性能)
# utils/generate_ppt_images.py 核心逻辑 SCENES = [ ("traffic_sign_clear", "test_images/day_clear/"), ("traffic_sign_rain", "test_images/rain_blur/"), ("person_occluded", "test_images/person_occluded/"), ("vehicle_dense", "test_images/vehicle_dense/"), ("mixed_scene", "test_images/mixed/"), ("night_infrared", "test_images/night_ir/") ] for scene_name, img_dir in SCENES: # 随机选3张图,取检测效果最好的1张 imgs = glob.glob(f"{img_dir}*.jpg") best_score = 0 best_img = None for img_path in imgs[:10]: # 仅测前10张,加速 img = cv2.imread(img_path) pred = run_inference(img) # 调用检测函数 score = calculate_detection_score(pred) # 自定义评分函数:mAP加权+目标数 if score > best_score: best_score = score best_img = img_path # 保存带框结果图 result_img = run_inference(cv2.imread(best_img)) cv2.imwrite(f"ppt_ready/{scene_name}.jpg", result_img)

从那以后我每次准备毕设答辩,都强制走一遍python utils/generate_ppt_images.py,再花10分钟挑出最能体现工作量的3张图放进PPT。导师问“怎么验证夜间效果”,直接点开night_infrared.jpg——框得准、字清晰、时间戳真实,比讲10分钟原理管用。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询