news 2026/10/10 21:00:10

红绿灯目标检测数据集:1000张图+三格式标签+YOLO训练全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
红绿灯目标检测数据集:1000张图+三格式标签+YOLO训练全流程

简介:面向目标检测学习与实战训练的YOLO红绿灯数据集,包含1000张真实场景高质量图片,数据场景丰富,覆盖不同路口、时间段与拍摄角度,能较好支撑交通灯检测算法的训练与评估。使用LabelImg软件完成人工标注,标注框质量高,同时提供VOC(xml)、COCO(json)、YOLO(txt)三种格式标签,并分别存放在独立文件夹中,无需格式转换即可直接接入YOLO系列模型训练。压缩包共2000个文件,以1000个xml和990个txt标签文件为主,另有6个HTML教程与说明文档、3个Python数据划分脚本和1个yaml配置文件,整体大小487.95MB。随包附赠Linux与Windows环境搭建教程、YOLO训练案例教程,并配套训练集/验证集/测试集划分脚本,便于用户按实际需求重组数据、快速开始实验。已有865人学习下载,适合正在做红绿灯检测、自动驾驶视觉感知相关课程设计、毕业设计或算法复现的学生与研究人员。

1. 红绿灯目标检测数据集为什么值得单独攒一套:1000张图、三格式标签和一套可复现流程

做自动驾驶或辅助驾驶感知的人都有个共识:红绿灯检测是目标检测里最容易翻车的一类任务。通用数据集里也有 traffic light 这个类别,但真正把模型拿到真实路口跑一遍,你会发现白天逆光、夜间过曝、灯色和倒计时数字混在一起的情况,通用模型基本扛不住。这套 YOLO红绿灯目标检测数据集,包含1000张图片,并且把 voc、coco、yolo 三种格式的标签全部配齐,附带划分脚本和训练教程,属于「拿到手不用再花一周转格式、踩划分坑」的落地型资源。适合正在做红绿灯识别、车路协同或智慧交通项目,需要一个干净数据集把模型先跑通的人。

2. 三种标签格式的分工:voc、coco、yolo 各自解决什么问题

2.1 voc 负责「人能看懂」,coco 负责「机器好读」,yolo 负责「训练直达」

很多第一次接触三格式数据集的人会问:既然 yolo 训练只需要 txt 文件,为什么还要保留 voc 和 coco 的标签?答案是三个格式在一条数据流水线里各管一段。voc 格式的标注存在 xml 文件里,标签是object节点下的bndbox,四个坐标是xmin ymin xmax ymax,人眼直接打开就能对着图片检查框是不是标歪了,是最适合做标注质检和人工修正的格式。coco 格式则是把整个数据集的所有标注汇总进一个annotations.json,结构里包含images、annotations、categories三张表,坐标变成bbox加area,并且标注类别有全局统一的 id,适合做跨数据集的评测基准和预训练迁移。yolo 格式是每张图对应一个同名 txt 文件,每行记录class cx cy w h,坐标是归一化后的中心点和宽高,模型加载标签时不用做任何换算,直接喂给 loss 计算。

三格式标签同时存在,最实用的意义是你可以随时换训练框架。今天用 ultralytics 的 yolo v8 跑一版,明天想拿 detectron2 复现一个 Faster R-CNN 做对比实验,后天天想用 mmdetection 跑 COCO 评测,不需要重新标注,直接转换即可。从工程效率上讲,三格式配齐省掉的不是一次转换时间,而是标注人员几天的重复劳动。常见做法是标注阶段用 voc 格式做存储和 review,随后再用脚本批量转出 coco 和 yolo,这个数据集落地时就把这条链路走完了。

2.2 坐标换算逻辑:从 voc 的左上右下到 yolo 的中心宽高

三种格式的坐标换算在转换脚本里是最容易写错的地方。voc 给的是绝对像素坐标xmin ymin xmax ymax,yolo 要的是相对图片宽度和高度的归一化中心坐标,换算公式如下。

