YOLOv8高空作业安全带检测实战:从数据集构建到TensorRT部署全复盘
2026/9/17 3:14:18 网站建设 项目流程

做施工安全和工业视觉落地的人,肯定绕不开一个场景:高空作业人员有没有系安全带。以前靠安全员盯监控,眼睛能看花,而且画面上人一多、背影一多,根本看不过来。后来我把“YOLOv8高空作业安全带检测数据集”和“安全行为检测”这件事从头到尾做完了一遍,从数据采集、标注、训练、评估,到TensorRT 8.6部署和现场报警联动,踩了不少坑,也总结了一套能直接落地的流程。这篇文章就把整个项目复盘一遍,重点讲清楚数据怎么整、类别怎么定、YOLOv8怎么训、部署时要注意什么,以及那些文档上不会写的坑。想用YOLOv8做安全行为检测的同学、做施工安全项目的集成商,或者正在准备相关毕设的人,都可以参考。

1. 项目整体设计与数据集构建思路

1.1 高空作业场景下安全带检测为什么难

很多人以为安全带检测就是训练一个模型,把“背带”框出来就行,真正上手才发现远没那么简单。高空作业的摄像头通常架在塔吊、杆塔、建筑外沿或者吊篮上,机位高、角度刁,画面上的人往往只有三四十个像素高,背带在图上就是几条斜线,模型很容易当成背景纹理丢掉。

遮挡问题也很致命。脚手架、护栏、安全网会把人的下半身挡掉,有时候只露出一个头和一截肩膀,背带被反光背心遮住,模型根本看不到“绑带交叉”这个关键特征。再加上工地背景特别乱,钢筋、吊绳、斜拉索和背带形态接近,单靠一个目标检测网络去区分,确实要靠数据砸。

还有一个很容易被忽略的问题:安全带的形态差异很大。全身式安全带和半身式安全带视觉特征不一样,不同厂家生产的背带反光条位置不同,有些工人把背带穿在棉袄外面,有些穿在里面只露出一根带子。只要现场样本不够全,模型在白天晴天表现很好,一到阴天或者傍晚就崩。

所以这个项目的核心难点不在于“模型结构”,而在于“数据能不能覆盖现场真实分布”。我在设计数据集时,第一优先级不是追求yolov8的什么trick,而是把高空作业的视角、光照、姿态、遮挡情况尽量铺满。

1.2 数据集的类别设计与判定逻辑

最开始我做的是单类别检测,只检测safety_harness,也就是把背带框出来。上线测试后发现误报非常严重:工人手里拿着背带、背带挂在栏杆上、甚至地面堆着一团安全绳,都会被当成“已佩戴安全带”。因为目标检测模型看到的是局部,它不知道这条背带到底穿没穿在人身上。

后来把方案改成两类检测:

  • worker_safe:人员已正确穿戴安全带
  • worker_unsafe:人员未穿戴安全带或穿戴不规范

这样做的逻辑是把“安全行为判定”直接转化成“人员目标分类”。检测器先定位人,再判断这个人属于安全还是不安全,模型学到的是“人+背带同时出现且位置关系合理”的组合特征,而不是单独的背带特征。对于安全监管场景,报警信号直接来自worker_unsafe这一类,不用再做额外的空间匹配逻辑,流程简单,也更容易满足实时性要求。

类别数量还能扩展到三类,比如worker_safeworker_unsafeuncertainuncertain用来处理那些遮挡严重、难以判断的样本。但实际使用中,uncertain这个类别很容易被模型当成“垃圾桶”,导致原本能分清的样本也往里面丢。我在项目里最终放弃了uncertain,而是把这些难样本通过background类或者忽略区域处理,效果反而更好。

1.3 数据集规模与划分策略

这个项目的数据集我最终定了大约12000张图,其中安全样本约8000张,不安全样本约4000张。比例不是随便拍的,而是根据现场真实分布来的。施工现场系安全带的合规率通常在80%左右,按这个比例去采样,模型才能学到合理的先验。

