资讯详情

YOLOv8+DeepSORT施工安全监控:从检测到跟踪的完整实战指南

📅 2026/10/10 13:43:20 | 华诺云谱 👁 阅读
YOLOv8+DeepSORT施工安全监控:从检测到跟踪的完整实战指南
简介面向施工安全监控场景的检测与多目标跟踪方案整合YOLOv8检测模型和DeepSORT跟踪算法适合计算机视觉开发者、工地安全管理人员及相关专业学生使用。资源内包含已标注完成的目标检测数据集共一千二百零六张图像同时提供YOLO格式的txt标签文件和VOC格式的xml标签文件并划分好训练集、验证集与测试集附带data.yaml配置文件可快速用于YOLOv5、YOLOv8以及最新系列模型的训练。类别涵盖安全帽、未戴安全帽、未穿反光背心、人员、反光背心等施工安全要素帮助识别隐患并跟踪人员活动轨迹同时附有训练好的检测模型可直接用于推理或继续微调。整个资源包共约两千个文件以xml标注文件、txt标注文件、Python脚本和PDF说明文档为主压缩包大小约三百五十六兆字节。随包还提供运行步骤PDF、track.py及utils.py等辅助脚本方便复现检测与跟踪串联流程目前已有九十四人学习适合希望快速构建施工场地安全监测系统的开发者和团队。1. 拿到这套 YOLOv8 DeepSORT 施工 site 检测跟踪方案先想清楚它到底解决什么问题施工 site 里的安全隐患监控最难的不是“认出来”而是“认出来之后还要盯得住”。YOLOv8 把画面里的工人、安全帽、反光背心、危险区域逐帧框出来DeepSORT 跟踪算法再把散落的检测框串成带稳定 ID 的轨迹系统才能回答“这个人三分钟前摘了安全帽”“有人一直站在吊臂回转区”这类 construction workers 安全事件。这个压缩包把数据集、DeepSORT 跟踪算法、训练好的检测模型都备齐了余下的工作是把它们拼成一条能稳定跑监控视频的管线。适合正在做工地智慧安监、或者第一次把目标检测落地到实时视频流的工程师和团队。后面所有内容都按这个目标展开先跑通最小链路再谈数据、训练和踩坑。2. YOLOv8 管检测、DeepSORT 管跟踪这套管线的分工逻辑与最小运行链路2.1 为什么工地安全隐患监控必须“检测 跟踪”两条腿走路单帧检测有个老毛病第 3 帧检测到工人 A 没戴安全帽第 4 帧他被脚手架挡住漏检第 5 帧又出现系统不知道这是同一个人于是一个隐患在几秒钟内重复触发四五次报警。安全员第一天还会看第二天直接把警报声关了这就叫“狼来了”效应。DeepSORT 不是来替代 YOLOv8 的它只解决一件事给检测结果做时序关联。它的内部逻辑说穿了就两步第一步用卡尔曼滤波预测每个目标在下一帧的大概位置第二步用匈牙利算法把预测位置和当前帧实际检测到的框做匹配匹配上就续用老 ID匹配不上就发新 ID。这样一来“同一个工人全程没戴帽子”和“三个工人轮流没戴帽子”就是两种完全不同的轨迹状态后者才是真正的安全事故素材。选型上当前从业方案里 YOLOv8 DeepSORT 是性价比最高的组合之一YOLOv8 网络结构图网上到处都有单阶段检测器速度和精度平衡得好训练生态成熟改造成本低DeepSORT 虽然被吐槽改进空间不大但它足够简单、可解释、好调参部署到边缘盒子不费劲。比它新的 ByteTrack、StrongSORT 效果更好但工程复杂度高项目紧张时不建议上来就上。2.2 用压缩包里的训练好的检测模型先跑通单帧检测拿到训练好的检测模型后先别急着重新训练。第一步永远是把它在你自己的机器上跑起来确认模型能加载、视频能读、结果能画出来。常见做法是直接用 ultralytics 的 pip 包几行代码就能跑from ultralytics import YOLO # 压缩包里的 best.pt一般就是训练完自动选出的最优权重 model YOLO(weights/best.pt) results model.predict( sourcedemo_video.mp4, imgsz640, conf0.35, # 置信度阈值先低一点看看模型的真实上限 saveTrue, # 保存画框后的视频 projectruns/detect, namedemo, ) # 逐帧取出检测结果后面接 DeepSORT 要用 for frame_idx, r in enumerate(results): boxes r.boxes.xyxy.cpu().numpy() # [x1, y1, x2, y2] 坐标 confs r.boxes.conf.cpu().numpy() # 每个框的置信度 cls_ids r.boxes.cls.cpu().numpy() # 类别 id # 这一步先 print 出来看格式别急着接跟踪 print(frame_idx, boxes.shape, confs, cls_ids)conf0.35 是我在工地场景常用的开局值比官方的 0.25 高一点又比 0.5 低因为工地画面里小目标多、遮挡多阈值太高会把真目标过滤掉。saveTrue 能直接生成画好框的视频第一眼就能看出模型对安全帽、人这两类的基础识别能力。注意这一步只是骨架验证不要用一帧视频的视觉效果下结论后面避坑章会细说。2.3 接上 DeepSORT把检测框变成持续 IDYOLOv8 输出的是“这一帧有哪些目标”DeepSORT 要的是“持续的目标状态”。耦合方式每个项目略有差异我用的是 deep_sort_pytorch 这类开源实现核心代码就一段from deep_sort_pytorch.deep_sort import DeepSort deepsort DeepSort( model_pathdeepsort/ckpt.t7, # 特征提取模型 max_dist0.2, # 外观特征最大余弦距离越小越严格 min_confidence0.35, # 低于此置信度的检测不参与跟踪 nms_max_overlap1.0, # 检测框 NMS 阈值1.0 表示不额外做 NMS max_iou_distance0.7, # 卡尔曼预测与检测框的 IoU 阈值 max_age30, # 轨迹丢失后最多存活帧数 n_init3, # 连续 3 帧匹配才确认轨迹 nn_budget100, # 外观特征池大小限制内存 ) for frame_idx, r in enumerate(results): detections [] for box, conf, cls in zip(boxes, confs, cls_ids): x1, y1, x2, y2 box w, h x2 - x1, y2 - y1 detections.append(([x1, y1, w, h], conf, cls)) # 注意detections 格式是 xywh不是 xyxy outputs, _ deepsort.update(detections, frame) # frame 为当前帧 BGR 图 for track in outputs: track_id, x1, y1, x2, y2, cls, conf track # 在这里做业务逻辑统计没戴帽子的工人、记录轨迹、触发报警 draw_box_and_id(frame, track_id, x1, y1, x2, y2, cls, conf)这个耦合过程有两个细节必须说清。第一DeepSORT 对外接口要的是 xywh中心点加宽高YOLOv8 给的是 xyxy左上右下转换错了跟踪会全程错乱这是最常见的低级错误。第二update 函数内部会把检测框裁出来送进特征提取模型所以传入的 frame 必须和之前 predict 的是同一帧、同一分辨率任何缩放都要保持和训练时一致。2.4 两个必调的 DeepSORT 参数max_iou_distance 与 max_age调跟踪参数是最容易玄学的地方但大部分问题最后都落在这两个参数上。max_iou_distance 控制“位置上多近才算同一个目标”。工地场景工人密集、互相遮挡设得太小人一靠近 ID 就分裂设得太大两个并排走的人会被当成同一个。我的经验是从 0.7 起调逆光、夜间场景适当降到 0.6因为这个环境下卡尔曼本身的预测误差就大硬要抠 IoU 会把目标丢掉。max_age 控制一个轨迹在持续漏检后还能活多久。安全帽戴在头上人转身、低头检测框很容易中断一两秒。max_age30 意味着允许 30 帧不出现按 25 帧每秒算能撑约 1.2 秒。想统计“某个工人全程没戴帽”这个值不能太小但如果是高危区域闯入报警漏检久一点再触发反而更稳。这个参数没有标准答案全靠你业务上能容忍多久的“沉默”。还有一个隐藏坑DeepSORT 的特征模型 ckpt.t7 是在行人重识别数据集上训的它对“反光背心 安全帽”这类工地特征并不敏感。所以当你发现两个工人 ID 天天来回串不要先怀疑代码先意识到外观特征在工地场景的分辨力有限后面避坑章我会给具体的调法。3. 施工场景数据集开源数据、自建标注与格式转换的完整路径3.1 公开的工地安全数据集到底能覆盖什么标题里给了数据集但你要先分清数据集和数据集不一样。公开能搜到的安全帽数据集最常被提到的是 SHWD 和 GDUT-HWD 这一类主要覆盖安全帽佩戴检测类别一般就是“戴帽 / 不戴帽 / 人头”。这类数据的优点是干净、标注规范适合训练后跑通管线。缺点也很明显类别单一几乎没有反光背心、安全绳、危险区域围挡这些真正构成 construction workers 安全隐患的实体而且拍摄视角集中在固定摄像头缺少戴安全帽的近距离特写和夜间样本。所以我的建议是公开数据集只用来做预训练和 smoke test正式交付必须掺入现场数据。工地场景的泄露风险在于“数据分布歪”——白天样例太多、夜间样例太少晴天多、雨天少模型在 demo 视频里表现不错一装到现场就翻车就是这个原因。压缩包里的数据集也一样你得先统计它各类别的数量比例再来决定要不要补数据。3.2 类别怎么设计不要直接让模型输出“违规”很多第一次做这个方向的团队标注时直接标“违规”“未戴帽”最后模型既学不会也不稳定。我的一线经验是模型只负责检测对象和对象状态事件判断留给后处理逻辑。建议的类别设计是 person、helmet、vest 三个基础类最多再加 safety_glasses、warning_sign 这类静态标志物。业务规则在跟踪层写检测到 person 的框看框内有没有 helmet 的框与之重叠如果没有再结合轨迹持续帧数判定是否触发报警。这样做的原因是目标检测模型对“有帽 / 无帽”这种细粒度状态切换并不擅长——同一个安全帽正面算有帽低头时被遮挡算无帽模型会闪跳。把状态判断交给 IoU 重叠逻辑反而稳定得多。3.3 VOC 转 YOLO 格式转换脚本与四个边界坑不管你下载的数据集是 VOC 还是 COCOYOLOv8 训练前最终都得转成文本格式的 label。这里给出最常用的 VOC 转 YOLO 脚本注意看后半段的四个边界处理import os import xml.etree.ElementTree as ET from pathlib import Path CLASSES [person, helmet, vest] # 顺序即 YOLO 的类别 id def convert_voc(xml_path: str, out_dir: str) - None: tree ET.parse(xml_path) root tree.getroot() # 必须用 XML 里声明的主图尺寸不能自己猜 img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: continue # 边界坑 1类别不在列表里直接跳过但你要先确认是不是拼写不一致 bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 边界坑 2坐标越界。标注软件偶尔会给负数或超出图宽高的值 x1, x2 min(max(x1, 0), img_w), min(max(x2, 0), img_w) y1, y2 min(max(y1, 0), img_h), min(max(y2, 0), img_h) if x2 x1 or y2 y1: continue # 归一化YOLO 要的是中心点坐标加宽高 cx (x1 x2) / 2.0 / img_w cy (y1 y2) / 2.0 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h # 边界坑 3极端细长框或零点几像素的框会让损失函数“教歪”模型 if w 0.001 or h 0.001: continue lines.append(f{CLASSES.index(name)} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_txt Path(out_dir) / (Path(xml_path).stem .txt) out_txt.write_text(\n.join(lines)) # 边界坑 4转换完务必肉眼抽查 20 张图 # 把原图和 txt 一起画出来确认类别 id 没串位这个脚本的四个边界坑每一个我都踩过。坑 1 的典型表现是 label 里写的是 “helmet” 而 XML 里写的是 “Helmet”大小写不一致导致类别全部被跳过坑 2 的越界坐标如果不修YOLO 的 anchor 匹配会出问题损失曲线尾段一直抖坑 3 是工地特写镜头里安全帽占据整张图帽子太近反而被过滤掉。转换完成后强制自己抽查 20 张不要省这一步。3.4 数据增强的两条红线翻转与色彩抖动YOLOv8 训练默认开启 mosaic、flip、hsv 等增强很多人直接默认跑但工地场景有两个红线。第一条是水平翻转。安全帽左右对称翻转没问题但施工场地里的吊车、警示牌、机械是有方向性的翻转会破坏语义。我的做法是在数据配置文件里关掉 flip 增强或者只在 person 类别多的样本上允许翻转。第二条是色彩抖动。工地监控常见的是黄昏逆光、夜间灯光、雨天反光这些场景差异非常大。HSV 增强能让模型对颜色变化更鲁棒但不要指望它替代真实样本——安全帽在夜间是暗红色靠 HSV 增强把白天的亮红色抖动成暗色和真实夜间成像的噪声纹理完全不是一回事。真实夜间帧只能靠现场采集这是所有工地项目跑不掉的环节。4. 训练检测模型用 YOLOv8 训自己数据集的参数、损失曲线与导出验证4.1 环境配置与数据目录结构GTX 1660 Ti 也能跑YOLOv8 环境配置最常翻车的地方是 torch 和 CUDA 版本对不上。我的建议是直接按 ultralytics 官方要求装不要自己混装。常见配置是 Python 3.9 以上torch 2.xCUDA 11.8 或 12.x。用 GTX 1660 Ti 跑 YOLOv8 的工程师很多6G 显存跑 yolov8s、batch8、imgsz640 是现实可行的不要一上来就上 yolov8l。数据目录结构按 YOLOv8 的习惯组织dataset/ images/ train/ val/ labels/ train/ val/对应的 data.yaml 这么写train: dataset/images/train val: dataset/images/val nc: 3 names: 0: person 1: helmet 2: vest这里有个细节YOLOv8 会自动找 labels 目录只要图片放在 imageslabel 放同名 labels 即可。路径建议写相对路径避免换机器后盘符对不上。4.2 训练命令与五个必调参数训练命令本身很短参数才是决定成败的地方yolo detect train \ datadataset.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch8 \ workers4 \ device0 \ projectruns/train五个参数按优先级排参数建议值理由imgsz640 起步小目标多再上 1280imgsz 提高一倍显存占用翻四倍先跑通再调batch1660 Ti 用 8配 accumulate2等效 batch16 的梯度累积收敛更稳epochs120~200配合早停工地数据量小150 轮以内足够mosaic默认 1.0最后 10 轮自动关闭关闭时机由专项逻辑控制不用手动干预patience30连续 30 轮验证集没提升就早停省时间还有一个容易忽略的modelyolov8s.pt 表示加载预训练权重强烈建议保留这一步。工地数据量通常只有几千张从头训练效果远不如从 COCO 预训练权重微调。至于网上常说的“安全帽改进 YOLOv8”比如换注意力模块、改 neck那是后话先把 baseline 训明白再说。4.3 损失函数曲线图怎么看一眼识别训练翻车训练结束后runs/train/exp 下有个 results.csv把它画出来看是最直观的验收手段。用一段小脚本import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/train/exp/results.csv) # 列名是 train/box_loss, val/box_loss, metrics/precision(B) 等 fig, axes plt.subplots(2, 1, figsize(10, 6)) axes[0].plot(df[epoch], df[train/cls_loss], labeltrain_cls) axes[0].plot(df[epoch], df[val/cls_loss], labelval_cls) axes[0].set_xlabel(epoch) axes[0].legend() axes[1].plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) axes[1].set_xlabel(epoch) axes[1].legend() plt.tight_layout() plt.savefig(loss_curve.png, dpi150)读图的三个经验。第一train_loss 持续下降而 val_loss 不降甚至上升就是过拟合说明数据量不够或增强不够先回去补数据不要加正则硬撑。第二box_loss 从头到尾都降得很慢先检查数据格式有没有转错再确认 imgsz 是不是太小导致目标框相对变小。第三mAP50 在训练后期发生锯齿状抖动而不是平滑上升通常是标注里有脏数据——某个类别的框边界画歪了模型学到一半被带偏。4.4 训练好的模型导出与验证训练完成后项目里存的是 best.pt 和 last.pt这两个文件名字很直白best 是验证集最优last 是最后一轮。我一般建议用 best.pt因为 last 可能已经在过拟合区了。量化指标用验证命令得到yolo detect val datadataset.yaml modelruns/train/exp/weights/best.pt重点关注 mAP50 和 mAP50-95 两个值。工地场景实际使用时我更看重 mAP50因为业务上要的是“有帽还是没帽、有人还是没人”边界框不需要像素级精确。mAP50-95 是更苛刻的框精度指标它在小目标很多的数据集上会很难看不代表模型不能用。如果要部署到边缘设备还得导出成目标格式model YOLO(runs/train/exp/weights/best.pt) model.export(formatonnx, opset12, imgsz640) # 常用格式还有 torchscript、rknn经 onnx 转导出时固定 imgsz 很重要训练和推理尺寸不一致框会集体偏移这是部署时最容易忽略的坑后面的避坑章节专门讲。5. 避坑工地场景让检测跟踪翻车的五个典型问题排查记录5.1 现象同一工人 ID 从 3 变成 18安全帽状态统计全部错乱原因施工人员穿同款反光背心、戴同色安全帽外观特征极度相似DeepSORT 的特征区分能力失效加上工人经常一前一后走入画面遮挡让轨迹中断。解决先把 max_cosine_distance 从 0.2 降到 0.15要求外观更严格匹配再把 max_age 从 30 调到 40让轨迹更耐遮挡。如果 ID 还是乱就要考虑换跟踪器比如 ByteTrack 这类运动优先的方案在密集施工场景通常比 DeepSORT 稳。这个调整不是玄学它是在“外观可信度”和“运动连续性”之间给 DeepSORT 重设权重。5.2 现象白天 mAP50 有 0.85夜间只有 0.4人成了黑影安全帽完全看不见原因数据分布问题训集里几乎没有夜间样本。很多人期望靠 HSV 色彩增强硬拽回来实际效果很差夜间画面的噪声纹路和灯光光晕是增强模拟不出来的。解决去现场拍夜间监控帧这是绕不开的功课。夜间帧至少要占总量 30%并单独划分 val 集。另外一个临时手段是把推理的 conf 阈值降到 0.25结合 DeepSORT 的轨迹连续性来过滤误检但这是补救不是主方案。按血泪经验说夜间数据偷懒了交付时必然在客户现场翻车。5.3 现象画面中人高 80 像素安全帽只有 15 像素imgsz640 根本认不出帽子原因小目标在 640 分辨率下特征太少anchor 匹配困难。工地监控的球机往往架在高处这是个普遍问题。解决训练和推理统一用 imgsz1280显存不够就裁剪画面分区域推理。标注时安全帽的框要贴合帽檐不要框进半个脑袋否则模型学到的是“人头顶区域”而不是“帽子”。还有一个工程技巧把画面按 2x2 切块分别推理再合并结果虽然增加了计算量但对小目标召回提升非常明显。5.4 现象警示牌、反光衣被识别成“人”原因标注阶段正样本里没有足够多的“反例”模型没学过警示牌这类外观接近反光服的物体。另外如果标注时远处模糊的人全部被漏标模型会学到“模糊的目标不用报”推理时反而漏掉真目标。解决专门收集一批干扰物图片进负样本标注为空目录即可。更关键的是自建标注时把画面中所有可辨识的人全部标全不要选择性标注。标注不一致是训练集最隐蔽的毒药它不会立刻让 loss 爆炸但会让推理阶段的表现像抽签。5.5 现象模型在 PC 上正常部署到 RK3588 后框全偏速度只有 2 FPS原因YOLOv8 训练时自动做 letterbox把原图缩放到 640x640 正方形而部署时如果用 rknn-toolkit2 转换模型预处理端直接 resize 成 640x640破坏了宽高比框自然全偏。这是 yolov8 部署到 rk3588 最常见的坑。解决导出 ONNX 时固定 opset12 和 imgsz640转换 RKNN 时预处理必须复刻训练时逻辑先 letterbox 到 640x640再除以 255 归一化。速度慢就先量化到 int8但量化校准数据集要包含工地难例最好把夜间帧也放进去否则量化后的模型在夜间的损失比白天大得多。这一步没有捷径RNN 转换的每个环节都要对着训练时的预处理代码逐行核对。6. 别只盯 mAP上线前先做这三件事我踩过的坑希望你绕开模型在验证集上拿到好看的 mAP离能用的监控系统还差一大截。我自己的血泪经验是第一次做工地安全检测交付前花了半个月调 mAP结果客户一看现场回放就说“误报这么多谁敢用”。从那以后我强制自己上线前先做三件事。第一拿一段 30 分钟的真实监控回放做端到端评测指标换成事件级准确率。比如“未戴帽事件”不要逐帧算准确率而是看完整事件有没有被识别、事件里有没有夹着误报。逐帧指标会被大量“无目标帧”稀释看起来 99% 很漂亮实际上真正的危险事件一条没抓到。我一般把报警事件设计成同一轨迹连续 10 帧以上未检出安全帽重叠才判定为未戴帽事件。这就是把检测框升级成轨迹状态判断效果比任何模型改进都立竿见影。第二给报警加一个缓冲机制。检测模型单帧误检是常态如果每一帧都触发报警系统在密集人群里会疯狂刷屏。我在跟踪层做状态机首次触发后至少间隔 5 帧且轨迹持续存在才输出正式告警。这样既不漏报又过滤掉了单帧抖动。第三把帧率纳入验收标准。工地现场通常有多路摄像头一路 25 FPS 推理完全不够用。如果边缘设备跑不动可以隔帧检测、隔帧跟踪比如每 3 帧跑一次 YOLOv8剩余帧用卡尔曼预测补上实际感知效果损失很小。这个技巧我在 RK3588 上多次验证过比盲目换轻量模型有效。这三个习惯我不再改回来了。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