仪表盘警告灯识别数据集生产流程:COCO格式构建与实战复盘
2026/8/31 10:34:21 网站建设 项目流程

简介:本资源是一套面向智能座舱、车载HMI与自动驾驶感知算法研发者的高质量汽车仪表盘标志识别数据集,聚焦ABS、安全气囊、发动机冷却系统等20余类关键告警与状态标识,解决仪表盘小目标密集、光照多变、视角受限下的细粒度识别难题,适用于模型训练、算法验证及车载UI交互研究。压缩包共2000个文件,含1997张高分辨率JPG图像(涵盖实车拍摄、3D渲染及多品牌车型仪表特写)与3个标准COCO格式JSON标注文件(含类别定义、图像元信息及逐框实例分割级标注),整体体积706.44MB,结构简洁,开箱即用。目前已有622人学习下载,资源可直接用于YOLOv8/RT-DETR等主流检测框架的微调训练,附带完整类别映射表与标注统计说明,显著降低数据清洗与格式转换成本。 去年做商用车仪表疲劳监测项目时,被一个看起来很小的问题卡了很久:市面上根本找不到一个像样的仪表盘警告灯识别数据集。自动驾驶赛道那些公开数据集,要么是街景级别的车、人、交通标志,要么是环视视角的语义分割数据,切进驾驶舱内部、对着仪表盘拍的高清数据几乎没有。ABS灯、安全气囊灯、发动机冷却系统灯这些符号,在整张仪表图片里往往只有几十个像素,通用目标检测模型直接拿过来跑,小目标漏检率相当难看。最后只能自己动手从零搭一个数据集。这篇就把21045张图片、COCO JSON格式标记的汽车仪表盘标志识别数据集的完整生产流程复盘一遍,包含数据来源、标注规则、COCO格式转换和训练前检查,希望能帮到同样被这个领域数据问题卡住的人。

1. 为什么这个数据集值得单独做

1.1 先回答一个问题:识别仪表盘警告灯到底有什么用

不是所有人第一眼都能看出这个数据集的商业价值。很多人觉得,仪表盘警告灯不就是车内的指示灯吗,车都开得快报废了才亮,识别它有什么意义?

真实场景里用处其实不小。第一个是智能座舱的驾驶员监控。车辆行驶途中,仪表盘突然点亮一个警告灯,驾驶员不一定能第一时间察觉,尤其是夜间或者高速上注意力全在路面上。这时候如果有一个摄像头持续读取仪表盘区域,模型检测出警告灯的位置和类别,系统就可以主动语音提醒:"ABS系统警示灯亮起,请注意检查。"这个功能对于商用车车队尤其刚需,司机在驾驶过程中根本没时间低头盯仪表。

第二个是二手车检测。评估师上车通电,用手机拍一张仪表盘照片,后台模型直接输出当前有哪些故障灯点亮。这个场景对检测速度和精度要求都不低,因为通电自检的窗口期往往只有几秒钟,警告灯全亮的那一瞬间如果没抓住,很多故障灯就熄了。

第三个是维修诊断辅助。在无法读取OBD数据或者OBD接口被改装屏蔽的情况下,视觉方案可以作为一套兜底手段,直接看仪表盘来确认故障状态。这套思路在不少汽车维修连锁店已经在试用了。

第四个是车队管理。司机在出车前拍一张仪表盘照片,系统自动判断是否有异常点亮的警告灯,有的话不让出车。本质上这是把"人眼检查"变成"机器检查",降低漏检率。

这些场景有一个共同的视觉特征:要识别的是仪表盘上的小符号,而不是整张图里的大目标。模型要能快速定位警告灯图标,并判断它属于哪一类。这和车辆外观检测、行人检测完全是两个路子,需要专门的数据来驱动。

1.2 为什么公开数据集解决不了

COCO、VOC、OpenImages这些公开数据集,类别里根本没有仪表盘警告灯。它们能告诉你哪里有车、有人、有猫,但没法告诉你仪表盘上那个黄色小壶是机油压力警示,还是发动机冷却液警示。