训练集、验证集、测试集的划分有一个大坑:视频抽帧出来的连续帧非常相似,如果随机划分,同一段视频的相邻帧会同时出现在训练集和验证集里,验证指标会虚高。必须按“视频片段”划分,保证同一个摄像头、同一段时间的视频帧全部落在同一个集合中。我在项目里是这样做的:先按日期和机位把视频切片,比如每3分钟一个片段,然后按片段分配train/val/test,比例大概8:1:1。这样验证集的指标才真正反映模型面对新场景的能力。

2. 数据采集、标注与预处理实战

2.1 数据从哪来:现场、公开集、合成数据

数据集是这类项目的命根子,但大多数人一开始手里根本没数据。我的经验是分三条线同步推。

第一条线是现场监控视频抽帧。这是质量最高、最贴合业务的来源。从工地监控系统里导出不同机位、不同班次、不同天气的视频,按每秒1帧或者每5秒1帧抽,抽完先做一次人工粗筛,把模糊、过暗、遮挡太严重的图丢掉。实际筛下来,10000张原始抽帧里能留下6000张就不错了。

第二条线是公开数据。网上有安全帽检测数据集、建筑工地人员数据集,里面多少会带一些安全带样本。这类数据可以补足不同角度、不同服装的多样性,但一定要人眼过一遍,因为公开数据集的标注质量参差不齐,有些图把安全绳的绳端当成了背带主体,直接用会污染模型。

第三条线是合成数据。用3D仿真软件或者图像合成工具,把人物和安全带的贴图随机贴到工地背景上,能补充极端罕见场景,比如工人站在吊篮边缘、背带被完全遮住但能看出没系。合成数据只建议占训练集5%-10%,纯度不够的话,模型容易学到假的纹理。

2.2 标注规范:这些细节决定模型上限

标注工具我用过LabelImg、X-AnyLabeling、CVAT,最终项目里主力是X-AnyLabeling,支持自动标注预标注、效率高,适合大批量数据。但工具是次要的,标注规范才是决定模型上限的东西。

我的标注规范里有几条硬性要求:

  • 每个被检测的人员目标必须有一个bbox,框要贴住人,不能把安全绳延伸到框外太长。
  • worker_safeworker_unsafe的判断标准:安全带穿戴完整、卡扣扣好才算safe;只披在身上没扣、或者完全没穿都算unsafe。
  • 人目标被遮挡超过70%时,不标注,避免给模型传递混乱信号。
  • 远小于20x20像素的目标不标注。硬标会让模型在训练时产生大量低质量正样本,拉低整体精度。
  • 视频连续帧中同一个人的状态突变,比如上一帧safe下一帧unsafe,要重点核查,经常是标错了。

标注字段我还会额外记录“遮挡程度”“目标尺度”“是否模糊”这几个属性,虽然YOLOv8训练时不会直接用这些字段,但在做错误分析和数据集补充时非常有用。比如我发现模型在“中等遮挡+远小目标”上误报集中,就专门去补充这一类样本,比盲目加数据高效得多。

2.3 数据增强与规模控制的平衡

YOLOv8自带了一些增强策略,比如Mosaic、MixUp、HSV扰动、随机透视,效果很好,但不是越猛越好。高空作业场景的背景本身就比较单一,大量使用Mosaic会把工地背景切成碎片,模型容易学到奇怪的特征。

我的做法是分阶段调整增强参数。第一遍用默认增强跑一个baseline,看loss曲线和验证集表现。如果存在过拟合,再逐步增强Mosaic和MixUp的权重;如果模型在远小目标上漏检,就增加多尺度训练的强度,比如让输入尺寸在960到1280之间随机波动。

针对现场摄像头普遍存在的运动模糊问题,我在训练集中随机加了高斯模糊和轻微的运动模糊增强,模拟工人快速移动、摄像头抖动的情况。加了之后,模型在早晚高峰工人集中上工时的表现提升特别明显,这个增强在常规项目里很少有人注意。

另外,尽量不要对视频抽帧连续截图做同样的增强后全部塞进训练集,这些增强后的图在背景上高度相似,只会增加训练时间,对泛化能力帮助很小。正确的做法是先把连续帧去重,只保留画面变化比较大的帧,再进行增强。

