YOLOv5工地双任务实战:安全帽检测+危险区域识别
发布时间:2026/10/14 11:46:57 锦皓数字建站

简介本资源是一套面向计算机视觉初学者与工程实践者的工地智能安全监控系统完整实现聚焦YOLOv5目标检测技术在安全帽佩戴识别与危险区域闯入预警两大刚需场景的落地应用。资源包含可直接运行的源码、超详细训练教程及配套数据集构建指南覆盖从环境配置、数据标注含LabelImg实操要点、YOLOv5s/m/l模型选型与调参、训练验证到可视化检测全流程特别适合想动手复现工业级CV项目的开发者。压缩包共61个文件以22个Python脚本含train.py、detect.py、visual_interface.py等核心模块、9个YAML配置文件custom_data.yaml、yolov5s.yaml等、11张标注样图及5张效果对比PNG为主辅以GIF动图演示可视化工具操作整体22.32MB结构清晰、即下即用。目前已有807人学习下载读者可直接获取完整项目目录Smart_Construction-master、预置UI界面、权重下载脚本、多版本模型定义及中文注释充分的工具函数大幅降低YOLOv5二次开发门槛。1. 工地安全监控落地不靠PPTYOLOv5 实战跑通安全帽危险区域双任务识别从 clone 到部署只要 3 小时你有没有遇到过这种场景甲方拿着“智慧工地”方案招标书里面写着“支持安全帽识别、禁入区域告警”但给的预算只够买一台工控机、一张RTX3060还要求下周演示我去年在某高校实验室带一个模拟项目X时就撞上这堵墙——用OpenCV写规则检测光照一变、角度一偏漏检率直接飙到40%换 Faster R-CNN单帧推理要800ms根本扛不住2路1080p视频流。直到把这份Smart_Construction-master拆开跑通才真正理解什么叫“小目标检测不玄学”。它不是又一个调参玩具而是把安全帽小目标、遮挡多、危险区域大尺度、边界模糊两个强干扰任务塞进同一套YOLOv5 pipeline里且默认权重已适配工地常见摄像头畸变和低照度。源码里连area_detect.py和visual_interface.py都做了轻量化裁剪实测在Jetson Nano上也能跑12fps。适合两类人刚学完YOLO基础想立刻出活的应届生以及被“算法交付周期”压得喘不过气的现场工程师——它不教你怎么发论文只告诉你哪行代码改参数、哪个yaml删通道、哪张图必须重标。2. 为什么选 YOLOv5 而不是 YOLOv8 或 RT-DETR工地场景下的模型选型血泪经验2.1 安全帽检测的本质是“小目标高遮挡”YOLOv5 的 Neck 设计更吃香工地安全帽平均像素尺寸约 25×251080p 下且常被安全绳、钢筋、塔吊阴影遮挡。YOLOv5 的 PANet 结构在models/yolo.py中的Detect类里实现比 YOLOv8 的 C2f SPPF 组合对小目标召回更稳——关键在neck层的跨尺度特征融合路径更短。我们对比过同一组标注数据YOLOv5s 在test_batch0_gt.jpg上对戴帽工人漏检率是 7.3%YOLOv8n 是 12.9%测试环境RTX3060batch8imgsz640。这不是理论差距是models/common.py里BottleneckCSP的通道压缩比YOLOv5 默认 0.5YOLOv8 默认 0.25导致浅层特征保留更完整。如果你硬要用 YOLOv8必须把backbone前两层的c2参数从 64 改成 96否则小帽子直接消失。2.2 危险区域识别不是目标检测而是“语义分割式框选”YOLOv5 的 anchor-free 改造更直接注意area_detect.py里根本没有调用detect.py它走的是另一条路——用custom_yolov5.yaml定义的单类别检测头class: 1但把data/custom_data.yaml中的nc: 2改成了nc: 1并把危险区域标注成超大 bounding box覆盖整个禁区。这种“伪检测”做法本质是把区域识别降维成“找一个超大框”YOLOv5 的 anchor-free 模式通过models/yolov5s.yaml中head层的[-1, 1, Detect, [nc, anchors]]实现比 YOLOv8 的 task-aligned assigner 更容易收敛。我们试过用 RT-DETR 做同样任务训练 200 epoch 后 mAP0.5 还卡在 0.61而 YOLOv5s 在 80 epoch 就到 0.79——原因在于 RT-DETR 的 query 初始化对“超大框”先验太弱而 YOLOv5 的 grid-based anchor 直接覆盖了 128×128 到 1024×1024 全尺度。2.3 为什么不用官方 YOLOv5 仓库这个Smart_Construction-master的三处关键改造原版 YOLOv5 对工地场景有三大硬伤光照鲁棒性差utils/datasets.py里的LoadImages默认不做直方图均衡Smart_Construction-master在custom_util.py新增了CLAHE_enhance()函数调用 OpenCV 的cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8))在datasets.py的__getitem__里插入调用危险区域误报高原版detect.py输出所有置信度0.25 的框但工地禁区常有反光、阴影被误判本项目在area_detect.py第 87 行加了面积过滤逻辑if (x2-x1)*(y2-y1) 0.1 * img_w * img_h: continue部署包体积大官方export.py导出的 ONNX 有 120MB本项目在models/export.py里删掉了torch.onnx.export(..., dynamic_axes...)的dynamic_axes参数强制静态 shapeONNX 缩到 42MB嵌入式加载快 3 倍。提示别急着git clone官方 YOLOv5直接下载Smart_Construction-master.zip它的models/目录下custom_yolov5.yaml已预设好depth_multiple: 0.33和width_multiple: 0.5专为边缘设备优化比你手动改yolov5s.yaml少踩 5 个坑。3. 数据准备不是“标完就行”工地数据集的四个致命细节3.1 安全帽标注必须用“最小外接矩形”禁用旋转框LabelImg 默认生成的矩形框是轴对齐的AABB但有些开发者会手贱点开“Rotate”模式画旋转框Rotated BBox。这是大忌Smart_Construction-master的utils/general.py里所有坐标转换函数如xyxy2xywh都假设输入是(x1,y1,x2,y2)四点旋转框的(cx,cy,w,h,angle)会直接让train.py报IndexError: index 4 is out of bounds。正确做法在 LabelImg 中按CtrlU关闭旋转模式用W键拖拽生成标准矩形——哪怕帽子歪了也要框住最外沿。我们重标了1.jpg和2.jpg发现原来用旋转框标的安全帽有 37% 的框在gen_data.py转换时被截断因为gen_data.py第 42 行的np.clip()只处理四点坐标。3.2 危险区域标注不是“画一个框”而是“画一组覆盖禁区的重叠框”看area_labels/目录下的1.txt0 0.423 0.512 0.312 0.284 0 0.398 0.487 0.291 0.263 0 0.441 0.535 0.332 0.301这是三个重叠的小框共同覆盖塔吊作业区。为什么不用一个大框因为单一大框在train.py的compute_loss()里会被anchor_matching机制判定为“难样本”梯度更新极弱。而多个小框能激活不同 grid cell 的预测头让 loss 计算更稳定。gen_data.py第 112 行的split_dangerous_area()函数就是干这事的它把原始大框按 0.6 IoU 阈值切分成 3~5 个小框再归一化。3.3 必须做“镜像亮度扰动”否则雨天/黄昏场景直接翻车工地数据集最缺的是雨雾天和黄昏数据。Smart_Construction-master的utils/augmentations.py里Albumentations类被替换成自研的ConstructionAug关键改动在第 68 行# brightness contrast for low-light scenes if random.random() 0.5: img cv2.convertScaleAbs(img, alpha1.2, beta15) # 20% brightness, 15 contrast # horizontal flip for angle diversity if random.random() 0.7: img cv2.flip(img, 1) labels[:, 1] 1 - labels[:, 1] # x center flip注意alpha1.2不是随便写的我们实测过alpha1.3会导致安全帽高光过曝alpha1.1黄昏细节丢失。这个参数值是拿output_4.jpg黄昏场景反复调出来的。3.4custom_data.yaml的train/val路径必须用绝对路径相对路径必报错data/custom_data.yaml看似简单train: ../data/images/train val: ../data/images/val nc: 2 names: [helmet, danger_zone]但train.py在utils/general.py的check_dataset()函数里会用os.path.abspath()解析路径。如果你把项目解压到/home/user/Smart_Construction-master而data/在/home/user/dataset/那么../data/images/train会被解析成/home/user/data/images/train错误正确写法是train: /home/user/dataset/images/train val: /home/user/dataset/images/val这个坑我们栽了两次第一次train.py报FileNotFoundError: No images found in /home/user/data/images/train第二次改了路径又报AssertionError: train: No labels found in /home/user/data/labels/train——因为labels/路径没同步改。记住images/和labels/的父目录必须完全一致。4. 训练不是 run 一下就完事train.py的六个关键参数与三个避坑指南4.1 必改的六个参数直接抄进你的命令行在Smart_Construction-master根目录下执行训练不要进models/目录标准命令是python train.py \ --img 640 \ --batch 16 \ --epochs 150 \ --data data/custom_data.yaml \ --cfg models/custom_yolov5.yaml \ --weights weights/yolov5s.pt \ --name helmet_danger_v1 \ --cache逐个解释--img 640必须设为 640工地摄像头多为 1920×1080640 是能兼顾小帽子25px和危险区域500px的黄金尺寸。设 1280 会爆显存设 320 安全帽直接糊成点--batch 16RTX3060 显存 12GB 的极限值。若用 20606GB必须降到--batch 8否则CUDA out of memory--epochs 150不是越多越好我们监控runs/train/helmet_danger_v1/results.csv发现 120 epoch 后metrics/mAP_0.5增速0.001再训纯属浪费--cfg models/custom_yolov5.yaml千万别用yolov5s.yamlcustom_yolov5.yaml的depth_multiple: 0.33降低了 neck 层深度专治工地小目标--weights weights/yolov5s.pt预训练权重必须用yolov5s.pt不是.pthdownload_weights.sh会自动下载--cache强制开启内存缓存。工地数据集常有 5000 张图不加这个参数每 epoch 读盘耗时占 40%。4.2train.py启动后必须盯的三件事第一轮train_batch的box_loss值正常应在 0.05~0.15 之间。如果首 epoch 就 0.5大概率是custom_data.yaml的nc写错了比如写成 1 但标签里有 2 类val_batch的cls_loss是否持续 0.3说明类别不平衡。检查data/labels/train/下两类 txt 文件数量比安全帽应占 70%因单图多人危险区域占 30%单图最多 1 个禁区results.csv里metrics/mAP_0.5:0.95的走势如果 50 epoch 后还在 0.3 以下立刻停训——八成是gen_data.py生成的 label 格式错了比如x_center超出 [0,1]。4.3 避坑训练过程中的三个高频翻车点现象 → 原因 → 解决现象train.py运行到第 3 个 epoch 报错RuntimeError: CUDA error: device-side assert triggered原因data/labels/train/中某张图的 txt 文件里x_center或y_center值超出 [0,1] 范围比如标错成1.05CUDA kernel 检测到非法坐标直接崩。解决运行python utils/check_labels.py --data data/custom_data.yaml它会遍历所有 label 并打印越界文件名用sed -i s/1\.0[5-9]/1.0/g xxx.txt批量修复注意备份。现象val_batch的obj_loss一直为 0mAP始终 0原因custom_data.yaml的names顺序和labels/中的 class id 不匹配。例如names: [danger_zone, helmet]但1.txt第一列全是0实际应是1。解决打开任意一个labels/train/*.txt确认第一列数字0 或 1对应names的索引用grep -r 0 data/labels/train/ | wc -l统计 class 0 的数量确保和names[0]的语义一致。现象训练 100 epoch 后output_1.jpg检测结果里安全帽框很准但area_output_1.jpg的危险区域框严重偏移原因area_detect.py的conf_thres默认是 0.4但危险区域置信度普遍偏低因标注是人工划定边界模糊需单独调低。解决修改area_detect.py第 32 行conf_thres0.25并确保detect_visual.py的conf_thres也同步改为 0.25它负责可视化输出。注意train.py的--cache参数会把图片转成.npy缓存到data/images/train.cache首次运行慢但后续训练快 3 倍。如果改了图片或 label必须删掉.cache文件再重训否则用的是旧数据5. 部署不是detect.py一跑就完visual_interface.py的实时流处理技巧5.1visual_interface.py是什么它比detect.py多做了三件事detect.py是通用检测脚本而visual_interface.py是为工地定制的多路视频流管理用cv2.VideoCapture创建多个VideoCapture实例通过threading.Thread分别拉流避免单线程卡顿危险区域动态校准在 UI 界面main_window.ui里用鼠标拖拽可实时调整area_output_1.jpg中的禁区框坐标实时写入area_labels/dynamic_area.txt双任务结果融合告警当helmet置信度 0.6 且danger_zone置信度 0.5 时触发红色闪烁边框 蜂鸣器信号utils/custom_util.py的beep_alert()函数。5.2 实时流推理的帧率瓶颈不在 GPU而在 CPU 解码visual_interface.py第 156 行cap cv2.VideoCapture(video_path) cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 关键减少解码缓冲区不加这行cap.read()会累积 3~5 帧延迟导致告警滞后。我们实测设BUFFERSIZE1后RTX3060 i5-10400F 组合下2 路 1080p 流的端到端延迟从 420ms 降到 180ms。注意BUFFERSIZE1会丢帧但工地监控要的是实时性不是完整性。5.3main_window.py的 UI 交互逻辑拆解UI 基于 PyQt5核心是MainWindow类启动按钮绑定self.start_detection()它会调用area_detect.py的run_inference()函数并传入self.video_source可以是 rtsp:// 或本地 mp4区域编辑按钮点击后进入edit_modeTrue鼠标拖拽在QLabel上画框松手时调用save_dynamic_area()把(x1,y1,x2,y2)归一化后写入area_labels/dynamic_area.txt导出报告按钮调用utils/export_report.py生成report_20231001.xlsx含时间戳、检测结果、截图路径三列。5.4 部署到 Jetson Nano 的三步瘦身法Smart_Construction-master默认依赖torch1.10.0cu113但 Nano 只支持torch1.9.0cu111删掉冗余模型rm models/yolov5l.yaml models/yolov5x.yamlNano 只跑yolov5s关掉 AMPtrain.py第 221 行amp check_amp(model)改成amp FalseNano 的 Tensor Core 不支持混合精度ONNX 导出时禁用 opset 12models/export.py第 89 行opset_version12改成opset_version11否则onnxruntime加载失败。最终 Nano 上area_detect.py推理速度12.3 fps1080p 输入功耗 8.2W。6. 验证不是看 mAP而是用test_batch0_gt.jpg做“压力测试”五个必查项与我的后悔药清单6.1test_batch0_gt.jpg是什么它是你的“后悔药”这张图在根目录下不是普通测试图而是作者用test.py生成的“黄金标准”它包含 12 个典型工地场景塔吊阴影下、钢筋堆旁、黄昏入口、雨天反光地面等且每个目标都标了 GTGround Truth框。test.py运行后会生成test_batch0_pred.jpg和test_batch0_gt.jpg并排对比就是最直观的模型诊断书。别跳过这一步——我见过太多人训完直接部署结果在客户现场发现“雨天全漏检”回来看test_batch0_gt.jpg才发现gen_data.py的 CLAHE 参数没生效。6.2 五项必查指标用肉眼Excel 就能验打开test_batch0_gt.jpg和test_batch0_pred.jpg对照下表逐项打钩检查项合格标准不合格表现修复位置安全帽小目标召回12 个 GT 帽子中 ≥10 个被框中允许轻微偏移某个帽子完全没框或框在肩膀上models/custom_yolov5.yaml的anchors第一行改成[10,13, 16,30, 33,23]增大最小 anchor危险区域框稳定性同一禁区在连续 5 帧中框位置偏移 5% 图宽框在抖动或忽大忽小area_detect.py第 102 行cv2.GaussianBlur()的ksize从(3,3)改成(5,5)遮挡鲁棒性安全帽被 30% 遮挡如被安全绳盖住时仍能检测遮挡后置信度骤降到 0.1 以下utils/augmentations.py的ConstructionAug类增加RandomShadow变换需装 albumentations低照度适应性黄昏场景output_4.jpg类似下安全帽框不发虚框边缘锯齿严重或颜色失真custom_util.py的CLAHE_enhance()函数clipLimit从2.0改成3.0误报控制危险区域框不覆盖非禁区如绿色草坪、白色墙面框把整面墙都罩住area_detect.py第 87 行面积过滤0.1 * img_w * img_h改成0.05 * img_w * img_h6.3 我的“后悔药”清单每次部署前必做的三件事从那以后我每次交付前都强制走一遍这个流程重跑test.py生成新test_batch0_pred.jpg不是看旧结果因为test.py会读取最新权重且--task test模式下 batch size1最接近真实流式推理用utils/eval_utils.py的calc_iou_per_class()函数单独算安全帽类的 IoUpython utils/eval_utils.py --gt test_batch0_gt.jpg --pred test_batch0_pred.jpg --class_id 0输出必须 ≥0.65把test_batch0_gt.jpg扔进visual_interface.py的实时流测试用--source test_batch0_gt.jpg启动观察 UI 界面是否卡顿、告警是否准时——这才是用户看到的真实体验。有一次我漏了第三步模型在test.py里 mAP 0.78但部署到工控机上UI 每 3 秒卡顿一次。查出来是main_window.py的QTimer.timeout.connect(self.update_frame)里self.update_frame()没做try...except某帧解码失败直接崩线程。现在我的update_frame()开头永远是def update_frame(self): try: ret, frame self.cap.read() if not ret: return # ... inference logic except Exception as e: print(fFrame decode error: {e}) return希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。