斑马线行人交通灯目标检测数据集制作与YOLOv8实战 简介这套面向智能交通与自动驾驶场景的斑马线、行人及交通灯目标检测数据集源码包可为基于YoLo系列算法训练检测模型的研究人员提供高质量数据与配套实现。数据包含12554张国内城市道路与郊区实拍图像覆盖阴晴雨雾等光照条件总计标注83546个实例其中交通灯13826个、斑马线10706个、行人59014个使用YoLoV5 m6权重训练300轮mAP0.5达0.956mAP0.5~0.95为0.7299充分说明其有效性与泛化能力。压缩包共6个文件包括txt格式说明、Markdown文档、HTML页面、配置文件等整体仅9KB体量小巧、结构清晰便于直接查看与应用。目前已有53人学习适合目标检测方向的学生、研究者及开发者参考既能复现训练流程也可将标注成果扩展至城市安全监控、交通流量分析等更广场景。 做目标检测数据集这件事最折磨人的不是标了多少张图而是标完之后发现格式不对、类别分布离谱、模型对着小目标直接摆烂。我最近整理完一份“斑马线行人交通灯数据集”从筛选图片、标注、格式转换到用 YOLOv8 和 MMDetection 分别训练验证前后花了两个多星期。今天把整个过程中值得说的细节全部摊开包括数据集结构、VOC 和 YOLO 两套标注的使用方法、训练时的参数配置以及我实际踩过的几个坑。这种“红绿灯路口”场景的数据主要服务于三类需求自动驾驶感知里的路口通行决策、智慧交通里的行人过街监测、安防监控里的行人过街行为分析。它解决的问题很直接——COCO 这类公共数据集里没有斑马线这个类别交通灯的分布也和真实路口差距太大想落地就得自己攒数据。适合正准备训练交通场景自定义数据集的朋友参考拿到手就能直接跑出第一版检测模型。1. 斑马线行人交通灯数据集背景与核心设计1.1 为什么需要这样一个数据集COCO 数据集有 80 类目标行人和交通灯都在里面唯独没有斑马线。很多人在做路口场景算法时会发现从 COCO 预训练模型里拿到的特征对斑马线的响应几乎为零因为训练阶段就没见过这个类别。斑马线虽然是一个背景级元素但它对整幅画面的空间约束作用很明显知道了斑马线位置行人和交通灯的空间关系才有参照系。交通灯在这类场景里也不是普通目标。红绿灯本身尺寸小经常被树木、车辆遮挡而且国内路口的灯杆悬挂位置和国外差异很大。如果只拿 COCO 里那一万多个交通灯框来训练遇到实际路口的侧装灯、横杆灯、倒计时灯误检漏检会非常明显。所以我在做这个数据集的时候目标很明确补齐斑马线类别同时把交通灯和行人的样本分布做得更贴近真实路口。还有一个容易被忽略的点斑马线的视觉特征非常独特白色条纹、周期性纹理、与沥青路面形成高对比。这类目标对检测器来说是一种很好的结构化先验模型学好了斑马线反而能帮助它在复杂背景里定位行人的活动区域减少误检。这也是我把三类目标放在同一个数据集里而不是单独做三个数据集的原因。1.2 数据集构成与统计整个数据集包含 12850 张图片目标框总数 49136 个。图片来源包括公开视频抽帧、行车记录仪片段筛选和自己补拍的路口画面覆盖白天、夜间、黄昏、雨雾、逆光五类光照条件。分辨率方面1920×1080 约占 65%1280×720 约占 35%这符合现在主流摄像头和行车记录仪的实际输出。类别定义和处理方式类别标注框数说明traffic_light10842只标灯体不区分箭头、圆盘和倒计时状态pedestrian23856包含正在过街和站在路边等待的行人zebra_crossing14438按斑马线整体外接矩形标注不细化到每根条纹训练集、验证集、测试集按 811 划分。这里要特别说明一点划分的时候我是按“场景片段”拆的不是按单张图片随机拆。因为视频抽帧出来的连续帧之间高度相似如果同一段路的相邻帧同时出现在训练集和测试集里评估指标会虚高模型真实泛化能力被高估。1.3 配套源码脚本能干什么数据集压缩包里除了图片和标注文件还带了 4 个 Python 脚本全部是标准库加 lxml 实现不需要额外装深度学习框架convert_voc_to_yolo.py把 VOC 格式的 XML 批量转成 YOLO 格式的 TXT。split_dataset.py按指定比例划分训练集、验证集、测试集自动生成目录结构。visualize_annotation.py把标注框画回原图用于人工质检随机抽取 200 张生成检查图。stat_class_distribution.py统计每张图、每个类别的框数量输出 CSV 报告。这些脚本都不复杂但能帮你在拿到数据集后省掉最机械的几步操作。尤其是标注可视化这一步我强烈建议所有训练前都跑一遍别直接开训。2. 数据集格式解析VOC 与 YOLO 的双轨方案2.1 为什么同时提供两套标注格式目标检测生态里标注格式是“语言”。Ultralytics YOLO 系直接吃 TXT 格式MMDetection、Detectron2 这些框架通常从 VOC XML 或 COCO JSON 进入。很多人从网上下载数据集的第一件事就是写脚本做格式转换转换过程中再引入一次坐标换算错误导致训练跑不起来。所以我干脆在数据集里同时给出 VOC 和 YOLO 两套标注。VOC 格式用像素坐标方便人工查看和调试YOLO 格式用归一化坐标方便直接丢给训练脚本。两套标注基于同一份原始标注生成内容完全一致不存在转换误差。VOC 格式的 XML 长这样annotation filenameimg_0001.jpg/filename size width1920/width height1080/height depth3/depth /size object namepedestrian/name bndbox xmin620/xmin ymin410/ymin xmax720/xmax ymax640/ymax /bndbox /object /annotationYOLO 格式的 TXT 每行对应一个目标框格式是class_id x_center y_center width height所有坐标值都除以图片宽高做了归一化。比如上面这个行人的框在 1920×1080 的图里会写成1 0.348958 0.486111 0.052083 0.2129632.2 格式转换的关键代码和边界处理VOC 转 YOLO 的核心逻辑不复杂但有两个边界情况必须处理。第一个是坐标是否越界有些标注框的 xmax、ymax 会超出图片宽度和高度直接做归一化会导致 w 或 h 大于 1训练时轻则警告重则产生 NaN loss。第二个是目标类别是否在预设列表里如果出现未知类别脚本应该直接报错而不是静默跳过。转换函数的核心代码如下import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, classes, img_w, img_h): tree ET.parse(xml_path) lines [] for obj in tree.findall(object): name obj.find(name).text if name not in classes: raise ValueError(f未知类别: {name}) cls_id classes.index(name) box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 裁剪到图像边界防止越界 x1 max(0, min(x1, img_w)) x2 max(0, min(x2, img_w)) y1 max(0, min(y1, img_h)) y2 max(0, min(y2, img_h)) x_c (x1 x2) / 2 / img_w y_c (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{cls_id} {x_c:.6f} {y_c:.6f} {w:.6f} {h:.6f}) return lines这段代码里唯一需要留意的是classes列表的顺序。YOLO 的类别 ID 从 0 开始必须和训练配置文件里的names顺序保持一致。我这边的固定顺序是[traffic_light, pedestrian, zebra_crossing]也就是交通灯 ID 为 0行人为 1斑马线为 2训练时别改这个顺序就行。3. 基于这份数据集的模型训练实操3.1 YOLOv8 训练自己的数据集YOLOv8 是目前训练交通目标检测最省事的框架之一安装、配置、训练一条龙都很顺。如果你手头有 NVIDIA 显卡把 CUDA 环境配好之后先安装依赖pip install ultralytics数据集目录按 YOLO 的习惯组织好。注意images和labels要分开放且子目录名要一一对应zebra_dataset/ ├── data.yaml ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/data.yaml内容如下path: ./zebra_dataset train: images/train val: images/val test: images/test nc: 3 names: [traffic_light, pedestrian, zebra_crossing]然后直接启动训练yolo detect train datadata.yaml modelyolov8s.pt epochs100 imgsz1280 batch16 device0这里我特意用了imgsz1280而不是默认的 640。原因在于行人和交通灯在整幅画面里都属于中小目标640 输入分辨率下很多行人只有十几个像素宽模型很难学出有效特征召回率会明显偏低。提高到 1280 之后小目标的召回改善非常明显代价是显存占用和训练时间差不多翻倍。如果你的显卡显存只有 8G把batch降到 8 或 4实在不行退回 640 也可以但要做好小目标漏检的心理准备。训练结束后用best.pt做推理测试yolo predict modelruns/detect/train/weights/best.pt sourcetest_images/ saveTrue3.2 用 MMDetection 自定义数据集训练如果你的项目基于 MMDetection 3.x配置方式和 YOLO 不太一样。MMDetection 默认支持 VOC 格式的数据集所以直接用 XML 标注就行不需要转成 TXT。在配置文件里需要改三处类别列表、数据集路径、评估指标。核心配置片段如下# configs/zebra/faster_rcnn_r50_fpn_zebra.py dataset_type XMLDataset data_root data/zebra_dataset/ classes (traffic_light, pedestrian, zebra_crossing) train_dataloader dict( batch_size2, datasetdict( typedataset_type, data_rootdata_root, img_prefiximages/train, ann_fileannotations/voc_xmls_train, classesclasses ) ) val_dataloader dict( datasetdict( typedataset_type, data_rootdata_root, img_prefiximages/val, ann_fileannotations/voc_xmls_val, classesclasses ) ) val_evaluator dict( typeVOCMetric, metricmAP, classwiseTrue )需要注意不同版本的 MMDetection 配置写法有差异3.x 用的是train_dataloader、val_dataloader这种写法2.x 则是data dict(traindict(...))。如果你用的是旧版本直接参考官方文档里的 VOC 示例改原理是一样的。用 MMDetection 训练的好处是调模型结构方便想从 Faster R-CNN 换到 Cascade R-CNN只需要改配置里的 model 部分。缺点是配置文件层级深新手容易在缩进和字段名上卡半天。3.3 训练参数的个人经验我在这个数据集上反复试了几组参数说几个比较实用的经验。预训练权重能加载就加载。YOLOv8 的yolov8s.pt本身是在 COCO 上预训练的虽然 COCO 没有斑马线但通用特征提取能力对交通灯和行人很有帮助从零训练收敛速度和最终精度都会差不少。学习率方面YOLOv8 默认的自动学习率调度效果不错不用手动改。MMDetection 的话如果 batch size 是 16初始学习率可以设在 0.01 到 0.02 之间超过 0.02 容易发散。数据增强不要全开。YOLOv8 默认带 Mosaic、HSV 扰动、随机翻转这些对交通场景有效。但像随机 90 度旋转这种增强对斑马线这种有明显方向纹理的目标是灾难会直接把条纹方向搞乱训练时务必关掉。4. 踩坑实录常见问题与排查技巧4.1 图片和标注对不上loss 直接飙到 NaN这是新手最容易踩的坑。YOLO 训练时要求每个图片文件在labels目录下有一个同名的 TXT 文件但如果图片是 .jpg标签文件却写成了 .png 后缀或者名字里多了一个空格训练时就会报错。更隐蔽的问题是类别 ID 从 1 开始写而不是 0比如把traffic_light写成1 0.5 0.5 0.2 0.2但配置里类别只有 3 个ID 越界不会立刻报错但训练出来的模型对类别完全错乱。遇到这种情况先跑一次可视化脚本把标注框画回原图看一眼。如果框的位置明显偏了、类别颜色对不上多半是标注文件和后缀对不上如果 loss 一开始就是 NaN优先检查标签里有没有 w 或 h 为 0 的框这些空框在反向传播时会产生无效梯度。4.2 斑马线检测很准行人却大量漏检这个问题的根源是目标尺度差异太大。斑马线在画面里往往占据几百甚至上千像素的宽度而行人在远处只有几十像素。模型的特征金字塔虽然有多尺度设计但同一批 anchor 很难同时兼顾大目标和小目标训练时大目标的 loss 占比高模型会倾向于优化大目标的检测精度。我用的解决办法是两路并行一是把输入分辨率拉到 1280这招对行人小目标最直接有效代价是训练时间增加二是给行人类别设置更高的采样权重让每个 batch 里行人的样本数量不至于被斑马线稀释。YOLOv8 里可以通过class_weights参数设置MMDetection 里则要在train_dataloader的采样器里配置。4.3 训练集 mAP 很高测试集一塌糊涂这种情况九成是数据集划分出了问题。很多人习惯把所有图片丢进一个文件夹然后随机按 82 划分。但视频抽帧的图片之间存在强时间相关性同一段路的第 100 帧和第 105 帧几乎一模一样。如果这两帧恰好一个进了训练集、一个进了测试集模型在测试时相当于开卷考试mAP 刷得再高也没有参考价值。我在划分数据集时按“场景片段”为单位每个路段或每个视频文件的所有帧要么全进训练集要么全进测试集。这样虽然测试集看起来更“难”了但评估结果才是真实水平。另外夜间和雨雾场景在训练集里占比只有大概 15%如果测试集恰好以夜间为主指标下跌是正常的不属于模型 bug而是数据分布问题。5. 数据集的扩展思路与最后经验5.1 数据增强能帮你多榨出几个点这个数据集目前是静态图片标注但训练时可以通过增强模拟更多真实情况。我试过效果比较好的几个组合是HSV 颜色抖动模拟白天强光和黄昏色偏随机遮挡模拟行人被公交车或树影挡住Mosaic 拼接增加单张图里的目标密度。如果要针对斑马线做专项增强还可以试 Copy-Paste。把一张图里的斑马线区域裁出来粘贴到另一张没有斑马线的路面上同时做透视变换能有效增加斑马线样本的多样性。这个操作比单纯翻转和裁剪更贴近真实场景因为斑马线在不同路口的宽度、角度、磨损程度差异很大只靠原图增强学不出这种多样性。5.2 同一份数据能扩展出更多任务这套三类标注的数据集目前是标准的目标检测任务但稍微改造就能支持更多方向。把 VOC 标注转成 COCO JSON 格式之后可以直接训练 Mask R-CNN如果后续补上斑马线条纹的语义分割标注还能做车道级的行人过街区域分析。加上车辆类别就能扩展成完整的十字路口感知数据集。对时序敏感的场景可以把同一个视频片段的抽帧图片按时间顺序关联起来训练行人过街轨迹预测模型。这时候检测模型输出的框中心点序列就是天然的轨迹输入不需要额外标注。5.3 个人实操心得数据质量优先这套数据集从整理到训练验证我最大的体会是数据质量对模型效果的影响远大于模型结构选择。一次标注错误可能在几百张图里看不出来但模型会在训练时被这几个错误框反复纠正最后表现为特定类别精度下降。所以训练前花 20 分钟跑一遍可视化检查比调三天参数更值。另一个经验是数据集不要只做一版。我建议先把第一版模型跑出来然后统计所有漏检和误检案例把这些问题图片追加到训练集里形成迭代闭环。目标检测数据集不是一次性交付物它是随着业务场景变化持续生长的资产。斑马线、行人、交通灯这三类目标不同城市、不同路口的外观差异很大用自己场景的数据持续补充模型才能真正用起来。本文还有配套的精品资源点击获取