更重要的是,警告灯这种目标属于典型的极端小目标。很多图标在1080p图片里只有20×20到60×60像素,占整图面积不到0.3%。通用检测模型如果在COCO这种以中型、大型目标为主的数据上训练,直接迁移过来针对小目标的表现普遍一般,往往需要领域数据进行微调,甚至从头训练一部分层。

不同品牌、不同年份的车辆,同一个警告灯的图标设计、颜色、位置差异很大。比如发动机冷却系统警示灯,有的车是温度计加水波,有的车是温度计加感叹号;有的车型放在转速表内侧,有的在转速表下方。公开数据集根本没有覆盖这种多样性的能力,必须构建自己的领域数据集。

1.3 21045张的定位

21045张图片在自动驾驶数据集里不算大,但在仪表盘内部视觉这个细分领域已经属于可用的规模。配上COCO JSON这种标准格式,拿到手后不管是接mmdetection、detectron2,还是ultralytics YOLOv8,都能直接消费,不需要额外做格式适配。

这个数据集和通用检测数据集最大的区别在于:它的标注格式规范、类别结构清晰、覆盖了ABS、安全气囊、发动机冷却系统这些核心警告灯。对于任何一个要做车载视觉、智能座舱或者汽车后市场服务的团队来说,这套数据可以直接作为预训练基础,也可以作为模型微调的领域补充。

2. 图像采集与筛选:21045张是怎么攒出来的

2.1 数据来源方向

仪表盘图片这种数据,指望一个单一渠道凑齐两万张根本不现实,需要多个来源配合。

实车采集是质量最高的来源。把车辆停在不同光照环境下,通电但不启动发动机,仪表盘自检时一堆警告灯会同时点亮,这是收集警告灯标注的黄金时间。正常行驶状态下,大部分警告灯是熄灭的,能拍到的只有转速、车速、油量这些常规信息,警告灯样本非常少。所以自检阶段那几秒钟,反而是数据价值最高的窗口。

维修厂和检测站合作采集是另一个主要渠道。车辆上检测线或者进维修工位时,通电自检阶段是天然的采集窗口。这个来源的量很大,但需要注意对车牌、人脸、车辆VIN码做脱敏处理,避免隐私问题。

视频截帧也贡献了一部分。从行车记录仪、测试车辆的车载录制设备里,截取仪表盘出现的片段,按一定间隔抽帧。这个来源数据量大,但相邻帧相似度极高,必须做去重,不然下游训练直接过拟合。

公开网络图片和视频素材占比最小。公开图片的版权和质量参差不齐,只能作为覆盖车型多样性的补充,不能当主力。这里提醒一下:公开渠道获取的图片需要确认授权或使用明确许可的素材,商业项目尤其要注意版权风险,否则后期很麻烦。

2.2 初筛流程

采集回来的原始图片大概有十几万张,最后只剩21045张,中间经过了好几轮筛选。

第一关是分辨率过滤。仪表盘上警告灯很小,如果原始图片分辨率过低,比如低于800×600,即使人眼能认出警告灯,模型也很难学到有效特征。这批数据统一要求短边不低于720像素,小于这个阈值的直接丢弃。

第二关是清晰度过滤。用Laplacian梯度方差计算清晰度,模糊的截帧直接删。仪表在车辆行驶中会抖动,很多视频帧是虚的,这类数据如果标注进去,既费人工又坑模型。

第三关是相似度去重。相邻视频帧的相似度极高,如果全留下,模型会把大量参数用在记忆重复帧上,导致过拟合。用感知哈希计算图片间的汉明距离,相似度高于阈值的只保留一张。这一步做完,数据量基本能砍掉一半以上。

第四关是光照场景均衡。仪表盘图片最怕的是夜间高亮和逆光过曝。按拍摄时间段和亮度直方图把图片分桶:白天、夜间、隧道地下车库、逆光,保证每个桶都有一定比例,不放任某一种环境占据绝对多数。

第五关是车型覆盖检查。按品牌、车系、仪表盘代际做分类统计,如果某个品牌占比过高,下一批次采集时会有意补充其他车型。这一步直接影响模型的泛化能力。

2.3 数据和标注的构成

整理后的21045张图片,大致可以按下面这个结构来组织,具体比例可以根据项目微调。