import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_txt_path, class_map): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find('size/width').text) img_h = int(root.find('size/height').text) with open(out_txt_path, 'w') as f: for obj in root.findall('object'): cls = obj.find('name').text if cls not in class_map: continue box = obj.find('bndbox') xmin = float(box.find('xmin').text) ymin = float(box.find('ymin').text) xmax = float(box.find('xmax').text) ymax = float(box.find('ymax').text) center_x = (xmin + xmax) / 2.0 / img_w center_y = (ymin + ymax) / 2.0 / img_h width = (xmax - xmin) / img_w height = (ymax - ymin) / img_h f.write(f"{class_map[cls]} {center_x:.6f} {center_y:.6f} {width:.6f} {height:.6f}\n")

这段代码的核心是先把 xml 里的文件名、图片宽高和 bndbox 坐标取出来,然后做两次除法:一次把左上右下角坐标转成中心点,一次把宽高转成相对宽高。class_map需要手动定义类别到数字 id 的映射,比如{'red': 0, 'green': 1, 'yellow': 2},这一步决定后续训练时类别顺序是否和 data.yaml 一致。

参数说明里最容易被忽略的是img_w和img_h必须取原始图片的宽高,而不是标注工具界面显示的尺寸。如果图片在标注前被压缩过,xml 里记录的尺寸和实际图片不一致,转换出来的 yolo 标签全部偏移,训练时模型学到的边界框是错位的。另一个常见坑是浮点精度:yolo 标签一般保留 6 位小数就够了,过长的尾数会让 txt 文件体积膨胀且没有任何精度收益。

2.3 从 voc 转 coco 时 bbox 格式的坑:xywh还是xyxy

从 voc 转 coco 的常见误区是把 bbox 直接写成[xmin, ymin, xmax, ymax]。coco 官方标注里 bbox 定义是[x, y, width, height],也就是左上角坐标加宽高,和 voc 的左上右下完全是两种语义。更隐蔽的是area字段,它应该等于宽乘以高,而不是四个坐标值的某个差值。如果从 voc 转 coco 时忘记把xmax - xmin算成width,训练时 coco 评测脚本计算 IoU 会直接出错。

转 coco 的另一个细节是annotation里的id必须全局递增唯一,image_id要能对应到images表里的 id。很多人转换时直接用循环变量做 id,一旦图片顺序在后续处理中被 shuffle,image_id 就和图片对应不上,评测分数会莫名掉几个点。建议的做法是先把图片列表定死,按文件名排序后给每张图分配 id,再遍历标注生成 annotation 列表。

3. 用划分脚本把1000张图拆成训练集、验证集和测试集

3.1 随机划分为什么会让小类别直接消失

1000张图看起来不少,但红绿灯数据有一个特点:类别天然不均衡。同一张图里红灯可能只占十来个像素,黄灯的出现频率远低于红灯和绿灯。如果直接按 8:1:1 做随机抽样划分,黄灯这类小样本类别很可能在验证集里一条都没有,训练时模型会认为「只要不是红灯就是绿灯」,验证集却因为恰好包含一张黄灯图而给模型打出低分——这不是模型变差了,是划分本身毁掉了数据分布。

所以划分脚本必须做分层抽样,按每个类别在图片中的出现频率,确保训练集、验证集、测试集里各类别占比接近总体分布。红绿灯数据还有一个特性:同一摄像头同一路口连续拍出来的几十帧图非常相似。如果这些帧被随机拆到训练集和验证集,相当于验证集里出现了训练集的近复制样本,mAP 虚高几倍,模型一上真实路口立刻现原形。因此划分前要按拍摄批次或者场景先做分组,再对组内做整体划分。

3.2 可直接运行的按类别分层划分脚本

下面是一个按类别分层、同时支持按场景分组划分的脚本,可以直接改路径使用。

