news 2026/9/8 23:58:32

交通灯检测未标注数据获取与利用:从数据集挖掘到伪标签训练

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
交通灯检测未标注数据获取与利用:从数据集挖掘到伪标签训练

简介:本资源是面向计算机视觉与智能交通领域研究者的交通灯检测基础数据集,适用于目标检测模型训练、信号灯状态识别算法验证及CCF BDCI相关赛题备赛。数据集包含2000个原始采集样本,其中1997张JPG格式图像覆盖城市道路、交叉口、不同光照与天气条件下的真实交通灯场景,2个JSON文件提供图像元信息与初步结构化描述,1个TXT文件含基础说明与使用指引,整体压缩包大小为873.01MB。目前已有1702人下载学习,体现了其在实际项目中的高参考价值。用户可直接获取未经标注的原始图像资源,结合主流标注工具(如LabelImg、CVAT)开展自定义标注,适配YOLO、Faster R-CNN等检测框架;同时,图像数量充足、场景多样性高,便于划分训练/验证/测试集,并支持多任务拓展(如红黄绿灯分类、箭头灯识别等)。

1. 为什么你需要一份“未标注”的交通灯数据

1.1 交通灯检测到底难在哪

做了几年检测任务,说实话,交通灯是少数让我觉得“数据比模型更值钱”的方向。它和通用目标检测不太一样,难在几个很实际的地方:第一,目标太小。路口画面里一辆车可能占几百个像素,但一个信号灯往往只有二三十个像素。在博世那套经典数据集里,很多灯的标注框甚至不到32x32像素,放到YOLOv8默认的640输入分辨率里,基本就是几个点。第二,环境干扰太严重。逆光、雨天、夜晚、LED屏闪烁、树影遮挡、对面车灯直射,都会让同一盏灯呈现出完全不同的样子。第三,地域差异非常大。国内常见的是圆盘灯加倒计时,欧洲很多路口是横排的小箭头灯,美国还有一堆黄灯闪烁的工况。同一个模型搬到另一个城市,性能掉几个点是非常正常的。

也就是说,交通灯检测的真正瓶颈不是模型结构,而是数据能不能覆盖足够多的场景。而“覆盖场景”这件事,其实不一定非要靠人工标注数据来完成。未标注数据同样能帮上大忙。

1.2 未标注数据能解决什么问题

很多人一听到“未标注数据”就觉得没用,因为训练目标检测确实需要框。这是思维定式。未标注数据在交通灯这个场景里至少有三条成熟的用法:

  • 自监督预训练。拿到几千张没标签的路口图像,在域内数据上做一轮自监督预训练,让backbone先学会“红灯、绿灯、黄灯、箭头灯长什么样”这种底层视觉特征,再拿少量标注数据微调。实践里这种做法的效果往往比直接用ImageNet预训练权重要好,尤其是当标注数据只有几百张的时候。

  • 伪标签 + 半监督迭代。用一个已经能用的交通灯检测模型,在未标注数据上推理,把高置信度的预测结果当成标签,和人工标注数据混合在一起训练。这是目前性价比最高的扩数据方式,后面我会重点讲怎么做。

  • 域适应。你的模型在A城市跑得好,到了B城市效果变差。这时候你不需要在B城市标大量数据,只需要采集B城市的未标注路口视频,用域适应或者自训练的方式让模型对齐目标场景的分布。这在智慧交通项目交付时特别实用。

1.3 哪些人适合看这篇

这篇文章主要写给三类人:一是做自动驾驶感知的算法工程师,想扩充交通灯场景但标注预算有限;二是做智慧交通、车路协同项目的开发者,手里有大量摄像头视频但是没时间标;三是刚入门目标检测的学生,想完整体验一遍“数据采集—清洗—伪标签—训练—评估”的全流程。

如果你只是想要一份“下载下来就能直接train”的标注数据集,那这篇帮助有限;但如果你手头恰好有一些路口视频、行车记录仪视频,或者你能从公开数据集的原始视频里挖出大量未标注帧,那这篇应该能帮你省下好几周的标注时间。

2. 主流交通灯数据集盘点:哪些能拿到未标注数据