维度分布情况
光照场景白天约60%,夜间约25%,隧道地库约10%,逆光约5%
警告灯状态至少一个警告灯点亮约70%,点火自检全亮约20%,全灭约10%
图像分辨率1280×720以上约85%,其余为720p至1080p
标注目标数单张平均约3到8个警告灯框

为什么保留约10%的"全灭"图片?因为在真实场景里,仪表盘大部分时间没有任何警告灯点亮。如果训练集全是点亮状态,模型会倾向于对任何区域输出一个框,误报率会很高。在检测任务里,负样本和正样本一样重要,这点常被低估。

3. 逐字段拆解COCO JSON:categories、images、annotations一个都不能错

3.1 为什么选COCO格式

选择COCO JSON而不是YOLO TXT、VOC XML,核心原因有三点。

生态兼容。mmdetection、detectron2、PaddleDetection、ultralytics都提供COCO格式的数据加载器。拿到COCO格式,等于拿到了通行证,不需要为每个框架单独写数据适配。

字段承载能力强。COCO不仅有bbox,还有segmentation、area、iscrowd。当前做目标检测用不到分割,但以后如果要做实例分割,可以在现有标注基础上直接扩展,不需要重新标一遍。

社区工具链完整。COCO API,也就是pycocotools,从数据可视化、指标评估到结果汇总都有现成实现。后续模型mAP评估直接套用COCO指标,省去自己写评估脚本的时间。

3.2 categories设计

categories是类别表,也是模型输出的语义空间。类别id从1开始,一旦发布不要随意改序,否则已训练的模型权重和类别对应关系就会错乱。

对于仪表盘警告标志,核心类别可以这样设计:

category_idnamesupercategory
1absdashboard_warning
2airbagdashboard_warning
3coolantdashboard_warning
4oil_pressuredashboard_warning
5battery_chargedashboard_warning
6brake_systemdashboard_warning
7tire_pressuredashboard_warning
8low_fueldashboard_warning
9power_steeringdashboard_warning
10seatbeltdashboard_warning

标题里提到的ABS、安全气囊、发动机冷却系统属于前三个核心类,其他常见警告灯按同样的命名规则补充。建议类名全部用小写加下划线,不要用中文,避免在部分框架里出现编码问题。

category_id必须从1开始,而不是0。COCO官方约定0是背景类,很多检测框架在计算损失时直接把0当背景处理。如果从0开始,第一个类别的梯度计算会全部出错,损失一路飙到NaN都有可能。

3.3 images字段

每个image对象包含以下基本字段:

{ "id": 1, "file_name": "train/000001.jpg", "width": 1920, "height": 1080 }

这几项看起来简单,但坑不少。id必须是全数据集唯一的整数,框架内部会用它来关联标注;file_name建议统一为相对路径,并把图片按train/val/test分文件夹存放;width和height必须和实际图片像素完全一致,不能拿缩略图的信息来对原图。如果width和height填反,模型训练时会把标注框映射到错误位置,mAP低得离谱,而且很难排查。

3.4 annotations字段

annotation是数据结构里最核心的部分:

{ "id": 1, "image_id": 1, "category_id": 1, "bbox": [1250, 312, 28, 32], "area": 896, "segmentation": [], "iscrowd": 0 }

各字段含义如下:

id是标注框的唯一编号,全数据集递增,不能重复。

image_id是标注框对应哪张图片,必须对应images里的id。

category_id是类别id,必须对应categories里的id。

bbox是四个值,依次是左上角x、左上角y、宽度w、高度h,单位是像素,必须是绝对坐标,不是归一化坐标。这是最容易出错的地方,后文会专门展开。

area是标注框面积,检测任务里直接用w*h计算就行。COCO评估脚本会根据area自动区分小目标、中目标和大目标,所以建议填对,虽然它不是必填项。

segmentation是目标分割轮廓。只做检测可以不填,传空数组即可。如果后续要做实例分割,需要保存多边形坐标,建议在标注工具里就允许多边形标注,而不是只画矩形。

iscrowd是是否为群体目标。仪表盘警告灯不存在多个目标粘连成一团的情况,全部置0即可。

3.5 JSON文件的整体组织

整个COCO文件是一个大对象,顶层包含info、licenses、categories、images、annotations五个key。

