ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于YOLOv5的道路交通标识识别:从数据集标注到实时部署

基于YOLOv5的道路交通标识识别:从数据集标注到实时部署 简介一套基于YOLOv5算法的道路交通标识识别系统完整项目面向计算机视觉方向毕业设计、课程设计与期末大作业场景适合希望快速搭建可运行深度学习项目的初学者。资源包含Python源码、道路交通标识数据集、训练权重与配置文件涵盖数据准备、模型训练、测试评估到界面演示的完整流程。压缩包共266个文件约423.33MB除主要py源码外还包含yaml配置、jpg/png图像样本、pt模型权重、txt标签说明以及Dockerfile、ipynb示例等可满足环境搭建、训练推理与结果展示等多环节需求。目前已有50人学习下载属于导师认可的高分项目。代码注释详细、结构清晰简单部署即可运行系统功能完善、界面美观数据集类别覆盖较广并附带评估与扩展脚本便于二次开发与结果验证。该项目已通过严格调试下载后即可直接使用尤其适合需要快速完成毕业设计或期末项目的高校学生作为蓝本。1. 基于YOLOv5的道路交通标识识别为什么毕业设计选它最稳每年这个时候都会有一批学生盯着“道路交通标识识别”这个题目发愁——要说难它不算最难的要说简单纯用传统图像处理又拿不出手。我给你的建议是直接站在YOLOv5的肩膀上做它代码结构清晰、训练链路完整、中文资料多到溢出而且对NVIDIA显卡的要求远没有你想象中那么高。这套方案的核心是把“交通标识检测”拆成数据准备、模型训练、推理部署三个环节每一环都有标准答案踩坑点也相对集中做完就是一套能演示、能截图、能写进论文的完整系统。这篇文章会照着标题里的“python源码数据集”展开告诉你数据集怎么来、训练参数怎么调、实时识别怎么接以及那些没人提醒你、但一定会遇到的坑。2. 先从数据集下手自建道路交通标识数据集的采集、标注与划分2.1 公开数据集怎么选TT100K、CCTSDB 的路况差异与取舍做交通标识识别最省事的办法是直接拿公开数据集跑。常见的选择有TT100K腾讯的交通标志数据集、CCTSDB长沙理工的交通标志集、德国GTSRB等。TT100K的图像大多来自腾讯街景视角丰富、场景真实但它的标注只有一部分是公开的另外它把很多小目标标成了“忽略区域”如果你不了解这个设定训练时会发现AP值莫名其妙地低。CCTSDB则更贴近国内路况标注类别有指示、警告、禁止三类适合做三分类的毕设缺点是图片分辨率偏低夜景和雨雾天气的样本不够。我的建议是如果题目不限定“必须从零采集”那就以公开数据集为底座再自己补拍100到200张本校周边路口的图片作为增量数据。这样既能保证数据量又能证明你做了“自建数据集”的工作答辩老师也不会揪着“数据是不是抄的”不放。如果题目要求完全自采数据那你至少需要准备2000张以上有效标注图片类别不超过10个否则YOLOv5很容易出现过拟合或漏检。2.2 用LabelImg标注自己的图片标注规范与三类易错框自建数据集的标注工具我推荐LabelImg它足够简单支持Pascal VOC格式xml文件YOLOv5可以直接把VOC转成txt标签。安装直接用pippip install labelimg labelimg启动后会打开画框界面。标注前先在左侧的“Open Dir”打开图片文件夹再用“Change Save Dir”选择保存标注文件的位置最后在“PascalVOC”下拉菜单里确认格式为VOC。画框时按键盘w键进入画框模式拖拽出目标框后填入类别名称。逻辑说明LabelImg生成的xml里存的是矩形框的左上角坐标和宽高YOLOv5训练时需要的是归一化后的中心点坐标。这个转换可以交给YOLOv5自带的voc_label.py脚本也可以自己写几行Python处理。我更建议直接写转换脚本因为你可以顺便过滤掉那些宽度或高度小于10像素的极小框——这类框在交通标识数据里很常见小目标框如果标注不准训练阶段会让损失函数一直震荡。标注时有三个易错的地方要特别留意第一个是“框得太大”。很多新手喜欢把标志牌连同后面的电线杆、墙体一起框进去导致模型学到的是背景纹理。正确做法是让矩形框紧贴标志牌外沿留1到2个像素的余量即可。第二个是“漏标遮挡物”。如果一辆车挡了半个限速牌很多人就把整个目标跳过了。实际上YOLOv5能处理部分遮挡你只需要把可见部分完整框出来。第三个是“类别混淆”。同一个“禁止停车”标志在不同文件夹里可能标成“banstop”和“no_parking”训练前必须统一类名否则类别数量会凭空多出一倍。2.3 训练集/验证集划分避免同场景图像“串场”数据划分是很多人不重视、但直接影响最终指标的环节。常见做法是把图片和标签按8:1:1切分成训练集、验证集、测试集。但如果你用的是街景连续帧截图同一个路口可能在几十张图里反复出现这时候如果随机打乱切分训练集和验证集里会出现“同一场景”的相似图像验证集准确率会虚高答辩时一旦被质疑“模型是否真的泛化”很难解释清楚。我的做法是先按“场景”分组也就是把连续帧、同路段图像归到一组然后以组为单位做随机切分。代码可以这样写import os import random from collections import defaultdict img_dir images groups defaultdict(list) for fname in os.listdir(img_dir): scene_id fname.split(_)[0] # 假设文件名以场景ID开头 groups[scene_id].append(fname) scene_ids list(groups.keys()) random.shuffle(scene_ids) train_scenes scene_ids[:int(0.8 * len(scene_ids))] val_scenes scene_ids[int(0.8 * len(scene_ids)):int(0.9 * len(scene_ids))] test_scenes scene_ids[int(0.9 * len(scene_ids)):] for scene in train_scenes: for fname in groups[scene]: print(train, fname)参数说明这里以场景ID前缀作为分组键80%的场景进训练集10%进验证集10%进测试集。切分完后还要检查每个类别的样本数是否均衡如果“禁止驶入”只有50个框而“限速40”有2000个框建议后期给少样本类别做复制粘贴增强或额外采集否则训练出的模型会对高频类别有严重偏向。3. 把YOLOv5跑起来环境搭建、模型训练与参数调整3.1 环境配置conda 创建环境与依赖安装的版本坑YOLOv5的Python版本建议用3.8到3.10PyTorch版本用1.10到2.0之间都可以但要注意CUDA版本必须跟PyTorch匹配。我最常用的命令是conda create -n yolo5 python3.8 -y conda activate yolo5 pip install torch1.12.1cu113 torchvision0.13.1cu113 -f https://mirrors.aliyun.com/pytorch-wheels/cu113/ pip install -r requirements.txt逻辑说明先把Python环境隔离到conda里避免污染系统环境。-f后面的地址是PyTorch安装包的镜像源国内环境用官方源经常超时这个镜像能稳定拉取。requirements.txt是YOLOv5项目根目录下的依赖清单里面包含opencv、pandas、matplotlib等直接安装即可。这里有个很常见的坑如果你的显卡是NVIDIA 30系以上CUDA 11.3搭配PyTorch 1.12是相对稳的组合如果显卡是Intel核显或AMD显卡那就走CPU版本把torch和torchvision换成pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu但训练速度会慢十倍以上毕设如果时间紧建议直接租云GPU而不是用CPU死磕。3.2 准备YOLOv5训练文件data.yaml、标签格式与目录结构YOLOv5训练前要整理出一个固定的目录结构并写一个数据配置文件。标准结构是datasets/ traffic_sign/ images/ train/ val/ labels/ train/ val/images和labels两个目录必须严格对应图片是jpg/png标签是txt文件每个txt文件名和图片文件名一致结尾是.txt。每一行标签格式为类别ID、归一化中心点x、归一化中心点y、归一化宽度、归一化高度。这五个数字全部用空格分隔。data.yaml写在项目根目录下内容如下train: datasets/traffic_sign/images/train val: datasets/traffic_sign/images/val nc: 6 names: [speed_limit, no_entry, warning, direction, stop, construction]参数说明train和val是图片目录的路径YOLOv5会自动在同级目录下找labels文件夹。nc是类别总数names是类别名称列表顺序必须和标注时定义的类名索引一致否则训练出来的模型推理时会出现“张冠李戴”。如果你用的是LabelImg标注转换voc到yolo时建议提前给每个类别编号比如0号是限速、1号是禁止驶入转换脚本会按这个顺序填写入txt。3.3 训练命令与超参数batch-size、epochs、img-size 怎么定训练命令是YOLOv5里最核心的操作了我习惯把常用参数写进命令行方便反复调整python train.py --data data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --device 0 --project runs/train --name signs_v1参数说明--weights指定预训练权重用yolov5s.pt起步最省时--img表示输入图片会统一缩放到640×640这个尺寸对交通标识这种中小目标比较友好--batch16是显存8GB显卡的常见选择如果你的显卡只有4GB显存改成8或4--epochs100这个数字够用数据量小的话60轮就能收敛--device 0表示用第一张GPU卡没有GPU就写--device cpu。训练过程中你会看到终端滚动输出每个epoch的loss、mAP、precision、recall。很多人纠结哪个数值才算好我的经验是看mAP0.5这个指标代表IoU阈值0.5时的平均精度对毕设来说达到0.85以上就算不错。如果训练到50轮时mAP还在0.6以下不要急着加epoch先检查数据或标签大概率是标注框有偏差。3.4 训练过程监控loss曲线、mAP日志与中断恢复训练会自动在runs/train/signs_v1目录下生成results.png里面画了box_loss、obj_loss、cls_loss和mAP的曲线。你不需要实时盯着终端只要每隔十几轮看一眼这张图。正常的box_loss曲线应该是前期快速下降后期缓慢波动下降如果box_loss在30轮后突然反弹升高通常是学习率太大或数据里有异常标签。训练中断也是家常便饭尤其是用了云GPU或笔记本长时间挂机。YOLOv5支持断点续训用--resume参数即可python train.py --resume runs/train/signs_v1/weights/last.pt它会自动读取上次训练保存的最新权重和超参数文件从断点继续跑。注意续训时不要再加--data和--weights参数否则会覆盖原配置。另外last.pt和best.pt是最重要的两个输出文件last是最后一轮权重best是验证集上mAP最高的权重。后续推理、导出、部署全部用best.pt不要用last这是很多新手会踩的坑——last未必不好但best是按你的验证标准选出来的最优结果。4. 从训练到落地权重转换、摄像头实时识别与UI封装4.1 用训练好的权重做图片、视频推理训练完的best.pt可以直接用于推理。YOLOv5自带detect.py命令如下python detect.py --weights runs/train/signs_v1/weights/best.pt --source data/images/test.jpg --conf-thres 0.5--source可以传图片、视频文件也可以传一个文件夹YOLOv5会批量处理并把结果保存到runs/detect/exp目录里。--conf-thres是置信度阈值0.5意味着检测框得分超过50%才显示。白天正常光照下0.5够用如果识别到很多漏检可以降到0.3但代价是会出现更多误检框。如果你需要在Python里调用模型而不是跑命令行可以这样写import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/signs_v1/weights/best.pt) result model(test.jpg) result.print() result.show()逻辑说明torch.hub.load会把YOLOv5的模型封装成一个可调用的Python类传入图片路径返回结果对象。result.print()在终端打印每个检测框的类别、置信度和坐标result.show()弹出窗口显示画了框的图片。这种调用方式适合后面做UI封装因为你可以把result里的result.xyxy[0]拿来做进一步处理比如统计每类标识的数量。4.2 摄像头实时检测与帧率优化实时识别是答辩演示里最亮眼的部分。用OpenCV读摄像头帧喂给模型推理再把检测结果画回画面import cv2 import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/signs_v1/weights/best.pt) cap cv2.VideoCapture(0) while True: ret, frame cap.read() if not ret: break results model(frame, size640) rendered results.render()[0] # 返回画好框的numpy数组 cv2.imshow(Traffic Sign Detection, rendered) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明model(frame, size640)是直接对当前帧做推理results.render()会在原图副本上绘制检测框和类别文字。实际测试中这个循环在GPU上大概能跑到30到40帧每秒如果觉得卡可以先把摄像头采集尺寸从1920×1080降到1280×720推理时间几乎可以减半。另外不要在每次循环里都做颜色转换或缩放操作这些开销累积起来也会掉帧。4.3 用PyQt5做简易识别界面可选如果你的毕设需要GUIPyQt5是最快出活的方式。核心思路是把上面的摄像头循环放进一个子线程主线程只负责显示画面避免界面卡顿。界面布局不用复杂左边是实时画面右边是检测结果列表底部放“开始识别”“停止”两个按钮。线程间用信号传递帧数据class DetectThread(QThread): frame_signal pyqtSignal(object) def run(self): model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt) cap cv2.VideoCapture(0) while not self.isInterruptionRequested(): ret, frame cap.read() if not ret: break results model(frame) rendered results.render()[0] self.frame_signal.emit(rendered)逻辑说明把模型加载放在子线程的run方法里保证模型只在子线程创建避免和主线程的Qt事件循环冲突。frame_signal信号携带画好框的图像主线程里绑定这个信号去更新QLabel的pixmap。这种写法虽然简单但足够应付答辩演示而且代码量少出错也好排查。4.4 导出模型为ONNX/TensorRT的边界常见做法是用YOLOv5自带的export.py导出ONNX方便在Android、树莓派或嵌入式设备上部署python export.py --weights runs/train/signs_v1/weights/best.pt --include onnx --opset 12导出ONNX后你可以用onnxruntime来加载并推理。但这个环节有一个边界要提醒你ONNX推理结果和PyTorch原始结果会有微小差异主要来自上采样和批归一化层的算子融合。如果你发现导出的ONNX在调用时检测框错位先检查是否在export.py里加了--dynamic参数——动态输入尺寸虽然灵活但在部分ONNX Runtime版本上会引发坐标偏移。对毕设来说固定640×640尺寸导出老老实实用别折腾动态维度。5. 道路交通标识识别的避坑与常见问题现象、原因、解决5.1 训练loss正常下降但mAP一直是0现象训练好几轮box_loss和obj_loss在降val输出里所有类别的mAP都是0precision和recall全是0。原因最常见的是标签文件和图片没有对应上。某个jpg对应的txt文件不存在或者txt内容是空的还有一种情况是txt里的类别ID超出了names列表的长度比如你在data.yaml里写了nc: 6但标签里出现了第7个类别IDYOLOv5会把这一行直接跳过导致模型学不到任何正样本。解决训练前写一段脚本扫描所有labels下的txt统计每个类别的样本量并对缺失文件、空文件做检查和清洗。我通常会在data.yaml里临时加一行debug: true然后重新运行train.py看终端是否打印“No labels found in ...”有就直接补标签或删掉对应图片。5.2 训练特别慢一个epoch要十几分钟现象用笔记本训练batch_size调到2还是跑不动目测GPU占用率只有20%。原因一是显存不够导致batch_size太小GPU利用率上不去二是没有装CUDA版的PyTorch实际上用的是CPU在跑三是--workers默认值太高或太低数据加载瓶颈卡住了GPU。解决先用nvidia-smi查看显卡型号和显存再在Python里打印torch.cuda.is_available()确认是True。如果显存只有4GB用--batch 4 --img 512在精度和速度之间取平衡。另外把--workers 0改成4到8Windows下worker过多会报DataLoader错误遇到就直接设0。5.3 白天检测很稳一到晚上就大量漏检现象测试白天图片mAP有0.9晚上或阴雨天图片检测框狂闪限速牌直接消失。原因道路交通标识在夜间通常会反光但反光区域的亮度在图像里可能过曝也有部分标识被路灯、车灯遮挡。YOLOv5对亮度变化并不鲁棒训练集里夜样本太少是根本原因。解决在训练集里做颜色扰动增强把HSV色相、饱和度、明度的调整范围加大特别是把图像随机压暗。具体做法是在hyp.scratch-low.yaml里把hsv_h: 0.015、hsv_s: 0.7、hsv_v: 0.4改成hsv_s: 0.9、hsv_v: 0.6然后重新训练。如果还不行就去网上爬一些夜间的交通标识图人工标注后混入训练集比任何调参都管用。5.4 摄像头实时检测时会闪烁抖动现象检测框在连续帧之间抖动同一块标识牌时而抓到时而丢掉置信度在0.3到0.8之间跳。原因单帧检测没有时序信息每一帧都是独立推理所以框的位置和类别概率会随噪声波动。摄像头自动曝光和白平衡也会导致亮度突变加剧抖动。解决最简单的办法是降低--conf-thres到0.3同时开启YOLOv5的--augment推理模式它会对同一帧做多尺度推理再融合结果稳定性有明显提升但会降低帧率。另一个思路是给检测框做一阶低通滤波用上一帧的坐标平滑当前帧坐标代码量不大但能显著改善观感。5.5 训练时内存被吃光进程被杀现象跑着跑着系统弹窗“内存不足”或者训练直接卡死。原因数据加载器在预处理阶段会把图片全部解码到内存如果数据集图片分辨率太大比如4000×3000街景图即使--img 640加载时的中间数组仍然占用大量内存。另一个原因是--cache参数默认会把图片缓存到内存小数据集没事大数据集直接爆。解决在train.py命令里加上--no-cache不让它把图片缓存到RAM同时把源图片统一resize到1920像素以内的长边再放进数据集。如果还是内存吃紧把batch_size减半。6. 把准确率再往上推数据增强、超参微调与坏例分析当你做完上面所有步骤模型基本能用了但想冲高分、答辩时多讲几个技术亮点可以在最后阶段做三件事。第一件事是调整数据增强的超参数。YOLOv5的hyp.scratch-low.yaml里默认开启mosaic增强它能把四张图拼成一张训练对小目标检测很有帮助。但如果你发现训练后期loss降不下去可以尝试把mosaic概率从1.0降到0.5因为mosaic生成的图像和真实场景差距大过度依赖会让模型在真实图片上泛化变差。同时把fliplr: 0.5左右翻转概率保留但不要加flipud上下翻转因为交通标识颠倒放置没有物理意义完全是标签噪声。第二件事是微调学习率和训练轮数。默认lr0: 0.01在batch_size为16时没问题但如果你把batch_size改成4学习率最好等比例降到0.0025左右。我习惯用YOLOv5自带的--cos-lr开启余弦退火或者用--warmup-epochs 3增加热身轮数避免前期梯度爆炸。最终模型收敛后把best.pt在测试集上跑一遍统计每个类别的召回率找出最弱的那个类别单独给它加样本或做复制粘贴增强比整体加数据更高效。第三件事是坏例分析。把测试集里所有误检和漏检的图片挑出来按原因归类是目标过小、遮挡、光照差还是类别相似比如“限速30”和“限速40”数字差异小。这一步能让你在毕业论文里多写一小节“错误分析与改进”很加分。对光照差的坏例把图像转到HSV空间看亮度直方图如果普遍低于80可以在推理前对整帧做一个轻量的伽马校正对目标过小的坏例把--img 640改成--img 960推理mAP会有0.03到0.05的提升代价是速度下降。我的习惯是每次训练完都把results.png、confusion_matrix.png和几组坏例截图存到固定文件夹写论文时直接引用。以上这些都是我自己做过三轮毕设项目后沉淀下来的经验返校前把模型导出成ONNX再把best.pt备份到网盘你就掌握了这套系统的关键环节。希望帮到你。对了最后补一句如果你在Windows上训练遇到奇怪的报错先尝试把杀毒软件退掉YOLOv5的数据加载进程经常被杀毒软件拦下来这个玄学问题我碰到过不止一次。本文还有配套的精品资源点击获取
返回列表