资讯动态

yolov5+opencv红绿灯识别实战:从模型训练到工程落地

发布时间:2026/9/27 23:42:51 来源:尧图企业网站定制
简介基于YOLOv5与OpenCV构建的红绿灯识别检测完整方案面向计算机视觉开发者、自动驾驶或智慧交通方向学习者解决交通灯目标检测与模型评估问题。压缩包共79个文件包含Python源码17个py、模型权重3个pt、配置文件17个yaml以及训练评估图表jpg/png和使用说明txt等整体大小约41.68MB目录结构清晰便于按模块调用。目前已有1487人学习下载适合具备一定深度学习基础、希望快速上手YOLOv5交通灯检测的读者。资源附带训练过程loss下降曲线、Recall、Precision、mAP等评估指标曲线共迭代200次模型拟合较好支持红灯、绿灯、黄灯、交通灯4类识别内置使用说明与推理脚本可直接用于实验复现或二次开发。1. yolov5opencv做红绿灯识别不是只有训练这件事红绿灯识别在自动驾驶和辅助驾驶项目里算是典型的小目标检测场景难点不在算法本身多深奥而在实际情况足够烦白天逆光、晚上灯晕、雨雾天颜色发灰、同一方向多个灯头同时亮。这套资源给的是 yolov5opencv 的完整落地路径从训练好的模型文件到评估指标曲线、再到可直接调用的检测脚本和说明文档全部包含。适合两类人一类是想在毕设或者工程 Demo 里快速跑通红绿灯识别的新手另一类是想拿一套真实数据流程做基准、再替换成自己数据集的开发者。我拆完这套包最大的感受是训练模型只是三分之一的工作剩下的三分之二是环境对齐、参数调优和踩坑修复。2. 红绿灯识别方案选型为什么是yolov5而不是纯opencv颜色分割2.1 传统opencv颜色分割的边界HSV阈值为什么扛不住天黑和逆光很多人在接触深度学习之前第一反应是用opencv做颜色分割把图像转成 HSV 色彩空间然后对红色、绿色分别设定阈值范围再用轮廓检测找出灯的位置。这套思路在小视频上看起来效果挺好尤其是正对路灯拍的画面。但实际装到车上或者路边固定杆上一测问题立刻暴露。最典型的翻车场景是逆光。黄昏时段太阳在灯的正后方摄像头拍到的红绿灯整体发灰红色灯的饱和度急剧下降HSV 里设置的固定阈值根本圈不住目标。更麻烦的是夜间LED 灯会产生光晕灯的实际发光区域和光晕混在一起轮廓提取出来的是一个大光斑中心坐标和真实灯位置偏移严重。此外黄灯和红灯在某些白平衡算法下会互相靠近纯颜色分割几乎无法区分。yolov5 这类目标检测模型解决的是“语义”问题它学习的是灯的形状、位置上下文和颜色组合。模型不只看颜色还看灯板结构、灯与灯之间的相对位置所以对逆光、过曝、雨天的鲁棒性远高于阈值分割。opencv 在这个项目里的角色退位成预处理和后处理工具图像缩放、格式转换、画框和状态读取辅助。这一点在当前这套资源里体现得也很明显模型文件负责检测opencv 负责周边配合工作。2.2 yolov5落地选型的现实逻辑模型大小与推理速度的取舍红绿灯检测对实时性有要求但不是所有场景都要跑满 60 帧。路边固定摄像头做交通违章抓拍30 帧就足够车端前视摄像头做辅助判断至少也要 20 帧以上。yolov5 的 s/m/l 三个尺寸在这个项目里是个很实在的取舍点。我一般会先从 yolov5s 开始验证流程因为 s 模型体积小、推理快CPU 上勉强能跑GPU 上能轻松跑满实时。如果发现小目标漏检严重再往 m 或者 l 升级。这套资源里提供的模型文件本身就是训练好的但你在换自己数据集时可以先从 s 起步。有一点要记住红绿灯是小目标在图像里往往只占几十个像素模型下采样倍数越大小目标特征丢得越厉害所以一般不太建议为了速度把头部的输入尺寸压到 320 以下。资源里的使用说明文档对这部分有明确建议默认推理尺寸 640 是性价比较高的选择。2.3 标签体系设计红绿黄三类的边界怎么定红绿灯识别标签设计看起来简单就是 red、green、yellow 三类但实操中会遇到边界问题。倒计时数字灯是算目标还是不算箭头灯和圆盘灯要不要分开黄灯闪烁状态怎么办这套资源的模型文件用的是基础三分类也就是红、绿、黄。这个设计的聪明之处在于先解决“灯亮没亮、什么颜色”这个核心问题把倒计时数字、箭头方向留给后处理逻辑。如果你需要做箭头灯识别建议在训练数据里单独加一类箭头灯标签但要注意和圆盘灯共享特征时模型容易混淆训练前最好做一次标签分布检查确认每一类数量不要悬殊过大。标注时还要注意把灯板周围轻微光晕框进去一点别只框灯芯发光部分这样模型学到的上下文特征更强检测更稳。3. 环境配置与工程结构先把踩坑最多的环节固定下来3.1 opencv和yolov5的环境对齐版本对冲比代码报错更折磨人yolov5 官方仓库对 opencv 版本的最低要求是 4.1.2但实际跑起来你会发现opencv 4.5 之后一些函数的默认行为变化很大尤其是图像缩放和颜色通道处理上。这套资源自带 requirements 依赖文件我在复现时先把关键库版本对齐到说明文档给的范围再用 conda 建独立环境避免把系统里原有 opencv 环境搞坏。conda create -n traffic_light python3.8 conda activate traffic_light pip install torch1.10.0 torchvision0.11.0 pip install opencv-python4.5.5.62 pip install -r requirements.txt这里用 Python 3.8 是因为这个版本和 torch 1.10 的兼容性最稳yolov5 官方在 5.0 版本时期大量测试基于这个组合。opencv-python 选择 4.5.5 而不是最新版是为了避免新版 opencv 在部分老型号 GPU 上调用推理引擎时出现不兼容。等这个环境跑通了再考虑升级不迟。3.2 源码目录与运行入口拿到资源包后第一步做什么解压后你不会第一时间看到训练好的模型而是先看到一套标准工程结构。我拆包后发现目录组织得很规整模型文件放在 weights 目录下检测脚本在根目录评估指标曲线图表统一放在 runs 目录里。第一步不是跑训练而是先跑一次检测脚本确认环境没问题。python detect.py --weights weights/best.pt --source data/test_images/ --conf-thres 0.5detect.py 会读取 weights 目录下的 best.pt 模型文件对 data/test_images 里的测试图片做推理conf-thres 0.5 表示置信度阈值。跑通之后你会看到终端打印每张图的检测结果和耗时同时在 runs/detect 目录下生成标注好框的图片。如果这一步能顺利出图说明环境基本没问题后面训练、验证都能跑。我习惯的做法是先看跑出来的框位置准不准而不是追求这一帧的置信度高低。3.3 检测脚本的核心参数输入源与阈值怎么调detect.py 支持的输入源很灵活单张图片、视频文件、摄像头实时流都可以。摄像头场景下要额外注意分辨率设置IMX 系列摄像头默认输出 1080p但 yolov5 预处理会缩放到 640所以摄像头采集分辨率不用太高720p 足够。parser.add_argument(--source, typestr, default0, helpfile/dir/URL/glob/screen) parser.add_argument(--img-size, typeint, default640, helpinference size (pixels)) parser.add_argument(--conf-thres, typefloat, default0.5, helpconfidence threshold) parser.add_argument(--iou-thres, typefloat, default0.45, helpNMS IoU threshold)img-size 640 是模型训练时的输入尺寸不要随意改动。conf-thres 默认 0.5 在现场调试时可调低到 0.3 观察召回情况如果检测框变多、误检也变多再逐档往回拉。iou-thres 控制在 0.45 到 0.5 之间这个参数对重叠灯头同时检测有直接影响调太高会把相邻的绿灯和红灯合并成一个框。我一般用 0.45因为红绿灯横向排列密集时0.5 会偶尔把两个灯框并成一个。4. 训练自己的红绿灯数据集从标注到评估闭环4.1 标注格式与数据组织labelImg画框之前先想清楚这些问题想把模型用到你自己的路段或者特定灯型上就要重新训练。数据集组织方式直接决定后面训练是否顺利。yolov5 要求的数据结构是 images 目录放原始图片labels 目录放对应的 txt 标注文件。dataset/ images/ train/ val/ labels/ train/ val/标注文件每一行的格式是类别序号 归一化中心x 归一化中心y 归一化宽 归一化高。比如一个红灯框在 640x640 图片里中心坐标为 (320, 200)宽 40 高 40那标注行就是 0 0.5 0.3125 0.0625 0.0625。这个归一化坐标是相对图片宽高的比例用 labelImg 标注时软件会自动算好不需要手写。我见过不少人在这一步翻车是因为训练集和验证集图片来自同一段视频的连续帧导致验证集与训练集高度相关评估指标虚高。正确做法是从不同时段、不同天气、不同路口采集数据再按 8:2 或 9:1 划分。红绿灯项目尤其要注意把夜间数据单独留出一部分放进验证集否则模型白天效果很好、一到晚上就失灵。4.2 训练参数设置超参数不是越大越好yolov5 训练用 train.py 启动参数看起来简单实际上每一个都值得细想。下面这套配置是红绿灯场景下我验证过比较稳的一组起始值。python train.py --data traffic_light.yaml --weights yolov5s.pt \ --img 640 --batch 16 --epochs 100 --device 0traffic_light.yaml 里定义类别数和类别名weights 用 yolov5s.pt 做预训练权重这比从零训练收敛速度快很多。batch 16 在 8GB 显存的显卡上比较安全如果显存更大可以调到 32。epochs 100 是起步值红绿灯检测目标小、特征不算复杂一般 80 到 120 轮足够收敛跑太多轮反而会在验证集上过拟合。yolov5 里还有一个 hyp.yaml 超参数文件可以调但新手不建议动。里面学习率、动量、数据增强系数环环相扣改一个不对整体就崩。特别是 mosaic 增强系数红绿灯小目标场景下 mosaic 本来是有利的能增加小目标数量但系数过高会让灯的形态被裁剪得面目全非。我通常保留默认最多把 hsv_h、hsv_s 稍微调低一点防止红色绿色在增强时色偏过度影响模型对灯颜色的判断。4.3 评估指标曲线怎么看不看mAP前缀和中后缀等于白看资源包里的 runs 目录保存了完整的训练曲线包括 precision、recall、mAP50、mAP50-95 四条曲线还有验证集上的混淆矩阵。很多人只盯着 mAP50 这个数字但红绿灯场景里真正值得关注的是 recall 曲线和混淆矩阵。红绿灯识别最怕的不是误检是漏检。漏检一个红灯在城市道路场景里可能直接导致违章判断失真所以 recall 比 precision 更重要。如果训练完成后 recall 在 90% 以下优先检查数据集中是不是某些灯型数量太少。另外一个重点是混淆矩阵里的 red 和 yellow 两类这两个类在颜色空间上接近如果混淆矩阵里它们的交叉块数值偏高说明训练数据的色彩多样性不够需要补充傍晚和阴天数据。mAP50-95 在红绿灯这种小目标场景里数值可能不算高不要只盯着它焦虑mAP50 达到 0.9 以上就算工程可用。4.4 评估指标的误读陷阱验证集场景单一会让数字骗人我在拆这套资源时注意到文档里额外强调了一件事不要只采集同一个路口的正对视角数据。原因是这个视角下灯光形态几乎不变模型很容易“背下来”而不是“学会”。验证集的数字再漂亮换一个路口、换一个摄像头安装高度mAP 可能直接掉十个百分点。这也解释了为什么资源的提取码说明里建议大家如果做毕设最好在论文里写清楚数据划分策略和场景覆盖范围否则答辩时被问验证集来源会很被动。真正稳妥的做法是至少覆盖三个路口的视频并且包含白天、傍晚、夜间三个时段。验证时还有一个细节如果你从视频里抽帧做数据集抽帧间隔要够大。连续帧之间的场景几乎一样等于把同一张图重复放进去训练时候 loss 降得很快验证时 mAP 很高但实际跑视频就拉胯。我一般按每秒 1 帧的频率抽而且抽完以后再人工过滤掉完全重复的帧。5. 避坑与常见问题我实际跑这个项目时踩过的坑5.1 检测框在视频里抖动明显现象同一盏绿灯在连续帧中框的位置跳跃一会上、一会下面积也忽大忽小。原因置信度阈值比较低时小目标的检测框边界对输入图像的微小变化特别敏感。V 视频编码本身就带来帧间画质波动模型输出的框坐标也会随之抖动。解决检测层面把 conf-thres 从 0.3 提到 0.5 以上减少低置信度输出干扰。后处理层面加一个简单的帧间位置滤波我习惯用指数移动平均对同一个目标的中心坐标做平滑平滑系数取 0.6 到 0.8。如果抖动依旧严重检查视频流解码是否丢帧必要时用 opencv 的 CAP_PROP_BUFFERSIZE 调大缓冲。5.2 opencv安装后import报错Illegal instruction现象conda 环境装好 opencv-python但 import cv2 时进程直接崩溃提示非法指令。原因pip 安装的 opencv-python 默认包含硬件优化指令集老款 CPU 不支持 AVX2 指令集就会触发崩溃。这个问题在红绿灯识别项目的工控机上特别常见因为很多人用旧型号工控机做路侧部署。解决换用 opencv-python-headless 版本去掉 GUI 相关依赖同时兼容性更好。安装命令是 pip install opencv-python-headless4.5.5.62。如果还不行检查 conda 里是否同时存在多个 opencv 版本用 conda list 查一下把多余版本全部移除。5.3 夜间红绿灯漏检严重白天效果很好现象白天检测一切正常晚上灯一亮反而检测不到或者框在光晕外圈中心偏出灯芯。原因夜间图像整体亮度低而 LED 灯区域过曝模型训练时夜间样本偏少对高光比的画面特征学习不充分。问题的本质不是模型结构是训练数据的分布和白天夜间失衡。解决补充夜间数据是根本办法至少让夜间图片占训练集的三成。另外可以在训练前对夜间图片做一次自适应直方图均衡化提升暗部细节。这套资源里模型文件对夜间有一定优化但如果你想跑自己的路段这个比例问题一定要自己调整。夜间推理时还可以把 conf-thres 下调 0.05 到 0.45牺牲一点精度换召回配合后处理状态机判断效果通常能接受。5.4 黄灯和红灯老是互相混淆现象验证集里红灯识别成黄灯的比例偏高或者反过来黄灯被识别成红灯。原因LED 灯在不同亮度下色温变化明显红灯偏暗时饱和度降低色调逼近黄色。标签边界本身存在一个天然模糊区模型学到的颜色特征交叠。解决一是检查标注框是否完整覆盖灯芯如果框偏小只标到最亮区域颜色信息不完整。二是训练前检查标签数据看红黄两类是否有接近重复的图像比如同一组视频的连续帧里红灯和黄灯同时出现标注混淆了。三是如果场景固定在十字路口可以在后处理阶段加一个位置约束条件比如同一组灯板内部红灯和黄灯不会同时亮用这个先验知识消掉一部分误检。5.5 训练时loss正常下降但map上不去现象训练 loss 曲线一路降到 0.05 附近看起来正常但 mAP50 卡在 0.7 左右不涨。原因最常见的是标注框和真实物体边界不贴合大量框比灯的实际发光区域大了一圈。模型学到的是“大框包含灯”而不是“框正好套住灯”导致验证时和标注框的 IoU 偏低。另一个常见原因是训练集里小目标占比过高且数据增强不足模型对小的灯芯区域特征学习不充分。解决重新整理标注数据尤其是检查自动标注或者他人提供的数据集里的框粒度统一性。训练时把 --img 从 640 提到 736 或者 832提升小目标在输入图像中的分辨率。还有一个实用技巧是把训练集和验证集的划分方式改成按视频片段而非按单帧划分避免同一场景跨集出现的泄漏这种方法通常能让 mAP 恢复到更真实的范围。6. 进阶把检测结果变成路口决策信号6.1 状态机判断单帧检测结果不可靠单帧的目标检测结果在工程落地里只能算建议不能当最终决策。红绿灯是状态灯前后帧之间的状态转移有固定逻辑红灯变绿灯要经过黄灯绿灯不能直接跳到红灯除非黄灯时间极短被漏检。我习惯在检测输出后面加一个简单的三态状态机维护当前灯色、持续帧数、状态切换的置信度积累。class TrafficLightState: def __init__(self, max_misses3): self.state unknown self.misses 0 self.max_misses max_misses def update(self, detections): if detections: self.state detections[0][class] self.misses 0 else: self.misses 1 if self.misses self.max_misses: self.state unknown return self.state这个状态机的逻辑是只有连续检测到同一颜色目标状态才更新如果连续多帧没有检测结果状态回到 unknown而不是沿用上一帧结果。max_misses 设 3 意味着允许 3 帧的瞬时丢失超过就认为状态不可信。参数根据实际帧率调整30 帧的视频流里 3 帧大约 0.1 秒足够覆盖目标暂被车辆遮挡的情况。6.2 帧率优化跳过帧与推理尺寸的平衡如果部署设备是一台普通 CPU 工控机yolov5s 在 640 尺寸下很难跑满 30 帧。一个实用的做法是跳帧推理每隔一帧执行一次模型推理中间跳过的那帧直接沿用上一帧的检测结果。因为红绿灯状态变化频率本身很低每秒 5 到 10 次推理就足够覆盖状态变化。用 opencv 读视频时要注意跳帧不是简单丢弃图像而是用 cap.grab() 跳过读取、用 cap.retrieve() 在推理帧时解码能节省不少 CPU。import cv2 cap cv2.VideoCapture(video_path) frame_id 0 while True: ret cap.grab() # 只获取帧不解码 if not ret: break if frame_id % 2 0: # 每两帧推理一次 ret, frame cap.retrieve() detections model(frame) frame_id 1grab 只做帧获取不解码retrieve 才实际解码图像数据。这样跳过的帧省下了 decode 时间也省下了推理时间。如果设备性能仍然紧张还可以把推理尺寸从 640 降到 480代价是远距离灯头的检测率下降。我在实际项目里测过480 尺寸配跳帧策略CPU 上可以稳定跑 15 帧左右的等效帧率路口这种低速场景够用。做红绿灯识别这么久我最大的一个教训是别在没跑通完整动态场景前就信 mAP 数字。静态图片指标和真实视频流之间隔着很多隐形的坑模型输出抖动、状态判断闪烁、不同天气数据分布偏移。从那以后我每次换新场景、新数据都会强制走一遍相同的流程先跑 50 帧视频确认检测稳定性再看状态机输出和人工标注对比最后才回头调训练参数。希望这套方法对你也有参考价值落地的路上少踩几个坑。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