去年帮朋友调试一个路侧卡口的车辆抓拍系统,车辆识别、车牌识别都跑得挺顺,唯独安全带检测这一项,换了三四个公开数据集,到了现场仍然频繁漏检、误检。后来把失败样本逐一拉出来分析,发现根子问题根本不在模型结构,而在数据集和真实抓拍场景之间差了好几条街。今天想聊的这8400张YOLO智慧交通安全带检测数据集,就是当时针对这类真实场景重新整理、筛选、标注过的一套东西,专门给YOLO系列模型用,做智慧交通、卡口执法、驾驶员状态分析这类项目时可以直接拿来训练。
安全带检测这件事,看起来只是"图像里找一根带子",真正落到工程上却和想象中完全不一样——目标太小、角度太刁、光照太乱、误检太多。很多刚入门的朋友拿着通用目标检测数据集训练完,mAP看着不错,一上真实抓拍图就露馅。这篇文章不做那种浮于表面的数据集介绍,而是把这个数据集从问题定义、数据构成、标注格式、YOLO训练配置、实测效果,一直到落地部署的坑,完整串一遍,适合正在做智慧交通视觉项目、准备自己训练安全带检测模型的算法工程师和独立开发者参考。
1. 安全带检测为什么是智慧交通里的"硬骨头"
1.1 卡口抓拍场景的真实痛点
先还原一下真实场景。路侧卡口相机抓回来的图,通常是整条车道、整辆车的画面,分辨率普遍在1080P到4K之间,但驾驶员安全带区域在画面里占据的像素非常少。安全带宽约3到5厘米,在距相机十几米远的成像平面上,可能只有三四十个像素宽,斜挎在驾驶员胸前,跟背景里的车窗边框、衣物褶皱、方向盘轮廓混在一起。这不是"找个大目标"的任务,更接近在复杂纹理背景里找一条细长条状结构。
另一个痛点是定义本身。交管执法关心的是"驾驶员有没有系安全带",可模型看到的是图像特征。安全带系上时,是一条从肩部斜向腰部的连续条带;没系时,这个区域是空的,或者只有横跨身体的衣服纹理。如果只用二分类的"系/未系"打标签,模型很容易学到背景纹理而不是安全带本身。这就是为什么这套数据集在标注上花了很大功夫:不只要告诉模型"这个人安全带是否系了",还要把未系安全带的人体区域也框出来,让模型有明确的负样本去对比。
1.2 数据集要覆盖哪些"肉眼简单、模型翻车"的难点
公开数据集里常见的图片,大多是正对车头、光线充足、安全带清晰可见的情况,用这些训练出来的模型,一到现场就露怯。整理这8400张图时,主要补的就是以下几类模型容易翻车的样本:
- 远距离小目标:车在远端车道,安全带区域只有几十像素,考验模型在小尺度下的特征提取能力。
- 逆光与车窗反光:前挡风玻璃上的反光会直接把安全带区域"淹没"在亮斑里。
- 夜间与隧道:低照度下车内细节严重丢失,安全带和座椅、衣物的对比度极低。
- 深色衣物与黑色安全带:黑安全带配黑衣服,视觉上几乎隐形,只能靠几何位置和边缘线索判断。
- 遮挡与姿态变化:方向盘遮挡部分胸部、驾驶员身体前倾、副驾驶坐姿偏低,安全带的走向和常规位置完全不同。
这些样本在通用数据集里占比很小,而真实道路上恰恰是这些场景最容易出问题。当初按这个思路筛选完,光是淘汰的质量不过关的图像就有两千多张,最后留下的8400张,每张都是能真正给训练"喂"出泛化能力的。
2. 8400张YOLO数据集的构成与标注逻辑
2.1 图像来源与场景分布
这套数据集共8400张图像,按场景维度做了分层整理。图像主要来自三类真实道路环境:城市平交路口、高速收费站匝道、普通国省道卡口,时间覆盖白天、傍晚、夜间三个时段,天气覆盖晴天、阴天、雨天。分布的大致比例是这样的:
| 场景维度 | 类别 | 占比 |
|---|---|---|
| 光线条件 | 白天顺光 | 约40% |
| 光线条件 | 傍晚/逆光 | 约25% |
| 光线条件 | 夜间/低照度 | 约20% |
| 光线条件 | 雨天/车窗有雨滴 | 约15% |
| 目标尺度 | 近车道(安全带像素宽度>80px) | 约35% |
| 目标尺度 | 中车道(安全带像素宽度40-80px) | 约40% |
| 目标尺度 | 远车道(安全带像素宽度<40px) | 约25% |
为什么在尺度上单独分层?因为YOLO这类单阶段检测器对尺度非常敏感。训练集里如果大部分是近处大目标,模型会倾向于学大目标的纹理特征,在远车道小目标上召回率暴跌。把各尺度的比例控制在合理范围,比追求总数更重要。
2.2 类别定义与标注规则
这套数据集采用YOLO格式的txt标注文件,每张图像对应一个同名txt,每行代表一个目标框,格式为:
class_id x_center y_center width height坐标均为归一化到0到1的值,直接能被YOLOv5、YOLOv8、YOLOv11等系列模型读取。类别定义上,建议按以下两类设置:
- class 0:安全带(带子系上的正样本区域)
- class 1:未系安全带(该系但没系的负样本区域)
这个设计思路很多人一开始不理解——为什么不直接标注"人"和"安全带状态"?原因在于,真正部署时你通常只关心"有没有违法",也就是未系安全带的实例。模型把class 0和class 1都检测出来之后,在后处理里可以只保留class 1的框作为违法证据,也可以同时输出两种框让执法人员人工复核。相比之下,如果只标注一类,模型在"有安全带"和"没有安全带"之间的决策边界会非常不稳定,误检率会显著上升。
标注框的位置也有讲究。安全带的完整区域是一个倾斜的带状区域,如果用水平矩形框去框整条安全带,会引入大量背景像素,尤其是斜挎角度大时,矩形框里一半都是衣物和背景。实践中最稳的标法是:把矩形框紧贴安全带可见段,框住从肩部到腰部的连续带体,宁可框得稍微贴合一些,也不要为了"省标注工作量"框一大片。对未系安全带的情况,则框住应该出现安全带的那条斜向区域——通常是驾驶员左肩到右腰的连线区域——这样模型学到的就是"这里应该有一条带子,但空空如也"的结构性差异。
2.3 数据量与有效标注实例数
8400张图像听起来不少,但要拆开看有效标注实例。统计下来,这套数据集里共包含约12000个标注框,其中class 0(安全带)约7800个,class 1(未系安全带)约4200个。单独看数量,未系安全带的样本偏少,这是因为真实道路上绝大多数驾驶员都守法系了带,未系样本本身就稀缺。训练时如果不做任何处理,模型会天然偏向多数类,对未系安全带的召回率会很难看。
解决方案有两条路,实操中都验证过有效。一是做类别重加权,把class 1的loss权重提高到class 0的1.5到2倍,让模型在训练时更关注少数类;二是对class 1做离线增强,比如把已有的未系安全带样本做水平翻转、小角度旋转、亮度抖动,扩到5000张以上再丢进训练。数据集本身没有做增强,原始图片保持原样,把增强空间留给使用者,这样更灵活。
3. 用YOLO训练安全带检测模型的关键配置
3.1 模型选型:为什么优先考虑YOLOv8s和YOLO11s
拿到数据集后,第一个问题就是选哪个模型。YOLOv5、YOLOv8、YOLO11系列都能跑,但针对安全带检测这个任务,最优先推荐的是YOLOv8s或YOLO11s这种小型号,而不是追求大模型。原因有三点:
一是部署环境。安全带检测通常跑在路侧边缘计算盒子上,这些设备的算力是有限的,用nano或small级别的模型才能在保证实时性的同时留出余量做其他检测任务。实测在一块约10 TOPS算力的盒子上面,YOLOv8s的FP16推理时间大约在15到25毫秒每帧,完全能撑住25帧以上的视频流处理。
二是任务本身不算复杂。安全带检测就只有两个类别,目标虽然小,但结构特征相对固定,不需要特别深的网络来建模复杂语义。small级别模型的参数量在11M左右,已经能够充分拟合这套数据集的规律,强行上large版本只会增加过拟合风险,还拖慢训练速度。
三是后续迭代需求。智慧交通项目里模型通常要频繁更新——新卡口、新车型、新角度都会触发补充标注和重训。小型号一轮训练在单张消费级显卡上只需要一到两小时,迭代节奏会舒服很多。
3.2 训练参数推荐与loss压测
以下是个人实测中比较稳的一套参数配置,可以直接作为起点:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 输入尺寸 img_size | 640x640 | 平衡小目标细节与显存占用 |
| 批量大小 batch | 16(24G显存)/ 8(12G显存) | 根据显卡调整 |
| 初始学习率 lr0 | 0.01 | 用预训练权重时不宜过大 |
| 训练轮数 epochs | 100-150 | 安全带模型100轮左右基本收敛 |
| 优化器 | SGD(动量0.937) | 比Adam在小数据集上稳 |
| 类别loss权重 | class 1设为class 0的1.5倍 | 缓解未系样本不足 |
| 数据增强 | mosaic=1.0, mixup=0.1 | mosaic增强对小目标有效,mixup轻开 |
| 预热 warmup | 3轮 | 避免初期loss震荡 |
有一个点必须提醒:安全带检测里mosaic增强虽然有用,但不要开得太激进。mosaic会把四张图拼接再缩放,这个过程中小目标的安全带区域很容易被压到几个像素甚至消失,导致模型学到一堆空白。实测中mosaic概率保持默认1.0问题不大,但如果训练完发现小目标召回率异常低,可以试试把mosaic关掉或把概率降到0.5,通常会有惊喜。
损失函数方面,YOLOv8默认使用CIoU作为边界框损失,配合DFL(Distribution Focal Loss)处理框回归的不确定性。安全带检测的一个常见现象是:框的类别置信度很高,但预测框和真实框的IoU不高——尤其远距离小目标上,框偏了几个像素就会导致IoU骤降。如果你用mAP@0.5作为指标,这个问题会被掩盖,一旦用mAP@0.5:0.95评估就原形毕露。建议训练结束后固定用mAP@0.5:0.95来对比模型版本,这个指标对小目标的定位精度更敏感,也更贴近真实部署需求。
3.3 预训练权重的重要性
强烈建议不要从随机初始化开始训练。安全带检测跟通用目标检测共享大量底层特征——边缘、纹理、形状、颜色——这些知识在COCO预训练权重里都已经学到了。直接加载YOLOv8s的COCO预训练权重,把最后一层类别数改成2,再做迁移训练,通常100轮就能收敛到不错的效果。如果用随机初始化,同样的数据量可能要200轮以上,而且最终精度往往更低。
另一个技巧是冻结骨干网络的前几层。刚换数据集时,前几十轮可以设置freeze=10,让backbone的底层特征先不动,只更新检测头和neck部分。等loss不再明显下降,再解冻全部层做微调。这样做的好处是防止预训练特征在前几轮被新数据集"冲掉",尤其是安全带这种目标比较小的任务,底层边缘特征越稳定,对最终精度越有利。
4. 实测指标与易错点分析
4.1 mAP、Precision、Recall到底该盯哪个
训练完第一时间看指标,但不能只看一个数。安全带检测项目的核心诉求是执法场景的"不漏判",因此优先级通常是:召回率 > 精确率 > mAP。也就是说,如果模型把没有系安全带的司机漏掉了,那是一次执法失误;如果模型把系了安全带的司机误判为未系,那最多是增加人工复核的负担。
基于这套数据集训练YOLOv8s(640输入、100轮、预训练权重)的实测结果大致如下:
| 指标 | 数值 |
|---|---|
| mAP@0.5 | 0.92-0.94 |
| mAP@0.5:0.95 | 0.71-0.74 |
| Precision(class 1 @ conf 0.25) | 0.88-0.91 |
| Recall(class 1 @ conf 0.25) | 0.90-0.93 |
| 未系安全带小目标(<40px)Recall | 0.78-0.83 |
注意最后一行,小目标的召回率明显比整体低一截,这是安全带检测里最正常的现象。如果你发现自己的模型在远距离目标上召回率低于0.7,优先怀疑训练集的尺度分布是否失衡,很多人上来就换模型、调anchor,实际上先统计一下训练集里小目标的占比,往往能找到更直接的原因。
4.2 误检高发区:安全带与背景纹理的"撞脸"
把验证集上误检的样本挑出来看,几个高发区域非常有规律:
- 安全带斜挎方向上的衣服纹理:深色条纹衬衫、格子衫的斜向纹路,在低分辨率下很像安全带。
- 车窗边框和后视镜轮廓:车窗玻璃的斜边、A柱的影子,与安全带的走向重合时极易误检。
- 方向盘上部:方向盘倾斜的角度和安全带类似,尤其是方向盘上有装饰条或纹理时。
- 副驾驶坐姿异常:副驾驶安全带系法不规范、带子拧转,呈现出的斜向条带容易让模型误认为是正样本。
这些误检很难通过单纯加数据解决,更有效的手段是调整后处理策略。实际操作中,我习惯把class 1的置信度阈值从默认的0.25提到0.35到0.4,同时对检测框做一次"几何合理性过滤":因为安全带有相对固定的空间位置,它应该在人体躯干的中上部位,如果检测框的y坐标落在图像的下三分之一区域,或者框的高度小于宽度的三倍却又不呈斜条状,大概率是误检,直接丢弃。这类基于任务先验的规则过滤,效果立竿见影,而且不增加推理延迟。
4.3 类别阈值与NMS的联动调整
YOLO默认的NMS用IoU阈值0.45,但对安全带这个任务,建议把IoU阈值适当调高到0.5到0.55。原因还是那个老问题:小目标的预测框往往有轻微偏移,同一个安全带可能会产生多个IoU不算高但实际指向同一目标的框。如果NMS阈值太低,这些框会被当成不同目标保留下来,出现一个驾驶员身上挂三四个框的尴尬画面。
同时要注意类别之间也会互相抑制。class 0和class 1的框在空间上高度重叠——毕竟一个"系了"一个"没系"的位置几乎一样——如果后处理里不同类别直接做NMS,很可能把正确的类别框干掉。YOLOv8的NMS默认按类别独立执行,但如果你自己写了后处理脚本,务必确认这点,别把两个类别的框混在一起做抑制,否则class 0和class 1只能活下来一个,这等于废了一半标注。
5. 从训练到落地部署:数据集的真正考验在车道线上
5.1 从PyTorch到TensorRT和NCNN
训练完成只是第一步,真正上线通常是导出成TensorRT引擎(英伟达平台)或NCNN(瑞芯微、海思等国产边缘芯片)。YOLOv8的导出命令非常简单,yolo export model=best.pt format=engine device=0,但导出前的量化选择要提前想清楚。
安全带检测强烈不建议直接上INT8量化。FP16精度下的模型损失几乎可以忽略,但INT8量化后,小目标检测的精度可能掉5到10个百分点。原因不难理解:安全带本身是低对比度的细长结构,INT8量化会把颜色和边缘的细微差异压缩掉,模型学到的判别线索被削弱。如果边缘设备的存储和带宽实在紧张,非要INT8,那也要用验证集做过校准,并且实地测试远距离样本,确认召回率下降在可接受范围内再上线。
5.2 安装角度差异导致的"域偏移"
这是一个非常隐蔽的坑。同一个模型在A卡口表现很好,换到B卡口就明显变差,问题经常出在相机安装角度上。A卡口相机正对来车,安全带走向是从左上到右下;B卡口相机装在侧方,安全带走向变成接近垂直或从右上到左下。模型虽然对旋转有一定鲁棒性,但角度差异过大时,特征的分布就变了,这就是典型的域偏移。
应对方法有三层。第一层是训练时做充分的角度增强——随机旋转参数建议在-15度到+15度之间,太大会引入不真实的畸变。第二层是如果知道部署卡口的大致角度,可以在数据集里专门补一组该角度的图像做微调。第三层是模型部署后,在前一两周持续搜集该卡口的真实抓拍图,人工标注后做增量训练。这套"训练集+现场数据回流"的打法,才是安全带检测项目长期保持高精度的核心,单一数据集再大也很难覆盖所有安装场景。
5.3 视频流场景:单帧检测还是加跟踪?
很多项目方想直接用单帧检测处理视频流,结果发现同一辆车在连续帧里一会检出未系、一会丢了,产生大量重复报警和遗漏报警。更稳的做法是在视频流上做跟踪后处理。简单说,用ByteTrack这类轻量跟踪器把车框关联起来,然后对一段时间窗口内的检测结果做投票:如果一个目标在连续N帧里被检出未系安全带的次数超过阈值,才输出一次报警。
这套机制的好处非常直接:一方面过滤掉单帧误检,另一方面避免对同一辆车重复报警。安全带检测的误检大多是偶发的,比如某帧里衣服纹理恰好像安全带,但连续十帧都误检的概率极低。给同一辆车的未系检测结果做一个置信度累计,误报率能下降一个量级。数据集本身的标注是单帧的,但使用场景是视频的,这个差异要在系统设计层面补上,而不是只指望模型。
5.4 夜间与低照度场景的兜底方案
前面提到数据集里有20%的夜间样本,但真实夜间场景的条件更为复杂。夜间卡口的图像质量取决于补光灯和相机参数,有的卡口画面偏暗、噪点严重,即便模型在夜间样本上训练过,现场表现也可能打折扣。
针对低照度场景,工程上有两个实用兜底方案。一是对输入图像做自适应亮度归一化,把图像线性拉伸后再送进模型,能在不改变模型结构的情况下提升低照度下的检出率。二是在模型外面加一个"时段开关":白天用普通模型,夜间切换到用夜间增强数据微调过的模型,两个模型共享同一套数据集,只是训练时的增强策略不同。这种做法看起来笨,但确实是最稳的,因为数据和模型分离,出了问题可以快速定位是模型的问题还是数据的问题。
6. 数据要一直长:从8400张开始的持续迭代思路
6.1 难例挖掘是数据集升值最快的方式
8400张数据集再完善,也不可能覆盖所有现场情况。真正让模型性能持续提升的关键动作,是部署之后持续做难例挖掘。具体操作很简单:在已上线的卡口每天保存一批模型的低置信度检测结果,也就是conf在0.3到0.6之间、判不准的样本,然后每周请标注人员补充一批。这些难例往往来自最刁钻的角度和最意外的光照条件,每补几百张再增量训练一次,模型的鲁棒性就会有肉眼可见的提升。
有一个注意点:难例挖掘时不要只挖"判错"的样本,也要定期补充"判对但置信度很低"的样本。模型能在低置信度下做对,说明它学到了一些边缘特征,但这些特征不够强,用更多标注样本把这些特征的权重拉上来,比纯粹纠正错误更有效率。
6.2 主动学习与数据预算的分配
对资源有限的小团队来说,主动学习比盲目扩充数据划算得多。流程是这样的:用当前模型对所有未标注的现场图像做推理,按置信度排序,然后只抽取置信度落在"最难"区间的那部分图像交给标注人员。置信度高到接近1的样本模型已经会了,标了也白标;置信度低到接近0的样本往往是目标被完全遮挡或目标根本不在画面内,标了价值也有限。真正值钱的反而是置信度中等偏低的样本——模型看见了点什么,但拿不准——这些就是决策边界附近的样本,标一个能顶五个。
具体实现上,可以设定推理置信度在0.2到0.5之间的图像为候选池,每个批次从候选池里随机抽30%加上人工指定的特别难例,合成下一轮训练集。这个策略对安全带检测尤其有效,因为这个任务的主要难点集中在特定视角、特定光照的边界情况,主动学习可以精准地把数据预算花在这些"临界难例"上。
6.3 多地域、多车型与安全带颜色的覆盖
最后聊一个容易被忽略的维度:地域和车型差异。不同地区的车辆类型差异很大——轿车、SUV、货车、面包车的驾驶室布局完全不同,安全带的位置和走向也有差别。货车驾驶室高,安全带在画面里的角度更陡;面包车挡风玻璃更垂直,安全带的可见度更高。如果项目要覆盖多个省份或多种车辆类型,最好在数据集基础上按需补充对应类型的样本。
安全带颜色同样值得注意。深色安全带在多数车型上占比不低,但很多数据集偏重浅色安全带样本,导致模型对深色安全带的召回率偏低。检查一下自己手里的训练集,如果深色安全带样本占比不到20%,建议补充一批。这个细节小,但对最终上线的误检率影响非常大。说到底,安全带检测的数据集不是攒够一个固定数量就算完了,而是要围绕目标场景持续"喂"正确方向的样本。8400张是一个很好的起点,后续以周为单位做增量更新,模型的实用性才会越来越强。