3. YOLOv8训练全流程与参数调优

3.1 数据集组织与配置文件

YOLOv8的数据集目录结构很简单,按官方约定组织就行:

datasets/harness/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── harness.yaml

harness.yaml内容:

path: /data/datasets/harness train: images/train val: images/val nc: 2 names: 0: worker_safe 1: worker_unsafe

这里有一个不起眼但很重要的点:类别顺序一旦定下来就不要频繁改动。你训练出模型后,导出ONNX,做TensorRT部署,写C++后处理,解析结果的索引全部依赖这个顺序。如果中途改了类别顺序,之前训练的权重就全部作废,部署端也要同步改,非常折腾。

3.2 训练命令与关键参数选择

我用的训练命令大概是这样:

yolo detect train \ data=harness.yaml \ model=yolov8m.pt \ epochs=200 \ imgsz=1280 \ batch=16 \ patience=30 \ optimizer=SGD \ lr0=0.01 \ lrf=0.001 \ weight_decay=0.0005 \ warmup_epochs=3.0 \ cos_lr=True

有些参数值得展开说。

输入尺寸imgsz我选了1280而不是默认的640。原因很简单:高空作业摄像头画面视野大,人员目标小,640尺寸下一个人就十几个像素,特征基本糊掉。用到1280后,小目标mAP提升了将近8个百分点。如果你的部署设备性能有限,建议先用1280训练,再在导出模型时用640做TensorRT的输入尺寸,虽然有些精度损失,但还能保留一部分小目标特征。

模型规模选了yolov8m,不是最大最好的yolov8x。高空作业安全带检测的难点在召回率而不在类别细分能力,yolov8m在精度和速度之间最均衡。真上了yolov8x,精度提升不到1%,推理速度掉了近一半,做边缘端部署时非常不划算。

batch size的设定要兼顾显存。在GTX 1660Ti这种6GB显存的卡上训练,imgsz=1280时batch=16会爆显存,可以降到4-8,或者干脆把imgsz降到960。YOLOv8对batch size不敏感,batch小一点最多收敛慢一点,不会出大问题。

3.3 损失函数曲线怎么看:别等训练完才发现问题

YOLOv8训练会生成results.csv,里面包含box_loss、cls_loss、dfl_loss、precision、recall、mAP50等字段。我习惯用一段简单脚本把曲线画出来:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("runs/detect/train/results.csv") epochs = df["epoch"] fig, ax = plt.subplots(2, 2, figsize=(14, 10)) ax[0, 0].plot(epochs, df["train/box_loss"], label="box_loss") ax[0, 1].plot(epochs, df["train/cls_loss"], label="cls_loss") ax[1, 0].plot(epochs, df["train/dfl_loss"], label="dfl_loss") ax[1, 1].plot(epochs, df["metrics/mAP50(B)"], label="mAP50") for a in ax.flat: a.legend() a.set_xlabel("epoch") plt.tight_layout() plt.savefig("training_curves.png")

看曲线有几个判断方法。前30个epoch,如果box_loss从1.6左右降到1.2以下,说明模型在正常学习。如果loss曲线震荡非常剧烈,先看batch size是不是太小、学习率是不是太高。如果训练loss还在降、验证集的mAP50已经连续20个epoch不涨,那就是过拟合信号,patience参数会自动触发早停,但我会更早介入,先降低增强强度或者加数据。

我那个项目到最后box_loss稳定在0.7左右,mAP50到了0.93,mAP50-95在0.63,看起来不算特别夸张,但在现场部署时,漏报率控制得很好,因为更关键的指标是recall,尤其对worker_unsafe这个类别。训练时要专门看每个类别的召回率,别被整体mAP糊弄过去。

3.4 模型评估与置信度阈值怎么定

训练完用验证集跑一遍评估:

yolo detect val data=harness.yaml model=runs/detect/train/weights/best.pt imgsz=1280

除了mAP,我还会重点看PR曲线和F1曲线。YOLOv8会在验证目录下生成F1_curve.pngPR_curve.png。安全行为检测和一般目标检测不一样,它对worker_unsafe的召回率要求极高,宁可误报也不能漏报。