import os import random import shutil from collections import defaultdict from sklearn.model_selection import train_test_split def load_yolo_labels(txt_path): """读取 yolo txt 标签,返回该图片包含的类别集合""" classes = set() with open(txt_path, 'r') as f: for line in f: parts = line.strip().split() if parts: classes.add(int(parts[0])) return classes def group_images_by_scene(image_dir): """按文件名前缀分组,例如 scene_001_frame_002.jpg 归入 scene_001 组""" groups = defaultdict(list) for name in os.listdir(image_dir): if name.endswith(('.jpg', '.png')): scene_id = '_'.join(name.split('_')[:2]) groups[scene_id].append(name) return groups def stratified_split(image_dir, label_dir, train_ratio=0.8, val_ratio=0.1, seed=42): random.seed(seed) groups = group_images_by_scene(image_dir) image_paths = [] for scene_id, names in groups.items(): for name in names: image_paths.append((name, scene_id)) # 第一次按场景分组切训练/其余 train_candidates, temp = [], [] for name, scene_id in image_paths: (train_candidates if random.random() < train_ratio else temp).append((name, scene_id)) # 第二次把剩余按 val_ratio 拆分 val_count = int(len(image_paths) * val_ratio) random.shuffle(temp) val_set, test_set = temp[:val_count], temp[val_count:] return train_candidates, val_set, test_set

这段脚本先按文件名前缀把图片归入场景组,再以组为单位切分。第一次按比例切出训练集,第二次把剩余样本随机分给验证和测试。这样同一个场景的连续帧不会出现在两个集合里,验证集的评估结果更接近真实部署表现。

脚本里关键参数是train_ratio和val_ratio,对 1000 张图来说常见的比例是 0.8 和 0.1。seed必须固定,方便别人复现你的实验结果。分层逻辑在代码里没有单独体现类别约束,只做了场景分组,严格的分层策略还需要在切分后打印各类别分布做检查。

3.3 划分完成后必做的三类检查

划分脚本跑完后不要急着开训练,先做三个检查。第一个是文件配对检查,遍历 txt 目录,统计没有对应标签的图片,以及没有对应图片的 txt,这些脏数据会在训练时报错。第二个是类别分布直方图,打印训练集、验证集、测试集里 red、green、yellow 三类各自出现的次数,如果某个集合里黄灯占比明显低于全局比例,说明划分脚本的随机种子或者分组策略有问题,需要重新划分。第三个是图片尺寸一致性检查,红绿灯图像来自不同摄像头时,尺寸可能是 1920x1080 和 1280x720 混在一起,yolo 训练时超参里如果开了rect模式问题不大,不开的话建议统一 resize。

一个实用习惯是划分完成后立刻生成清单文件,把三张图片划分到三个 txt 文件里,同时在清单旁边生成一个 hash 文件保存样本名。后续训练重复跑的时候直接用清单,不需要重新执行划分脚本,避免两次划分结果不同导致试验对比失效。

4. 从零跑通红绿灯 yolo 训练:配置、命令与参数解读

4.1 data.yaml 的写法和类别顺序

拿到三格式标签后,训练的第一步是写对data.yaml。这个文件的路径前缀决定了训练时去哪里找图片和标签,很多人在这一步翻车是因为用相对路径而当前目录不对,模型报AssertionError: Label class 1 exceeds nc=1或者直接找不到图片。

# data.yaml,放在数据集根目录下 path: /home/user/traffic_light_dataset # 数据集绝对路径 train: images/train val: images/val test: images/test names: 0: red 1: green 2: yellow

names里的顺序必须和你转换脚本里class_map的顺序完全一致,否则训练出来的模型输出类别编号和实际灯色对不上。训练时的类别数由 yaml 里的 names 个数决定,不需要单独写nc参数。一个容易被忽略的点是path使用绝对路径更稳妥,尤其当你用 pycharm 启动训练时,工作目录经常不是数据集根目录,相对路径会直接打偏。

还要确认 labels 目录的结构。yolo 训练默认标签路径是和 images 同级的labels目录,内部按 train/val/test 子目录和图片一一对应。若你的数据集把标签单独放在另一个顶层目录,需要在train和val配置里用datasets/traffic_light/images/train加labels/train的方式指定,或在数据目录内做软链接。脚本里我通常直接建立 images 和 labels 的对称目录结构,省得训练时改一堆参数。

4.2 训练命令与超参数调整

用 yolo v8 训练红绿灯模型的最小命令如下。

yolo detect train data=traffic_light.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=640 \ batch=32 \ lr0=0.01 \ optimizer=AdamW \ seed=42 \ device=0

这个命令用yolov8n.pt作为预训练权重初始化,imgsz设为 640,这是 yolo 系列在 COCO 上表现稳健的默认输入尺寸。红绿灯目标在整幅图像里通常很小,如果你用的摄像头是 1920 分辨率,输入图可以提高到 960 或 1280,小目标检测召回率会明显上升,但训练速度和显存消耗也随之增加。