2.1 经典数据集清单与特点

我把做交通灯检测绕不开的几个公开数据集整理了一下。这里我特意不写死精确到个位数的统计量,因为很多版本和划分在不同平台上不一样,以官方发布文档为准更可靠。但数据集的特点和适用方向是有共性的:

数据集来源/城市内容特点标注情况未标注获取方式
Bosch Small Traffic Lights德国1280x720车载图像,灯体极小,经典小目标测试集标注图像大约一千多张官方原始视频序列中有大量未标注帧,需申请
LISA Traffic Light美国加州包含白天/夜晚、圆形灯/箭头灯/行人灯等多种类型,场景丰富帧级标注,覆盖约上万帧官方提供原始视频,标注稀疏,可提取未标注帧
DriveU Traffic Light德国城市道路多段城市道路视频,标注较稀疏,适合抽未标注帧关键帧标注,不是每一帧都有框完整的视频流可以按帧抽取
LaRa Traffic Light法国巴黎带GPS和时间戳同步的视频序列,多路口、多灯型视频由标注帧和大量无标注帧组成原始视频流
S2TLD丹麦包含合成数据和真实数据,做“合成→真实”域适应常用合成域有大量标注,真实域部分标注真实域视频可提炼未标注样本
BDD100K美国/其他大而全的自动驾驶数据集,交通灯只是其中一类有交通灯标注,但标注密度不高官方原始视频可自行抽帧,注意非商业许可

如果你只想要一个起点,我建议优先看Bosch和LISA。Bosch的未标注帧里都是典型的德国窄路口场景,LISA的视频里有很多美国大路口和夜晚红灯反光的情况,风格差异大,正好用来测试模型跨场景能力。

2.2 为什么很多标注数据集的“未标注帧”被低估

大多数视频型标注数据集,标注人员不是逐帧打框的。比如一段30秒的路口视频,可能每隔10帧才标一帧,或者只在信号灯状态改变的关键帧上打框。这意味着官方发布的数据包里面,天然就躺着大量“没有标签但画质正常”的视频帧。很多人在数据集页面只看到“有标注”三个字,就直接把这个来源忽略了。

我自己常用的一个做法是:下载官方原始视频序列,用它提供的标注JSON/XML反查被标注的帧ID,然后把没有被标注的帧全部导出来。这样得到的未标注数据和标注数据完全同源,画质、相机视角、路口类型都一致,做预训练或者伪标签非常合适。这就是很多人忽略掉的一块数据金矿。

2.3 关于版权与许可,下载前先搞清楚

先说结论:做学术实验和写论文基本没问题,但商用一定要谨慎。

这些数据集大部分是“仅供研究用途”的,具体条款每个页面都不同。有些要求你用学校或企业邮箱单独申请,有些允许直接下载但是禁止二次分发。你的模型如果只是内部验证,一般问题不大;如果要做成产品卖给客户,建议把许可条款发给法务过一遍。

顺带解释两个热词里常有人问的许可证含义。Apache License 2.0:允许商用、允许修改和再分发,保留版权声明即可,对专利有明确授权,是目前最友好的协议之一。GPL-2.0:允许商用和修改,但衍生作品必须以相同许可证开源,有“传染性”,如果你的项目是闭源产品,引用GPL代码要非常小心。至于“Apache 2.0/GPL-2.0的数据集”这种说法,要看它约束的是代码还是数据本身,很多数据集页面写的是“数据集使用CC BY-NC 4.0”这类知识共享协议,属于另一套体系,不能和软件许可证混为一谈。

3. 三条路径获取未标注交通灯数据

3.1 从现有标注数据集中剥离未标注帧

这是成本最低的方式。以DriveU这类带视频的数据集为例,标注文件里通常会写明每一帧的编号或者时间戳。你只需要写个小脚本,把标注过的帧从视频里挑出去,剩下的帧全部导出为图片。

关键代码思路大致是这样:

import cv2 import json # 假设标注文件里记录了所有被标注帧的 frame_id 列表 with open("annotations.json", "r") as f: annos = json.load(f) labeled_frames = {item["frame_id"] for item in annos["frames"]} video_path = "raw_video.mp4" save_dir = "unlabeled_frames/" cap = cv2.VideoCapture(video_path) fps = cap.get(cv2.CAP_PROP_FPS) frame_id = 0 while True: ret, frame = cap.read() if not ret: break if frame_id not in labeled_frames: # 每间隔3帧保存一次,避免连续冗余 if frame_id % 3 == 0: cv2.imwrite(f"{save_dir}/{frame_id:06d}.jpg", frame) frame_id += 1 cap.release()

实际操作中有两个细节。一是帧ID和时间戳对不上的问题,有的数据集标注里写的是视频时间(比如3.24秒),你抽样的时候要用frame_id = int(time * fps)换算,要注意四舍五入的误差。二是抽帧间隔,我建议先全量抽到内存里看一眼画面重复率,再决定要不要跳帧。城市道路视频在等红灯时前几十帧几乎一模一样,全部保留只会拖慢后续清洗速度。

3.2 行车记录仪自采:低成本扩场景

自己采数据看着原始,其实是最能补足公开数据集短板的方式。公开数据集主要集中在德国、美国、丹麦、法国这几个地方,国内的路口形态、信号灯位置、倒计时样式它们覆盖得很差。你如果最终要部署到国内项目,自采数据几乎是必经之路。

采集设备不一定要多贵,行车记录仪完全够用。我建议注意下面几点:

  • 安装角度:记录仪稍微往上仰一点,保证画面里能看到路口上方的信号灯杆,而不是只拍前车屁股。
  • 分辨率至少2K:因为交通灯在画面里占比太小,1080P拍出来后期裁切会很不舒服。
  • 路线规划:尽量覆盖十字路口、T型路口、带倒计时牌的路口、多车道宽路面、夜间街道路口。另外,最好把不同时段的数据分开存放,方便以后按场景评测。
  • 拍摄时长:不用一次拍一小时,每一段5到10分钟就够,关键是路口类型要多、光线条件要杂。
  • 隐私问题:公共道路拍摄要遵守当地规定。真正落地发布前,建议对清晰可见的车牌和人脸做模糊处理。这个可以用现成的检测模型自动处理,不用人工一个个盖马赛克。

3.3 官方原始数据/未标注子集

除了上面的数据集的标注包,有一部分数据集的官方页面还提供了“raw data”下载,这些原始视频里没有任何标签文件,专供做自监督和无监督研究的。

申请这类数据时,我建议直接发邮件给发布方的研究组,正文写清楚三件事:你是谁、用在什么项目上、是否需要商用授权。大多数情况下,学术用途的申请都能通过。注意有些页面下载之后要等人工审核,不要反复刷注册,耐心等就行。

4. 未标注数据的工程化处理:抽帧、清洗与存储

4.1 抽帧不能无脑均匀抽

拿到一段路口的视频,很多人第一反应是“每秒抽一帧”。这在车辆快速通过路口时没问题,但一旦遇到红灯停车队列,前车刹车灯亮着不动,连续几十帧画面几乎相同。把这些帧全部送进训练集,会造成严重的重复样本问题,模型会在重复的车尾和信号灯上过拟合。

我推荐一个做法:时间抽帧加运动量筛选。先用每3秒一帧的节奏粗抽一遍,然后计算相邻帧之间的像素差异。我用的是朴素但有效的方案,缩放到32x32的灰度图后计算平均绝对误差(MAE):

import cv2 import numpy as np def frame_diff(a, b): a_small = cv2.resize(cv2.cvtColor(a, cv2.COLOR_BGR2GRAY), (32, 32)) b_small = cv2.resize(cv2.cvtColor(b, cv2.COLOR_BGR2GRAY), (32, 32)) return np.mean(np.abs(a_small.astype(int) - b_small.astype(int))) # 如果相邻帧差异小于 2.0,就认为画面基本静止,跳过这一帧

这个阈值不一定对所有视频通用,我的经验是0.5到3.0之间都正常,你可以先看几组统计值再定。对于等红灯场景,差异通常会低于1.0;车辆正常通过路口时,差异值往往在5.0以上,所以阈值设2.0左右比较平衡。