我见过不少新手把images和annotations塞成一个大list后没有去重,或者id重复,最终模型训练时加载不出数据。最稳妥的构造方式是用dict保存images,用image_id做key,最后再转成list,从源头避免重复。

生成的JSON文件建议使用UTF-8编码,写入时不要用默认的ASCII。Windows环境下如果直接json.dump到文件,中文路径会被转成\uXXXX,虽然不是致命问题,但排查起来很痛苦。我自己写转换脚本时,unified到JSON的输出固定会加ensure_ascii=False。

4. 标注规则的制定:小目标、相似符号与质量边界

4.1 标注对象:点亮还是可见

这是做仪表盘标志数据集最核心的一个决策。有两个方向:一是只标"点亮状态"的警告灯,模型的输出直接对应"当前有故障";二是标注"所有可见的警告灯图标",不管是否点亮,后续再做亮灭分类。

如果落地场景需要同时定位图标并判断是否有异常,建议采用第二种策略:标注所有清晰可见、能识别类别的警告灯图标。这样模型可以先用检测框定位出仪表盘上有哪些警告灯,再通过后续分类判断灯是否点亮。如果只标注点亮状态的灯,那么同一种警告灯在未点亮时完全不参与训练,检测器很难学会"这个位置有一个ABS图标,只是没亮"的语义。

当然,纯检测需求也可以走第一种路线,只输出点亮的警告灯位置。两种路线没有绝对的对错,取决于最终产品的逻辑。但不管选哪种,必须在标注规范里写死,不能让标注员自己临场决定。

4.2 边界框怎么画

规则很简单:框住符号主体本身,不包括外圈的发光光晕,也不包括符号下方的"ABS"文字说明。

很多仪表盘警告灯图标旁边会带文字缩写,比如一个黄色小壶底下写着"ABS"。标注时只框图形标志,文字不属于检测目标。如果图形标志和文字距离太近,甚至有遮挡,那也以图形的外接矩形为准,不去扩展框体。

对于由多个元素组合而成的警告灯,比如"温度计+波浪线"这种发动机冷却系统标志,就按一个整体框处理,类别为coolant。不要拆分成多个小框,否则训练数据里的实例数量虚增,但语义却是碎的,后续调试非常别扭。

4.3 相似符号的区分

仪表盘警告灯里,很多类别的视觉特征高度接近,标注员不熟悉车型很难分清楚。以下三组是最容易出问题的:

机油压力警示灯,机油壶加油滴,和发动机冷却液警示灯,温度计加波浪线,在低分辨率下容易混淆,两者的颜色都是黄红系。区分的关键在于壶嘴和温度计的刻度线。

制动系统警示灯,红色圆形加感叹号,和电池充电警示灯,红色方形加正负号,形状接近。颜色和内部符号有差异,但标注员如果对车不熟,很容易随手标成"感叹号"。

胎压监测警示灯,黄色马蹄形加感叹号,中间有横线波纹,经常被标成普通感叹号类别。这类符号在部分车型上看起来特别像"报警"通用图标,不结合车型经验很难判断。

解决方案是给标注员提供一份带示例图的标准说明文档,每个类别放3到5个不同车型的示例图,明确标注哪些情况归属哪一类;遇到分不清的,要求单独标记为"待确认",由车型知识更丰富的复核员处理。这样能显著降低初标阶段的误标率。

4.4 小目标的标注下限

仪表盘警告灯在1080p图像里可能只有十几二十像素宽。标注框太小的时候,人工很难画准。

我设置的规则是:框宽度或高度小于6个像素的实例不标注。低于这个尺寸,模型能学到的特征极其有限,反而容易在训练时引入噪声。对于20像素以上的目标,要求标注框边缘和图标边缘的贴合误差维持在2像素以内。

这个"6像素"不是拍脑袋定的。我之前做过对比实验,把5到6像素的目标和10像素以上的目标放在一起训练,模型对小目标的召回率几乎没有提升,反而是误检增加。所以不如把标注精力集中在有效目标上。

4.5 质量控制流程

数据集的整体质量,不取决于某一个人的认真程度,而取决于流程设计。我采用两轮标注加一轮审核。