epochs和batch是影响最大的两个参数。1000 张图的数据量不算大,150 个 epoch 通常足够收敛;如果训练过程中验证集 loss 还在下降就继续加到 200,如果已经回弹就回调到 120。batch取决于显存,单张 24G 卡可以开 32,16G 卡降到 16,显存不足时报错CUDA out of memory是正常的,减小 batch 而不是调小 imgsz 是优先选择。

优化器默认是 auto,对于这个数据量,显式指定AdamW往往比 SGD 收敛更快。lr0初始学习率新手爱用 0.001,实际上 pre-trained 模型用 0.01 起步更常见,配合 warmup 和 cosine 衰减才能让 loss 顺利下降。具体数值要在训完第一个 epoch 后看 loss 变化趋势再调整。

4.3 模型导出:onnx 与部署

训练完成后,runs/detect/train/weights/下会出现best.pt和last.pt。best.pt是验证集上 mAP 最高的权重,直接用它做后续导出和推理。导出 ONNX 的命令如下。

yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=640 dynamic=True

导出 onnx 的核心参数是dynamic=True,这会让导出的模型支持动态 batch 和动态输入尺寸。如果你的部署环境是 jetson agx orin 或者 d435i 深度相机配套的边缘盒子,动态尺寸能省下不少重导出的时间。导完后用onnxruntime跑一次推理,确认输出维度是[1, 84]或者[1, 25200, 84]这类格式,前 4 个是 bbox 的 cx、cy、w、h,第 5 个是置信度,后面是类别概率。红绿灯检测在部署时常遇到的问题是相机 ISP 把红色灯罩的色彩平衡掉,导致红灯被识别成黄色甚至灰色,这一步在导出模型阶段解决不了,属于数据增强范畴。

5. 避坑与验证:红绿灯检测最容易翻车的五个问题

5.1 五条高频踩坑记录

现象一:训练时提示Label class 0 missing from class list。原因是数据集里存在空标签文件或者类别 id 超出 data.yaml 定义的 names 数量。解决方法是遍历标签目录,把类别 id 超过 2 的 txt 文件删除或重新标注,同时统计每个类的样本数,确认没有空文件留下。

现象二:mAP 很高但推理时把绿色倒计时数字框成目标。原因是标注时把「红灯/绿灯/黄灯」整个圆灯和数字连带框进去了,模型学到了倒计时数字的特征。解决方法是严格按灯罩圆形区域标注,只框灯体不框数字;如果灯和数字共用一个发光区域,则考虑把类别拆成 red(含数字)和 red_none(纯灯),让模型学会两者都归为红灯。

现象三:夜间图片检测精度骤降。原因是训练集里白天图占七成,夜间过曝和光晕图太少,模型对夜景域分布学习不足。解决方法是训练时增强夜景:对图片做随机亮度抖动、高斯模糊、模拟光晕,或者在数据集中额外补拍夜间视频帧。yolo 训练参数里hsv_h、hsv_s、hsv_v三个增强项可以适当加大,尤其把hsv_v从默认 0.4 调到 0.7 能明显提升低光场景的鲁棒性。

现象四:训练和验证划分后小目标召回率低于 10%。原因是 640 输入下红绿灯目标在图里只有 8x8 像素,yolo 下采样到 80x80 特征图时目标信息几乎丢失。解决方式是用 960 输入尺寸训练,必要时开启saver多尺度训练,或者在 yolo 配置里加上 P2 层小目标检测头。

现象五:转换脚本跑完后 coco json 加载报 KeyError。原因是 json 里的is_crowd字段漏填,coco 官方 api 读取时会强制检查这个字段。解决方法是给每条 annotation 补上is_crowd: 0,同时在 images 表里补license和flickr_url字段,这些字段虽然不参与计算,但 cocoapi 的加载器会校验字段存在性。

5.2 用混淆矩阵判断模型是否真的可用