4.2 清洗:把没用的帧挑出来丢掉

抽完帧之后,未标注数据集里会有明显的一批“垃圾帧”,不处理直接进训练流程就是浪费资源。

第一类是模糊帧。夜间或者车辆颠簸时,画面整体模糊,模型学不到任何有效特征。可以用拉普拉斯方差做检测:对灰度图做拉普拉斯变换,然后计算方差。方差很低说明图像边缘太少,也就是模糊。具体阈值和分辨率强相关,1280x720的图我一般以80到120为界,低于这个值就删掉。第二类是过暗/过曝帧。统计灰度直方图,如果纯黑像素占比超过30%,说明画面基本是夜里的死黑状态;如果纯白像素占比很高,说明是迎着太阳拍的车前盖反光。这两种帧对训练没有正面贡献。第三类是完全没有信号灯的帧。这个最消耗时间,我的做法是先用一个现成的交通灯检测模型把所有帧都过一遍,只保留检测到灯体、或者置信度处在模糊区域的帧,其他的直接丢进“无效样本目录”备用。

这块顺便说一下“数据质量”这件事。最近总有人讨论高质量数据集评测规范,我的理解是:对检测任务来说,所谓高质量不一定是标注有多精细,而是有效样本占比高、场景覆盖广、噪声类别少。未标注数据的清洗本质上就是在做第一层质量筛选。

4.3 目录组织和格式预留

清洗完之后,不要随手把图片扔进一个大文件夹,后面训练的时候会后悔。我习惯从一开始就按下面这种结构组织:

dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── raw/ │ └── unlabeled/ └── scripts/

未标注图片在还没有标签之前,先统一放在raw/unlabeled/下面。等伪标签生成完毕,再按YOLO格式移动到images/labels/对应的训练集目录。这样做的原因是,YOLO系列的训练流程默认是“图片目录 + 标签目录”配对扫描,如果图片和标签数量对不上,或者目录里混着没标签的图片,训练时会报错或者直接忽略。提前把目录结构规划好,后面转COCO、转VOC都会方便很多。

顺便提一句“BDD100K转YOLO”这类问题,其实所有带标注的数据集,最终都要落到统一的中间格式上。不要迷信某种格式本身,核心是维护一个“图片路径 + 类别 + 归一化坐标”的清单,格式只是这个清单的外皮。

5. 未标注数据怎么做进训练流程

5.1 自监督预训练路线

如果你完全没有任何现成的交通灯模型,那伪标签这条路暂时走不通。这时候可以先走自监督预训练。

思路很简单:用清洗好的几千张未标注交通灯图,做一轮对比学习或者掩码重建预训练,让骨干网络学会提取路口图像的特征。常见框架比如SimCLR、MAE、DINO,随便挑一个能跑通的就行。

不过我要提个醒:交通灯是小目标,全局自监督预训练时,模型很容易只关注到车辆和路面的主体特征,灯体实在太小了。我实测下来的改善办法是:先把图像里包含信号灯的区域裁成小块,用这些小块图像做自监督预训练,然后再把backbone权重拿回去用完整图像微调检测头。这样预训练阶段看到的就是灯体本身,而不是整张路口大图。

5.2 伪标签 + 半监督迭代:性价比最高的路线

这是我最推荐的一条路。条件是你手里已经有一个效果还过得去的交通灯检测模型,哪怕只是在公开数据集上训练的也没关系。整体流程是:

  1. 把未标注图片批量推理一遍,拿到所有框、类别和置信度。
  2. 按置信度把结果分成三档:高置信度(比如0.8以上)直接作为伪标签;中置信度(0.5~0.8)放进候选池,等人工抽检后决定要不要用;低置信度(0.5以下)直接丢弃。
  3. 把高质量的伪标签数据和已有的真标注数据混合,重新训练模型。
  4. 重复一轮,每轮之后模型对目标场景的理解都会更好。

用YOLOv8做这一步非常顺手,推理时直接保存txt标签:

from ultralytics import YOLO model = YOLO("traffic_light_baseline.pt") results = model.predict( source="dataset/raw/unlabeled/", imgsz=960, conf=0.5, save_txt=True, save_conf=True, project="pseudo_labels", )

