news 2026/9/7 6:39:32

YOLO工地安全带检测实战:从数据标注到TensorRT部署全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLO工地安全带检测实战:从数据标注到TensorRT部署全指南

简介:本资源是一个基于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 标注标准:同一个框,两次标注要一致

安全带检测的数据标注其实是这个项目里最折腾的一环。如果你定义“安全带”是一个完整的目标,那标注框应该怎么打?

我第一次做的时候,让三个标注员标同一批图,结果三个人给了三种不同的标法。有人把斜挎的带子标成一个倾斜的长方形,有人标的是覆盖整个胸腹区域的大框,还有人把安全绳也一起框进去了。拿到训练集,模型直接学糊涂了。

为了让标注统一,我们定了三条规则:

  1. 标注目标必须是“佩带在人体上、起到防护作用的织带部分”,不包括安全绳、挂钩、固定点。
  2. 标注框贴合织带的最小外接矩形,也就是说允许倾斜角度较大的框,用YOLO的旋转框(OBB)格式会更准,但如果没有OBB支持,就画常规的axis-aligned框,尽量紧贴主要织带区域。
  3. 如果安全带完全被反光背心或衣物遮挡,不标;如果部分遮挡还能看清织带,标看清的那部分。

这些规则看着简单,但落到每一张图上都会遇到边界情况。比如工人坐在高凳上,安全带的腿带和腰带叠在一起,是标一个框还是标两个?我们的处理办法是:标一个框,以腰带和肩带的交汇区域为中心,保证模型关注的是“这个区域有安全带”这个事实,而不是安全带的精确轮廓。

数据标注是个脏活累活,但这步直接决定了模型的最终表现。在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( data="safety_belt.yaml", epochs=150, imgsz=640, batch=16, lr0=0.01, lrf=0.01, momentum=0.937, weight_decay=0.0005, warmup_epochs=3.0, warmup_momentum=0.8, cos_lr=True, optimizer="AdamW", amp=True, patience=30, workers=4, device=0, )

这里有几个参数值得说一下为什么这样设:

  • lr0=0.01:迁移学习中,预训练权重已经有了很好的特征提取能力,学习率不宜过大,0.01是一个相对安全的起点。如果你是零基础从头训练,可以放到0.02,但效果通常不如迁移学习。
  • cos_lr=True:使用余弦退火调整学习率,前期快速收敛,后期在极小范围内精细调整,比固定步长衰减更平滑,对最终精度有帮助。
  • patience=30:如果连续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再到TensorRT

PyTorch模型直接推理速度一般,而且部署环境必须装完整的PyTorch框架,这在生产环境里不够优雅。我习惯先把best.pt导出成ONNX,再在目标机器上转成TensorRT的engine文件。

yolo export model=best.pt format=onnx opset=12 dynamic=True

导出ONNX之后,用trtexec转TensorRT:

trtexec --onnx=best.onnx --saveEngine=best.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, conf=0.5, iou=0.45, classes=None, imgsz=640, device=0) 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 = f"buckled {conf:.2f}" color = (0, 255, 0) # 业务逻辑:记录已系安全带的检测事件 else: label = f"unbuckled {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()

代码里的conf=0.5iou=0.45是两个关键的推理参数。置信度阈值设低了会狂误报,设高了会漏检。安全带检测的经验值是0.5左右,但最好根据实际场景微调,后面再细说。

4.3 业务判定:只靠模型输出是不够的

如果你只把模型输出的“有安全带/没安全带”直接交给告警系统,那大概率会收到一堆离谱的告警:空地上的一件叠好的安全带被检测成“已系”,人走过去又检测成“未系”……这是模型没结合上下文导致的。

我做的系统里,业务判定层加了几条规则来抑制误报:

  1. 目标锁定和跟踪:用ByteTrack或者简单的IoU tracker给画面里的每个“人”分配一个ID。只有当同一个ID的人连续N帧(比如5帧)都被判定为“未系安全带”时,才触发告警。单帧的误判会被时间序列过滤掉。

  2. 最小检测框过滤:如果一个“未系安全带”目标的置信度不高或者框面积太小,说明模型可能是在遮挡区域或远距离目标上做的猜测,这种不告警,只记录。

  3. 人-安全带位置关系判断:如果检测到了“人”,但几乎没有“安全带”目标与其重叠,这可能是因为安全带被完全遮挡,也可能是真的没系。这时候不直接判违规,而是标记为“疑似未系”,由人工复核。这个设计在合规性上非常重要,因为自动化系统不该“冤枉”工人。

  4. 区域屏蔽:有些区域(比如休息区、办公室门口)不需要检测安全带,可以在系统后台画一下ROI,ROI之外的检测结果直接忽略。

这些规则叠加起来,告警准确率能比单模型直接输出高出一大截。

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的人很多,能让它在复杂工地场景里稳定运行、误报可控、告警可解释的人,才算真的把这活儿干明白了。

如果让我再给一次建议,我会说:动手之前,先花两三天把现场情况摸清楚——摄像头机位、人员动线、光照变化、着装规范,这些信息对项目的决定作用,可能比更换任何一个模型版本都大。毕竟模型是你自己写的,但工地是现实的世界。

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

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

教授创业潮下的具身智能:数据闭环与工程化才是真门槛

如果你最近半年翻过科技媒体,大概会注意到一个耐人寻味的现象:很多新闻标题里,原本出现在论文署名中的高校教授,开始密集出现在创业公司的创始人名单里。而他们选择的方向,几乎都指向同一个词——具身智能。朋友圈里有…

作者头像 李华
网站建设 2026/9/5 16:01:56

Android新闻推荐系统源码解析:从毕业设计到答辩实战指南

简介:这是一套面向计算机、通信、人工智能等相关专业本科生的毕业设计级Android新闻推荐系统实现,适用于课程设计、大作业及毕设参考,尤其适合具备Java基础并希望实践移动开发与推荐算法结合的学习者。资源包含完整可运行的Android客户端源码…

作者头像 李华
网站建设 2026/9/6 8:46:28

AI Agent接入公共互联网的安全风险与日志排查实践

最近大家都在讨论一个趋势:OpenAI 之后,Anthropic 的 Claude 系工具也开始把操作范围延伸到公共互联网。简单说,AI 不再只是做文本生成,它能在任务里发起 HTTP 请求、读取网页、调用 API,甚至操作命令行。这对自动化效…

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

大规模MIMO信道估计MATLAB仿真:LS与压缩感知算法对比实战

这次我们来看一个非常经典的通信信号处理仿真任务: 大规模 MIMO 系统信道估计 。很多做 5G、6G 物理层算法的同学,或者正在准备通信方向毕业设计的读者,都会遇到这个课题。它的核心不是把信道估计算法背下来,而是要在 MATLAB 里…

作者头像 李华
网站建设 2026/9/6 10:56:09

基于微信小程序的师生互动桥系统毕业设计项目源码

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

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

社交交友源码解析:双端原生IM与音视频通话架构设计

简介:这是一套面向移动应用开发者与创业团队的社交类即时通信APP完整源码解决方案,聚焦一对一语音视频直播场景,适用于Android与iOS双端原生开发学习与快速产品化落地。资源包含619.62MB的ZIP压缩包,涵盖Android(Java&…

作者头像 李华