实际使用中,我把默认的conf=0.25调到conf=0.15,让模型对不安全状态更敏感。代价是误报会增加,但配合后面的时序判定和区域过滤,误报能压下去。单纯看单帧准确率,conf=0.15时的precision只有78%,但连续10帧里有8帧报警才触发联动,实际现场误报率可以控制在每天几次以内,完全可以接受。

4. 安全行为判定逻辑与后处理

4.1 从单帧检测到连续行为判定

目标检测模型输出的每一帧结果只是单帧判断,直接拿着去报警会被瞬间误检搞得痛苦不堪。防风打火机闪一下、工人弯腰捡东西、摄像头抖动一下,都可能导致单帧误判。所以我在检测后面加了一层轻量级的行为状态机。

做法是:用IoU匹配算法对相邻帧的检测框做关联,给每个目标维护一个状态结构体,大致逻辑是:

track_state = { "track_id": 1, "unsafe_count": 0, "total_count": 0, "is_alerting": False }

每来一帧,先做检测,然后做目标匹配。如果某个目标匹配上,就更新它的类别计数。判定规则是:连续10帧中,worker_unsafe占7帧以上,并且持续时间超过5秒,才触发报警。一旦触发报警,进入5分钟冷却期,等现场处理完再重新判定。

这个逻辑能把大部分偶发误检过滤掉,但有一个代价:真正发生危险动作时,报警会有几秒延迟。对施工安全来说,5秒以内的延迟可以接受,因为报警本来就是为了通知安全员去现场处理,不是做毫秒级紧急制动。

4.2 区域联动与电子围栏

高空作业摄像头画面很大,并不是所有区域都需要做安全带检测。比如画面上有地面通道、材料堆放区,工人路过时没系安全带,不应该触发报警。我给每个摄像头配置了ROI多边形,只有检测框中心点落在ROI内才参与行为判定。

ROI配置在界面上就是画一个多边形,存成json文件。现场改动很容易。这套区域联动机制还有一个好处:同一路摄像头可以配置多个ROI,比如塔吊臂上是一个ROI,钢平台上又是一个ROI,每个ROI的判定阈值可以单独设,灵活很多。

4.3 边缘部署:TensorRT 8.6与RK3588

模型训练完只是第一步,现场设备大多不是插着4090的服务器,而是Jetson、RK3588这种边缘盒子。我落地时主要做了两条部署路径。

首先是TensorRT 8.6部署。流程是先用Ultralytics导出ONNX:

yolo export model=best.pt format=onnx imgsz=1280 opset=12 simplify=True

然后用TensorRT构建engine:

trtexec --onnx=best.onnx --saveEngine=best.engine --fp16 --workspace=2048

C++端用TensorRT的C++ API加载engine,输入输出是float数组,后处理里要做NMS过滤和坐标换算。这一步坑很多,最典型的是TensorRT各版本API不兼容,编译时一定要锁死版本,我用的是8.6.1.6,配套的CUDA和cudnn版本也要一致。

另一个坑是动态shape。如果导出的ONNX是动态输入尺寸,TensorRT构建engine时会多花时间,而且容易报错。我直接固定输入尺寸为1280x1280,舍弃动态输入,换来更快的推理速度和更稳定的构建过程。

第二条路径是RK3588的NPU部署。流程是:先导出ONNX,然后用rknn-toolkit2转成rknn模型,再烧到3588的NPU上跑。RK3588部署YOLOv8有几个注意点:ONNX的opset要设成12,太高某些算子不支持;转模型时要指定mean_valuesscale_values,不同训练代码出来的预处理参数不一样,转完一定要用同一张测试图对比输出,看误差在不在接受范围。

我的经验是用TensorRT跑在Jetson Orin Nano上,FP16精度下1280x1280输入,YOLOv8m推理速度大约25毫秒;用RK3588 NPU跑640x640输入,YOLOv8s大约35毫秒。边缘端如果资源紧张,就退而求其次用640输入,虽然小目标检测能力变弱,但通过扩大ROI和时序判定,工程上还是可以接受。

5. 常见问题与排查技巧实录