跑完之后,pseudo_labels/labels/下每个图片都对应一个txt文件,里面是YOLO格式的类别、中心点、宽高、置信度。再用一个脚本把置信度低于0.8的标签删掉,剩下的就是可用的伪标签。

我踩过最大的坑是:伪标签里的类别分布会失衡。比如模型对绿灯检测得特别好,伪标签里就全是绿灯,黄灯几乎没有。如果你发现这种情况,要按类别做抽样,保证每类数量别差太远,否则训练完的模型会偏向于把其他灯也判成绿灯。另外,伪标签框的边缘通常不如人工标注干净,训练时建议在标签上加一点轻微抖动(比如坐标随机偏移1到2个像素),可以略微提升框回归的稳定性。

5.3 域适应与场景扩充

如果你的目标是把模型从公开数据集场景迁移到特定城市、特定硬件上,域适应路线也值得考虑。不展开讲对抗训练这些复杂公式,只说一个非常实用的变种:用目标场景的未标注数据做“自训练”。先用源域模型在目标域未标注视频上推理,筛选出高置信度的结果,然后把这些带伪标签的目标域数据和源域标注数据混合重新训练。这和5.2的流程很像,区别是这里更强调“目标域数据比例”的调节。我实测下来,目标域数据占比在30%到60%之间效果最好,太少没效果,太多会让模型逐渐忘记源域里见过的复杂情况。

6. 常见问题与避坑实录

6.1 抽出来的帧大量重复怎么办

表现是:训练集统计下来明明有5000张图,实际互相去重之后可能只有1500张的有效信息。重复不仅浪费算力,还会让验证指标看起来虚高。解决办法是上一章说的运动量筛选,再加上pHash感知哈希去重。对每张图计算一个64位哈希值,两两比较汉明距离小于5就视为近似重复,保留其中一张。这个步骤在几千张图上跑起来很快,值得加进流程里。

6.2 视频里根本没有信号灯的帧太多

如果采集路线经过很多没有信号灯的路段,粗筛阶段会发现一半以上的帧都检测不到灯。不用慌,先用现成模型过一遍,把完全没有检测框的帧直接挪走。注意这里别把“置信度低的帧”也一起删了,低置信度帧往往是你的模型在目标场景下漏检的候选难例,留着对后续迭代有帮助。

6.3 伪标签的置信度阈值到底设多少

我见过有人直接设0.9,结果拿到的伪标签数量太少;有人设0.3,结果错框一堆,训练之后模型反而变差了。建议分档处理而不是一刀切。我通常把高置信度设在0.8,中置信度在0.5~0.8,低置信度区间直接丢。高置信度伪标签也要按一定比例混入,不是越多越好,我一般控制在总标签量的30%以下。中置信度样本留着每轮抽检200到300张,人工快速确认一下,这样能让迭代更稳。

6.4 小目标漏检、误检严重怎么办

YOLOv8默认640输入对交通灯这种小目标很吃亏。我在自采数据上训练时会把输入分辨率提到960,推理时候再切图(tiling),也就是把大图切成几个有重叠的小块分别推理。切图重叠率至少20%,防止正好把一个信号灯切成两半。另外,评估指标一定要分小目标看:除了mAP@0.5和mAP@0.5:0.95,我习惯单独统计面积小于32x32像素的灯的AP,很多模型整体mAP看着不错,小目标AP其实很差,只有单独统计才能暴露问题。

6.5 开源许可证和数据集版权怎么避坑

这里再强调一遍:代码库的Apache 2.0/GPL-2.0许可证,和数据文件本身的许可协议是两回事。数据集的页面往往单独写了“reserved for non-commercial research use”“custom license”这类字样。哪怕是GPL代码配合的数据,数据本身也不自动变成GPL。做商用项目之前,把这些许可落到文档里存档,别等项目交付了再来补授权,那时候非常被动。

6.6 要不要把未标注数据全部重新人工标注

成本上不建议。真实场景里,交通灯类别少、目标特征集中,伪标签的可靠性比通用目标检测高不少。如果你一定要人工复核,我建议用主动学习的思路:只挑模型置信度中等、灯体过小、或者被遮挡严重的难例来标,这样同样的标注预算能把模型短板补得更准。

