YOLO工地安全带检测实战:从数据标注到TensorRT部署全指南 📅 发布时间:2026/8/31 15:56:27 👁 浏览次数: 简介本资源是一个基于YOLO算法的实时安全带佩戴状态检测系统实现面向计算机视觉初学者、智能交通与车载安全方向开发者及高校课程设计实践者解决驾乘人员安全带佩戴自动识别与预警这一典型工业级图像识别问题。压缩包共17个文件含7张实拍测试图像jpg、2个预训练模型文件best.pt和yolov11.pt、1个核心推理脚本app.py、1个Streamlit配置文件config.toml、1个依赖清单requirements.txt、1个README说明文档及辅助文件整体大小为10.31MB其中模型文件可直接加载推理app.py封装了图像输入、YOLO预测、结果可视化全流程.streamlit配置支持快速部署交互式Web界面。目前已有61人学习下载资源结构完整、开箱即用涵盖数据样例、训练成果、部署脚本与工程配置特别适合理解YOLO在小目标检测中的实际调优逻辑并为后续扩展至多类别车内行为分析提供可靠基线。1. 安全带检测到底难在哪先想清楚业务边界再做模型上个月有个做工地安全管理的朋友找到我说他们想上一套基于YOLO的安全带检测系统压缩包发过来里面是标了一半的几张工地照片和一份写得很含糊的方案文档。我打开扫了一眼第一反应是这个项目怕不是只训练一个模型那么简单。安全带检测这个需求在网上搜一圈绝大多数教程就是“用YOLO训练一个能框出安全带的模型”然后贴几张训练曲线就完事了。但实际在工地上跑过一遭就知道真正难的根本不是“能不能框出安全带”而是“怎么判断这个人到底有没有系好安全带”。这是两码事。先说清楚两类业务场景因为这两个场景的目标完全不同抓拍审核场景摄像头在工地出入口或塔吊上抓拍工人经过或作业时的画面系统判断画面里有没有“未系安全带”的违规情况把违规照片推送给安全员。这类场景对实时性要求不高但对准确率要求很高因为要作为处罚依据。实时提醒场景摄像头架在高空作业面实时分析画面一旦发现未佩戴就现场语音提醒。这类场景对延迟敏感模型必须在边缘设备上跑得动而且误报太频繁会被工人直接无视。我朋友要的是第一种但方案里很多技术点都按第二种在写这显然是不对的。所以做系统之前先把你到底要解决什么问题想清楚比选什么模型重要得多。接下来是技术边界。安全带检测和普通的目标检测有个很大的不同安全带本身是个细长条、容易被身体遮挡、和背景颜色接近的小目标。如果你把“安全带”当成一个独立类别去框很快就会遇到一个尴尬的局面——模型能框出来但框的位置五花八门有人框的是斜挎在胸前的那条带子有人框的是腰部横着的那条还有人把安全绳也一起框进去了。这就涉及到一个很核心的建模决策你到底要检测什么我见过的做法分两种。一种是直接检测“安全带”本体训练一个类别另一种是先检测“人”再检测“安全带”通过两者位置关系判断是否佩戴。第一种简单但只适合“画面里只有一个人、拍摄角度固定”的受限场景比如考勤闸机。第二种更通用能应对多人、多角度的复杂工地场景但训练和推理都更复杂。我最终推荐的做法是采用“人员检测安全带检测逻辑判定”的三段式结构而不是一刀切地只训练一个模型。原因后面会展开讲。做任何目标检测项目第一步一定是搞清楚你的场景边界摄像头装在哪、拍多大范围、光照条件如何、人员密度多大、有没有夜间要求。这些参数决定了你要用什么样的数据集、什么样的模型结构、什么样的部署方案。安全带检测尤其如此因为工地的环境太杂了安全带有荧光色、红色、蓝色、黑色有斜挎式、背心式、腰带式还有各种穿了反光背心把安全带完全盖住的情况。你让模型怎么学2. 数据是天花板数据集从哪来、怎么标注、怎么平衡模型效果的上限在数据上这句话在安全带检测上体现得淋漓尽致。YOLO系列模型结构已经很成熟了但再好的结构喂进去的数据不行出来的东西就是不行。2.1 开源数据集能用但别指望直接拿来用搜过一圈就知道纯“安全带”类别的公开数据集少得可怜和质量相关的更少。和安全带关系比较大的是BDD100K自动驾驶数据集里面有安全带的标注和SODA驾驶人行为数据集包含安全带使用状态但这两个都是从驾驶场景来的拍的是车内视角和工地场景相差十万八千里。工业场景的安全带检测防坠落安全带是全身式的和车内三点式安全带完全不是一回事。所以我的建议是开源数据集可以作为预训练或者补充样本但主力数据必须自己采自己标。和朋友那边的安全员一起聊了一圈他们目前有十几个摄像头的历史监控录像这些录像就是最好的数据来源。挑天气好、光线好的几天从不同机位把视频片段按帧抽出来大概抽了3000多张图去掉重复严重的留下大概1800张有效帧。这些图涵盖了不同时间段、不同角度、不同光照条件单从多样性来说已经比开源数据集靠谱了。2.2 标注标准同一个框两次标注要一致安全带检测的数据标注其实是这个项目里最折腾的一环。如果你定义“安全带”是一个完整的目标那标注框应该怎么打我第一次做的时候让三个标注员标同一批图结果三个人给了三种不同的标法。有人把斜挎的带子标成一个倾斜的长方形有人标的是覆盖整个胸腹区域的大框还有人把安全绳也一起框进去了。拿到训练集模型直接学糊涂了。为了让标注统一我们定了三条规则标注目标必须是“佩带在人体上、起到防护作用的织带部分”不包括安全绳、挂钩、固定点。标注框贴合织带的最小外接矩形也就是说允许倾斜角度较大的框用YOLO的旋转框OBB格式会更准但如果没有OBB支持就画常规的axis-aligned框尽量紧贴主要织带区域。如果安全带完全被反光背心或衣物遮挡不标如果部分遮挡还能看清织带标看清的那部分。这些规则看着简单但落到每一张图上都会遇到边界情况。比如工人坐在高凳上安全带的腿带和腰带叠在一起是标一个框还是标两个我们的处理办法是标一个框以腰带和肩带的交汇区域为中心保证模型关注的是“这个区域有安全带”这个事实而不是安全带的精确轮廓。数据标注是个脏活累活但这步直接决定了模型的最终表现。在LabelImg或者X-AnyLabeling里面标注导出成YOLO格式的txt文件每个文件对应一张图片里面每一行是类别id、归一化后的中心点x、中心点y、宽、高。这些格式问题搞清楚了后面训练才不会出错。2.3 类别不平衡正负样本比例要控制安全带检测的一个天然问题是在合法的工地上大部分工人是系了安全带的所以“有安全带”的样本远多于“无安全带”的样本。但这会导致模型训练出一个很懒惰的结论——不管什么图都倾向于预测“有安全带”因为这样在训练集上loss比较低。解决这个问题的思路有两个方向将“未系安全带”定义为一个独立的类别来训练而不是只检测“已系”。这样模型学到的是两种状态的差异特征而不是单纯的有无目标。在数据采样时控制正负样本比例。理想情况下戴/未戴的比例控制在2:1到3:1之间比较合适不要超过5:1。如果原始数据里“未系”样本太少可以对这些样本做更多的数据增强变相提高它们的权重。我用的是第二种配合类别权重调整。YOLOv8的配置文件里可以直接指定每个类别的loss权重把“未系安全带”这个类的权重调高一点相当于告诉模型“这个类虽然少但你得学仔细”。2.4 数据增强在真实场景边缘疯狂试探Mosaic增强、随机翻转、色彩抖动、随机仿射变换这些是YOLO训练标配。但对安全带检测来说最有效的增强是模拟不同天气和光照条件——把图像的亮度随机调低加上高斯噪声模拟阴天傍晚的工地再加一点随机遮挡用黑色矩形块随机覆盖小区域模拟人和人之间互相遮挡的情况。这里有一个要注意的点不要把安全带的颜色和纹理增强没了。安全带通常是鲜艳的荧光色这是它重要的视觉特征。如果色彩抖动太激进把荧光黄绿给抖成了土黄色模型反而学不到关键特征。所以色彩类增强的强度要比一般的目标检测任务调低一些。3. YOLO模型选型与训练细节从配置文件到loss曲线模型选型这部分我直接说结论YOLOv8的小模型或者中模型就够用不是越新越好也不是越大越好。3.1 选型逻辑算力、延迟、精度的三角平衡网上关于YOLO的讨论很容易陷入“算法竞赛党”的思路——整天比较谁在COCO榜单上AP高一点。但实际工程不是这么选的你要看自己的部署环境。朋友项目里的摄像头是普通的网络摄像头视频流通过RTSP拉到本地服务器服务器上有一块中端的NVIDIA显卡比如T4或者RTX 3060级别。在这种配置下YOLOv8s或YOLOv11s可以在1-3ms内完成一张1080P图像的推理用TensorRT加速后完全够用。如果跑到YOLOv8x推理时间翻倍但精度提升可能只有2-3个点对安全带检测这种大目标场景来说不值当。YOLO系列迭代了这么多版本从v5到v8到v11每一代都在结构上做了优化但对普通用户来说最大的感知差异在于v8以后anchor-free机制让模型更容易收敛anchors参数不需要手动算了。所以在v8、v11上面训练从配置到调参都省心不少。我用的是YOLOv8s输入分辨率设成640x640保持默认如果你觉得小目标检测不利索可以上1280但训练时间和推理时间都会翻倍。对工地场景、1080P摄像头画面来说先把640跑通、跑好再谈要不要提分辨率。3.2 训练命令与参数一份可以直接抄的训练配置数据准备好了标注文件放好目录之后训练命令很短。我习惯用ultralytics的Python API来训练比命令行更灵活from ultralytics import YOLO model YOLO(yolov8s.pt) # 从COCO预训练权重加载做迁移学习 results model.train( datasafety_belt.yaml, epochs150, imgsz640, batch16, lr00.01, lrf0.01, momentum0.937, weight_decay0.0005, warmup_epochs3.0, warmup_momentum0.8, cos_lrTrue, optimizerAdamW, ampTrue, patience30, workers4, device0, )这里有几个参数值得说一下为什么这样设lr00.01迁移学习中预训练权重已经有了很好的特征提取能力学习率不宜过大0.01是一个相对安全的起点。如果你是零基础从头训练可以放到0.02但效果通常不如迁移学习。cos_lrTrue使用余弦退火调整学习率前期快速收敛后期在极小范围内精细调整比固定步长衰减更平滑对最终精度有帮助。patience30如果连续30个epoch验证集mAP没提升训练提前终止。安全带检测数据集一般不会很大150个epoch足够早停机制省时间。data指向的yaml文件内容是path: ./datasets/safety_belt train: images/train val: images/val names: 0: safety_belt 1: no_safety_belt如果你希望检测“已系安全带”和“未系安全带”两个状态就按这个格式两个类别。3.3 训练过程中的loss曲线怎么看训练时终端会打印每一轮的box_loss、cls_loss、dfl_loss和mAP指标。很多同学看到一堆数字就头大其实只需要盯住几个关键点。前20轮box_loss和cls_loss应该快速下降mAP50曲线开始爬升。如果前20轮loss纹丝不动大概率是学习率没设置好太大导致震荡太小导致不收敛或者是数据格式搞错了。50轮以后loss下降变慢mAP50和mAP50-95的差距会呈现出来。mAP50看的是“框得差不多的概率”mAP50-95看的是“框得多准”。安全带检测里安全带的精确边界其实没那么重要你不是要量它的尺寸只要框的位置基本覆盖住织带区域就行。所以mAP50-95略低一些是可以接受的。如果loss在训练后期突然上涨恭喜你遇到过拟合了。训练集规模小模型把训练集的噪声也学进去了。解决方案是增加数据增强强度或者冻结部分骨干网络层的参数。这里插一条很重要的经验训练过程中一定要保存best.pt和last.pt。ultralytics默认会保存但不少人培训的时候最后拿到的best.pt是几百轮后的结果跟last.pt差别不大就随意用了。其实best.pt是在验证集上表现最好的权重建议用best.pt做后续部署除非你有充分理由用last.pt继续微调。4. 从模型到系统推理加速、视频流接入和业务判定模型训出来只是第一步把模型变成一个真正能用的安全带检测系统这里面还有不少工程活。4.1 模型导出从PyTorch到ONNX再到TensorRTPyTorch模型直接推理速度一般而且部署环境必须装完整的PyTorch框架这在生产环境里不够优雅。我习惯先把best.pt导出成ONNX再在目标机器上转成TensorRT的engine文件。yolo export modelbest.pt formatonnx opset12 dynamicTrue导出ONNX之后用trtexec转TensorRTtrtexec --onnxbest.onnx --saveEnginebest.engine --fp16--fp16这个参数值得注意。半精度推理在T4、RTX 3060这些显卡上能把推理速度提升近一倍而且精度损失一般很微小对安全带检测这种粗粒度任务来说完全可接受。如果显卡不支持FP16部分老显卡也可以不启用但速度会慢不少。TensorRT的engine文件是跟显卡型号强相关的在RTX 3060上转出来的engine放到T4上不一定能用必须在最终部署的机器上重新转换。这个坑我踩过不止一次。4.2 视频流推理RTSP拉流、帧处理、结果回传视频流接入用成熟的CV库就够了核心逻辑是import cv2 import numpy as np from ultralytics import YOLO model YOLO(best.engine) # TensorRT engine cap cv2.VideoCapture(rtsp://192.168.1.100:554/stream1) while True: ret, frame cap.read() if not ret: break results model(frame, conf0.5, iou0.45, classesNone, imgsz640, device0) for r in results: boxes r.boxes for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) x1, y1, x2, y2 map(int, box.xyxy[0]) if cls_id 0: label fbuckled {conf:.2f} color (0, 255, 0) # 业务逻辑记录已系安全带的检测事件 else: label funbuckled {conf:.2f} color (0, 0, 255) # 业务逻辑触发告警 cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2) cv2.putText(frame, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imshow(safety belt detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()代码里的conf0.5和iou0.45是两个关键的推理参数。置信度阈值设低了会狂误报设高了会漏检。安全带检测的经验值是0.5左右但最好根据实际场景微调后面再细说。4.3 业务判定只靠模型输出是不够的如果你只把模型输出的“有安全带/没安全带”直接交给告警系统那大概率会收到一堆离谱的告警空地上的一件叠好的安全带被检测成“已系”人走过去又检测成“未系”……这是模型没结合上下文导致的。我做的系统里业务判定层加了几条规则来抑制误报目标锁定和跟踪用ByteTrack或者简单的IoU tracker给画面里的每个“人”分配一个ID。只有当同一个ID的人连续N帧比如5帧都被判定为“未系安全带”时才触发告警。单帧的误判会被时间序列过滤掉。最小检测框过滤如果一个“未系安全带”目标的置信度不高或者框面积太小说明模型可能是在遮挡区域或远距离目标上做的猜测这种不告警只记录。人-安全带位置关系判断如果检测到了“人”但几乎没有“安全带”目标与其重叠这可能是因为安全带被完全遮挡也可能是真的没系。这时候不直接判违规而是标记为“疑似未系”由人工复核。这个设计在合规性上非常重要因为自动化系统不该“冤枉”工人。区域屏蔽有些区域比如休息区、办公室门口不需要检测安全带可以在系统后台画一下ROIROI之外的检测结果直接忽略。这些规则叠加起来告警准确率能比单模型直接输出高出一大截。5. 实测踩坑记录那些训练文档里不会告诉你的问题最后一个部分聊聊我在这个项目里踩过的坑。这些都是实际跑系统之后才暴露出来的训练文档和教程里基本不会提。5.1 “yolo训练指标全是0”是怎么回事网上搜“yolo训练指标全是0”能搜出一堆人问我自己也遇到过。训练了十几个epoch终端打印的mAP50和mAP50-95全是0但loss在降。排查过程大概是这样的先看验证集图片是否正常如果验证集图片里有大量无目标图也就是没有安全带的图占了绝大多数mAP会算出来接近0因为模型预测的框和真值框对不上。再看标注类别是否正确YOLO训练时类别id从0开始。我在标注导出的txt文件里类别id不小心写成了1和2而yaml文件里定义的是0和1这样模型学习的目标映射全错了指标自然全是0。还有数据路径问题datayaml文件里的路径如果写错ultralytics会默认生成一个空的验证集训练照常跑但mAP全是0。这类问题看着低级但在新手里高发。我的经验是训练前先写个小脚本把数据和标注可视化跑一遍用ultralytics自带的验证逻辑或者只是画几个框在图上看看。这一步能排查掉80%的低级问题。5.2 反光背心一穿模型直接“瞎”了工地工人普遍要穿反光背心而反光背心是荧光色安全带也是荧光色两者在图像上几乎融为一体。我第一版模型在测试集上mAP50有92%一到实际画面里大量穿了反光背心的工人被识别成“未系安全带”。这个问题怎么解我后来在训练集里增加了大量“穿反光背心系安全带”的正样本让模型学会在颜色相近的情况下通过织带的形状和走向来区分。同时也加重了随机遮挡、色彩对比度调整这类增强。折腾了一轮之后实际误报率下降了一半以上但还是不太干净。这个场景说实话目前没有哪个开源模型能完全搞定必须在自己的数据上持续打磨。5.3 半遮挡情况下的决策游移工地上人走来走去难免互相遮挡。模型在遮挡严重的时候经常同一秒钟内把一个人从“已系”切到“未系”又切回“已系”。这就是为什么我在业务判定层一定要加时序跟踪和连续N帧判定。你在测试集上看不到这个问题因为测试集的图片是静止的、独立的但监控视频是连续的模型在连续帧间的稳定性比单帧准确率更重要。解决思路除了加跟踪器也可以在推理时加入“预测平滑”机制维护一个类别的指数移动平均分数比如当前帧的输出分数是0.7上一帧累积分数是0.8那么综合分数 0.3 * 0.7 0.7 * 0.8 0.77用这个平滑后的分数去和阈值比较。这样单帧的异常抖动会被摊平不会导致告警状态频繁切换。5.4 边缘设备部署显存和内存要提前量好如果系统要跑到边缘设备上这个问题就必须提前考虑。我一个合作伙伴用的是一种带GPU的边缘盒子显存只有4GB。TensorRT的FP16版本模型加载没问题但如果你同时跑多个视频流显存占用会迅速上涨过一会儿就OOM了。我的做法是每个GPU进程只跑一个模型实例多个视频流通过队列串行喂给这个实例利用TensorRT的上下文共享来降低显存峰值。同时把输入分辨率从640降到480牺牲一点精度换更低的延迟和显存占用。其实对近距离的安全带检测来说480分辨率也够用。这部分的经验总结下来就是部署环境决定了你训练时要怎么选模型和输入分辨率而不是先训好一个模型再想着适配环境顺序搞反了后面会非常被动。回过来看这个项目安全带检测系统的核心难点与其说在模型训练不如说在对业务场景的理解、数据的精细打磨和工程化部署的能力。YOLO本身是个成熟到不能再成熟的工具能用它跑通一个demo的人很多能让它在复杂工地场景里稳定运行、误报可控、告警可解释的人才算真的把这活儿干明白了。如果让我再给一次建议我会说动手之前先花两三天把现场情况摸清楚——摄像头机位、人员动线、光照变化、着装规范这些信息对项目的决定作用可能比更换任何一个模型版本都大。毕竟模型是你自己写的但工地是现实的世界。本文还有配套的精品资源点击获取