第一轮是初标。标注员按规则完成所有图片。第二轮是交叉校对。另一位标注员随机抽取30%的图片,独立重新标注一遍,对比两次结果的类别一致率和框IoU,IoU低于0.7的重新回初标流程。第三轮是审核。由熟悉车型的复核员全量检查标注结果中的类别标记,尤其是相似类别的标注。

这套流程的成本不低,但换来的结果是两万多张图里,标注框的边界可信度很高。如果去掉这个流程,模型训练时会把标注员的误标也当作ground truth学进去,后期排错非常困难。有时候准确率上不去,问题根本不在模型,而在数据里的噪声。

5. 格式转换实战:从标注工具导出到标准COCO JSON

5.1 标注工具选型

不同工具的导出格式差异很大,选型直接影响转换工作量。下面是我实际对比过的几个选项:

工具原始格式转COCO难度是否推荐
LabelMeJSON,归一化坐标中等,需要还原像素坐标推荐,灵活且免费
CVAT内置COCO导出低,直接导出数据量大时推荐
labelImgVOC XML中等,需VOC转COCO小项目还行
Roboflow云端多格式有付费限制

我自己用的是LabelMe加自写转换脚本。LabelMe的JSON结构简单,出问题好排查;而且它支持多边形标注,后续扩展实例分割不用重新标。CVAT虽然能直接导出COCO,但如果是本地部署,配置成本略高;云端版本用起来顺手,但涉及数据出域的问题,一些企业里会卡合规。

5.2 LabelMe到COCO的转换逻辑

LabelMe的每个标注文件长这样:

{ "imagePath": "000001.jpg", "imageWidth": 1920, "imageHeight": 1080, "shapes": [ { "label": "abs", "shape_type": "rectangle", "points": [[0.65, 0.29], [0.69, 0.32]] } ] }

这里的points是归一化坐标,四个值都在0到1之间。转换到COCO时要做两件事:把坐标还原成像素坐标,再把(x1, y1, x2, y2)转成COCO的(x1, y1, w, h)。

下面是一个精简版转换脚本,核心逻辑可以直接抄:

import json import os from glob import glob coco = { "info": {"description": "dashboard warning light dataset"}, "licenses": [], "categories": [], "images": [], "annotations": [], } cat_name_to_id = {"abs": 1, "airbag": 2, "coolant": 3} coco["categories"] = [ {"id": 1, "name": "abs", "supercategory": "dashboard_warning"}, {"id": 2, "name": "airbag", "supercategory": "dashboard_warning"}, {"id": 3, "name": "coolant", "supercategory": "dashboard_warning"}, ] image_id = 0 ann_id = 0 for labelme_file in glob("labelme_output/*.json"): with open(labelme_file, "r", encoding="utf-8") as f: data = json.load(f) img_w = data["imageWidth"] img_h = data["imageHeight"] image_id += 1 coco["images"].append({ "id": image_id, "file_name": os.path.basename(labelme_file).replace(".json", ".jpg"), "width": img_w, "height": img_h, }) for shape in data["shapes"]: label = shape["label"] if label not in cat_name_to_id: continue pts = shape["points"] x1 = pts[0][0] * img_w y1 = pts[0][1] * img_h x2 = pts[1][0] * img_w y2 = pts[1][1] * img_h x, y = min(x1, x2), min(y1, y2) w, h = abs(x2 - x1), abs(y2 - y1) if w < 1 or h < 1: continue ann_id += 1 coco["annotations"].append({ "id": ann_id, "image_id": image_id, "category_id": cat_name_to_id[label], "bbox": [round(x, 2), round(y, 2), round(w, 2), round(h, 2)], "area": round(w * h, 2), "segmentation": [], "iscrowd": 0, }) with open("coco_annotations.json", "w", encoding="utf-8") as f: json.dump(coco, f, ensure_ascii=False, indent=2)

这段脚本只覆盖了最简单的rectangle类型。如果标注时用了polygon,需要把polygon点集的归一化坐标转成像素坐标,并生成segmentation字段。更完整的转换逻辑可以参考pycococreatortools里的函数,核心思想一致。

5.3 坐标验证不能省

转换完以后

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询