7. 一套可以直接抄的落地节奏(伪标签+YOLOv8为例)

最后给你一套我最近跑过的完整节奏,适合手里已经有几百张标注数据、想快速扩充场景的情况。

第一步,收集未标注数据。从公开数据集剥离未标注帧,或者用车载记录仪拍原始视频,目标先定在5000到10000张有效画面上。

第二步,抽帧清洗去重。按3.1和4.1的方法处理,筛掉模糊、过暗、重复帧,最后大概还剩3000到5000张“值得进训练流程”的图。

第三步,生成伪标签。用已经训练好的交通灯模型推理,保存YOLO格式标签。命令我在5.2给过了,唯一要注意的是输入分辨率设到960,别用小分辨率跑。

第四步,双阈值过滤和抽检。高置信度0.8以上直接保留,中置信度0.5到0.8先保留清单。随机抽200张伪标签可视化出来人工看一眼,重点看有没有把红灯误检成车辆尾灯、把倒计时LED误检成信号灯的情况。

第五步,混合训练。原始标注数据作为基础,伪标签数据按30%左右比例混入,YOLOv8训练时图片尺寸设960,训练轮次150左右,早停和学习率参数可以按默认来。

第六步,按场景细分评估。在验证集上分别统计白天、夜晚、逆光、远距离四类场景的AP,看伪标签到底提升了哪个部分。我自己跑下来,假标签带来的提升主要来自“环境多样性”,而不是简单的数据量增加。夜间AP如果还是上不去,大概率是伪标签里夜景样本本身太黑、标注质量差,这时候别继续加数据,先去想办法补亮一点的夜间样本。

最后分享一个经验:整个流程跑第一轮的时候,别急着加更多数据,先把这一轮数据清洗、伪标签过滤、训练和评估闭环走通。等你看到“加了未标注数据之后小目标AP确实有提升”,再扩大规模也不迟。交通灯检测的数据工程,本质上是一个反复迭代收敛的过程,先小后大、先稳后扩,是省时间的关键。

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

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

嵌入式C语言数据类型扩展:从stdint.h到volatile的确定性编程

很多从 PC 端 C 语言开发转嵌入式的人,都会在某个时刻遇到一种诡异的情况:代码在电脑上编译运行一点问题没有,放到单片机工程里就各种错乱。排查到最后,往往发现罪魁祸首不是逻辑,而是int类型。C 语言标准对int只给了一…

作者头像 李华
网站建设 2026/9/6 13:25:23

牛客五模编程题详解:校招笔试算法备战与刷题策略

2019年牛客第五次模拟考试的编程题集合,我到现在还有印象。那时候秋招刚进入白热化,身边同学人手一个牛客账号,每周模考雷打不动。五模这个场次比较特殊,它不像前几模那样偏重单一考点,而是把字符串处理、排序、动态规…

作者头像 李华
网站建设 2026/9/3 15:35:23

30张图,搞懂分布式追踪系统!

在微服务架构中,一次请求往往涉及到多个模块,多个中间件,多台机器的相互协作才能完成。这一系列调用请求中,有些是串行的,有些是并行的,那么如何确定这个请求背后调用了哪些应用,哪些模块&#…

作者头像 李华
网站建设 2026/9/4 1:17:11

分布式锁的各种实现,看完这篇你就懂了!

今天我们讲讲分布式锁,网上相关的内容有很多,但是比较分散,我自己重新学习总结,共 4 种实现方式,分享给大家。文章内容比较多,预计阅读 22 分钟,建议大家先收藏。不 BB,上文章目录&a…

作者头像 李华
网站建设 2026/9/5 10:33:17

无人机感知技术落地地面机器人:从VIO到代价地图的迁移

晚上八点回到家,发现扫地机器人又卡在床底一根电源线旁边,电机嗡嗡响,轮子空转。你很难不把它和大疆无人机做对比——无人机能在树林里高速穿行,灵活避开树枝,为什么换个场景就“笨”成这样?答案不在电机&a…

作者头像 李华