5.1 数据集与标注问题

这个项目里最常见的数据问题是样本不均衡。我一开始标注时,安全样本远多于不安全样本,比例接近9:1,训练出的模型对worker_unsafe不敏感。解决方法是单独采集不安全场景的视频,或者用数据增强针对不安全类别做过采样。我当时是把不安全样本重复复制并做轻度增强,把训练集比例调整到7:3,召回率提升很明显。

还有一个很隐蔽的问题:标注框的类别标反了。几个标注员对“安全带穿但不扣”算safe还是unsafe理解不一致,导致同一批数据里同类样本特征互相冲突,训练loss很难降下去。后来我建了一个标注FAQ,把安全穿戴的几个关键判断点用截图列出来,让所有标注人员照着执行,问题才慢慢消失。

5.2 训练效果不理想的排查

如果你遇到底层loss降不下去,或者mAP波动大,先检查三件事:类别概率是否均匀、标注框是否越界、训练集是否包含大量重复帧。YOLOv8训练过程中如果loss在某个数值附近持续震荡,大概率是数据有噪声,而不是模型结构有bug。

显存不够也是高频问题。GTX 1660Ti跑1280输入时batch只能设4,这时候不要硬扛,可以开启cache=True减少磁盘IO,或者把workers调高,但最有效的还是降batch、降输入尺寸。

我遇到过最典型的训练问题是:训练集mAP很高,验证集mAP很低。原因是视频抽帧的数据泄漏。后来按视频片段划分数据集后,这个现象立刻消失了。

5.3 部署运行阶段的坑

部署阶段的高频问题我整理成了速查表:

问题现象可能原因解决方案
TensorRT推理结果和PyTorch差异大ONNX导出时opset或预处理不一致对比同一张图的预处理,统一mean/std和缩放方式
推理速度慢,帧率不高输入尺寸太大、模型过大、没有开FP16改用640输入、换yolov8s、开启FP16
报警总是漏报置信度阈值太高、ROI没覆盖目标区域调低conf、扩大ROI
报警总是误报缺少时序判定、单帧直接报警增加连续帧计数和状态机
夜间红外画面检测效果差训练集里缺乏红外样本单独采集夜间数据,或在训练时加灰度化和亮度增强
RK3588转换报错ONNX包含不支持的算子降低opset、固定输入尺寸、逐层检查算子

经验就是,部署阶段的问题绝大多数不是因为模型训练得不好,而是数据格式和预处理不一致造成的。所以我每次换部署平台,第一件事不是看算法,而是拿同一张现场图走一遍完整链路,对比输出框是否一致。这一条建议能帮你省掉至少一半的排查时间。

6. 个人心得与后续扩展建议

做了整个项目之后,我最真实的体会是:做安全行为检测,不要一上来就想着改YOLOv8的结构、加注意力机制、魔改head。对这个小目标、强干扰、真实落地的场景来说,数据质量、标注一致性、时序判定和部署优化才是决定项目成败的四个支柱。模型本身用官方YOLOv8m就足够能打了,真正拉开差距的是你愿不愿意在数据清洗、难样本挖掘上下功夫。

还有一个经验是,现场算法要留人工接管的口子。安全行为检测再准,也不可能100%判断所有情况,尤其是工人背对摄像头、背带被完全遮住的时候。给现场安全员做一个简单的一键确认和报警复核流程,比追求模型完美更实际。

最后再分享一个小技巧:采集数据时,不要只在天气好的白天拍。一定要安排夜间、雨天、逆光时段各拍一批,哪怕数量少。因为摄像头部署后的真实运行环境,往往是模型训练时最缺少的那部分。把这些“不好看”的样本补进去,模型在夜间和恶劣天气下的鲁棒性会提升一大截。这个项目后续如果要扩展,可以往两个方向走:一是加上安全帽、反光衣、人员越界检测,合成一套完整的施工安全行为识别方案;二是把安全带检测从检测框升级为关键点检测,识别双钩是否挂好、安全绳是否系在挂点上,这种更细的行为判断,才是施工安全AI真正值钱的地方。

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

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

立即咨询