mAP 是宏观指标,红绿灯场景判断模型是否可用必须看混淆矩阵。训练完成后运行yolo detect val会在runs/detect/val/下生成confusion_matrix.png,重点看三个数字:红色被误判成绿色的比例、绿色被误判成红色的比例、黄灯被误判成其他灯色的比例。前两项超过 5% 就直接下线,因为这是行车决策的信号灯语义错误,比漏检更危险。误判多发生在目标尺寸小或被遮挡时,可以针对性补充难负样本,而不是盲目增加总训练数据。

5.3 进阶用法:同一份数据集同时喂给 yolo 和多模态分析

当你只拿 1000 张图训练一个红绿灯检测模型,可能会觉得数据量太小不踏实。实际上这份数据集的价值在迁移学习场景下会放大不少。coco 格式标注可以直接用于训练 swin transformer 或 detr 等检测框架,voc 格式可以用于半监督学习的分批标注。红绿灯检测往往只是智慧交通系统的一个环节,yolo 模型负责输出灯色和位置,后接一个多模态大模型分析灯色状态与车流的关系,这时数据集的 coco 格式让检测结果与语言描述对齐变得非常直接,不需要再写一次坐标转换。

另一个值得尝试的方向是用这份数据集做跨摄像头域适应实验。取出某个场景的图片作为源域,另一个摄像头拍到的图片作为目标域,利用划分脚本把场景按摄像头分开,就能在域适应研究中跑基线。模型最终要在新路口上线,保守做法是先只用这份数据集训练,再收集新路口两小时视频做半自动标注微调,而不是指望一个模型吃遍所有路口。这是我的个人经验,尤其在红绿灯这类外观变化有限但环境光照差异大的目标上,花时间做微调往往比攒十万张图更有收益,希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 21:00:03

day36算法练习:质数判定、字符串处理与排序的细节优化

这一天的挑战有点意思——三道题放在一块儿&#xff0c;其实正好覆盖了编程里三个最基础也最容易出问题的环节&#xff1a;数学逻辑、字符串处理、还有集合操作。质数、翻译字符串、分割数字并排序&#xff0c;听起来都是入门题&#xff0c;但真上手写的时候&#xff0c;你会发…

作者头像 李华
网站建设 2026/10/10 20:57:01

LR-ASPP + MobileNet v3:道路图像语义分割的轻量化实战与PyTorch实现

简介&#xff1a;面向道路场景图像语义分割任务&#xff0c;这份资源提供了一套基于轻量级分割网络与迁移学习的实战工程。利用预训练权重微调&#xff0c;在道路分割数据集上仅训练10个轮次&#xff0c;验证集平均交并比即达到0.98&#xff0c;效果显著&#xff0c;适合希望快…

作者头像 李华
网站建设 2026/10/10 20:53:38

Linux文本处理三剑客:grep、sed与awk实战解析

Linux 文本处理工具&#xff0c;这三个词组合在一起&#xff0c;可能第一反应是“这有什么好讲的&#xff0c;不就是 grep、sed、awk 嘛”。但如果你真在服务器上排查过 800MB 的日志文件&#xff0c;被满屏的报错刷到眼花&#xff0c;或者需要从一段接口返回里精确抠出某个字段…

作者头像 李华
网站建设 2026/10/10 20:53:09

中外儿童背诵内容对比:中国娃吟诗作对,外国娃背什么?

最近刷到好几个短视频&#xff0c;一边是中国三岁半的萌娃穿着小汉服&#xff0c;奶声奶气地背《将进酒》&#xff0c;背到“天生我材必有用”还配了个握拳的小动作&#xff1b;另一边是外国小朋友围坐一圈&#xff0c;在老师带领下念法语数字歌&#xff0c;或者一本正经地背诵…

作者头像 李华
网站建设 2026/10/10 20:52:22

微信小程序校园社交开发实战:云开发+SpringBoot混合架构与避坑指南

简介&#xff1a;这份PDF文档是2021年中国高校计算机大赛微信小程序应用开发赛中南赛区二等奖作品“约在南华校园”的完整说明资料&#xff0c;面向参赛学生、小程序开发者及对校园兴趣社交产品感兴趣的学习者。文档围绕一款服务华中地区高校学生的轻量级社交平台展开&#xff…

作者头像 李华
网站建设 2026/10/10 20:48:29

按钮禁用时 hover 效果还在?用 is-disabled 彻底消除的完整方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华