资讯动态

YOLOv5+PyQt5实现智慧工地安全帽检测与危险区域入侵告警系统

发布时间:2026/9/1 0:21:08 来源:尧图企业网站定制
简介本资源是一套面向计算机及相关专业在校学生、教师与工程技术人员的智慧工地安全监管实战项目聚焦施工场景下的安全帽佩戴识别与危险区域入侵告警两大核心需求融合YOLOv5目标检测与PyQt5桌面GUI开发技术兼具毕设、课设与工程原型验证价值。压缩包共2000个文件含406张标注图像jpg、743份XML标注及对应TXT标签文件、49个Python主程序与配置脚本py/yaml、49个模型权重与训练配置文件以及部署说明、操作文档等整体大小236.04MB。已有4147人学习下载项目代码经实测可直接运行GUI界面支持按钮自定义与危险区域手动绘制入侵触发实时弹窗声音告警配套文档详述数据准备、模型训练、界面交互逻辑与部署流程目录结构分层清晰便于新手入门与二次开发拓展。1. 工地安全从“人盯人”到“算法盯人”这套系统解决的真实问题做智慧工地项目之前我一直在想一个问题工地上那么多摄像头一天24小时录着真正起到安全监管作用的有多少答案很残酷——大部分摄像头只是“事后查监控”的工具事故发生之后调出来看看谁干了什么但事故本身并没有被阻止。安全帽佩戴检测和危险区域入侵检测就是要解决这个“事前预防”的问题。传统做法是安全员现场巡查一个工地几万平方米巡查一圈半小时期间哪个角落有人摘了帽子、哪个吊装区有人误闯根本看不过来。而视觉检测算法的优势在于它不疲劳、不眨眼、不偷懒可以同时盯住十几个甚至几十路画面一旦发现违规行为立刻截图、录像、告警。这个项目选用YOLOv5做目标检测PyQt5做桌面端GUI整体是“Python生态全家桶”的思路。YOLOv5在工业级落地中属于性价比很高的选择——推理速度快、训练生态成熟、社区资料多部署到普通工控机上跑实时视频流完全没压力。PyQt5则负责把“算法能力”包装成一个普通人能操作的软件打开界面、选择摄像头、点击开始检测结果实时显示告警自动弹出。整套系统跑通之后工地安全员只需要看屏幕上的告警信息就行不用再一段一段翻录像。无论你是想把计算机视觉技术落地到实际项目里的开发者还是正在做毕业设计、找工作项目的学生这篇文章都会把从数据集整理到模型训练再到界面开发的完整链路讲清楚包括我实际开发中踩过的坑和调优思路。2. 数据集整理比模型结构更决定上限安全帽数据的收集与标注细节很多人在目标检测项目里最容易犯的错是一上来就研究模型结构、调整网络参数结果数据一塌糊涂训练出来的模型自然没法用。目标检测领域有一句话垃圾进垃圾出。模型结构再好训练数据质量不行检测效果一定拉胯。2.1 数据类别设计比想象中更需要细想安全帽佩戴检测看似是一个“戴了/没戴”的二分类问题实际操作中我强烈建议做成三分类——甚至四分类。项目源码里提供的标注类别通常是helmet正确佩戴安全帽head头部裸露未佩戴安全帽但我个人在复现和扩展时更喜欢加入一个person类别。原因很简单如果只有head这一个类别那么模型会把画面中所有“人”的头部都识别出来——包括手、胳膊、身体其他部位被误检成头的情况会明显变多。有了person类别作为上下文参照告警逻辑可以写成“检测到person但对应的head区域没有helmet”误报率会明显下降。如果是真实工地场景还建议考虑增加类别说明helmet带安全帽的头部head没带安全帽的头部person完整人体辅助判断safety_vest反光背心可选工地上通常和安全帽同时要求2.2 数据来源与采集策略源码压缩包里通常附带了一份标注好的数据集但如果你需要针对自身工地场景重新训练数据的来源主要有三个途径第一公开数据集。SHWDSafety Helmet Wearing Dataset是用的比较多的开源安全帽数据集包含约7500张图片、9000多个标注实例覆盖了大部分常见角度和场景。GDUT-HWD也是不错的选择尤其是俯视角度和远景小人物的图片较多这个特点对工地场景特别重要——因为摄像头通常装在塔吊、围挡顶部是从上往下看的视角。第二工地实拍。这个方法效果最好但获取成本高。实际操作中可以让工地安全员用手机拍摄不同时间段、不同天气、不同工位的照片每段视频抽帧成图片。有个小技巧从视频中抽帧的时候不要连续抽而是每隔10到20帧抽一张这样能避免相邻图片几乎一模一样导致训练集和验证集“近亲繁殖”。第三现场摄像头录像截取。如果工地已经有监控系统把不同摄像头的录像各取几段抽帧后筛选。这个方式的优点是视角和最终部署时的视角完全一致模型上线后的表现会非常稳定。2.3 标注工具与质量把控标注工具我用的是LabelImg和X-AnyLabeling。LabelImg是老牌工具轻量、稳定、导出YOLO格式的txt很方便。但它的缺点是标注效率偏低。如果你手上的图片数量超过5000张建议用X-AnyLabeling——它内置了SAM分割模型可以辅助标注框选效率能提升一倍左右。标注的时候有几个关键的细节值得注意遮挡情况一定要标。工地画面里人挨着人、安全帽互相遮挡是很常见的框体被遮挡的部分该框就框不要因为看不见完整目标就跳过。模型靠边缘特征也能学习到目标的存在。远景小人头不要放过。摄像头俯视视角下人很小只有二三十个像素这种样本一定得留够比例。否则模型在远处小目标上的漏检率会很高。标注框的紧密程度要统一。尽量让标注框紧贴目标边缘不要留太多空白也不要裁掉目标本身。很多人标着标着就“放飞自我”框的大小忽大忽小模型学习的时候会被搞糊涂。2.4 数据增强的策略数据增强这块我建议优先做的是马赛克增强Mosaic和随机仿射变换。YOLOv5里的Mosaic增强会把4张图拼成一张训练对小目标的检测能力提升很明显——因为它相当于把图片缩小了模型被迫学习去识别更小的目标。但有一个坑不要一开始就把增强参数拉满。我遇到过的情况是增强太猛之后模型在训练集上的损失降不下去验证集上的mAP也上不来。后来把增强概率从默认值往下调了30%效果就正常了。一个合理的做法是先用默认参数训练50轮看loss曲线是否正常下降如果正常再逐步把增强概率调高做对比试验。训练集样本越多增强强度可以越高样本少的时候增强太猛会让模型学到很多“假特征”。3. YOLOv5训练环境配置、超参数调整与踩坑复盘YOLOv5虽然被人吐槽“学术创新点不够”但在工程落地这个维度上它确实非常省心——配置简单、训练稳定、部署资料多。下面我把从零跑通到训练自己数据的完整过程整理出来。3.1 环境安装里最容易被卡住的三个地方在Windows环境下安装YOLOv5官方仓库的依赖时最常遇到的问题是torch和torchvision版本不匹配。很多人一上来就pip install torch装的是CPU版本或者和CUDA版本对不上的版本结果训练速度慢到怀疑人生。我的建议是直接去PyTorch官网的Get Started页面按照你的CUDA版本选择对应的安装命令。比如CUDA 11.8对应的命令是pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118安装完验证一下GPU是否可用import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))只要能输出True和你的显卡型号就说明环境没问题。这里还得提一句很多压缩包里附带的requirements.txt是半年前甚至一年前的版本直接装容易和最新的PyTorch版本冲突。稳妥的做法是先装PyTorch再装其他依赖如果出现版本冲突优先升级或降级opencv-python、numpy、matplotlib这几个常出问题的库。3.2 训练自己数据集的完整流程假设你已经按照源码包里的目录结构整理好了数据YOLOv5训练自己数据的标准流程是在data/目录下建一个helmet.yaml内容如下train: data/helmet/train/images val: data/helmet/val/images nc: 3 names: [helmet, head, person]确保labels目录和images目录同级YOLO格式的标注txt文件和图片文件名一一对应。下载预训练权重我推荐用yolov5s.pt起步——速度和精度的平衡点上s版本是最稳的python train.py --data helmet.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --device 0训练结束后在runs/train/exp/weights/目录下找到best.pt和last.pt其中best.pt是验证集上表现最好的权重后续部署推理用的是这个。训练时有个参数--cache值得说一下。如果你的内存够大16G以上加上--cache ram可以把图片缓存到内存里训练速度会有一个质的提升。数据量大的时候磁盘IO往往是训练瓶颈--cache直接绕过了这个问题。3.3 超参数调整思路YOLOv5自带的超参数文件data/hyps/hyp.scratch-low.yaml对大多数情况都够用但对安全问题这种需要极低漏检率的场景有几个参数值得单独调整。fl_gammaFocal Loss的gamma值默认是0.0也就是不使用Focal Loss。如果你的场景中远景小人头特别多把fl_gamma调到1.5左右能有效降低小目标漏检。这个参数调整的本质是让模型更关注难分类的样本——那些模糊的、微小的、部分遮挡的目标。hsv_h、hsv_s、hsv_v颜色增强安全帽的颜色在工地上相对固定黄色、红色、蓝色、白色但不同光照条件下颜色偏移很严重。把hsv_h从默认的0.015调高到0.03hsv_s从0.7调到0.8模型对光线变化的适应能力会明显增强。anchor尺寸是另一个值得关注的点。如果训练时日志里频繁出现“anchors are not a priority”的提示就说明默认锚框尺寸和你的数据集目标尺寸差距较大。可以在train.py里加上--noautoanchor参数手动调用python train.py --data helmet.yaml --weights yolov5s.pt --img 640 --noautoanchor让程序自动基于你的数据集重新计算锚框第一次会先跑一遍聚类分析。3.4 训练过程中最值得注意的三个信号第一个是过拟合信号训练集loss持续下降但验证集loss在某个epoch之后开始回升说明模型开始“背答案”了。解决办法是增加数据增强强度、增加数据量、或者提前停止训练。第二个是mAP波动如果验证集的mAP曲线像心电图一样上下乱窜大概率是验证集图片数量太少或者不同类别的样本数量严重不均衡。比如helmet有一万张而head只有一千张模型就会严重偏向helmet这个类别。可以考虑对head类别做过采样复制或者在loss函数里给少数类加上权重。第三个是类别混淆训练完一定要看confusion_matrix.png和results.png这两张图。如果head和helmet之间有大量互相混淆说明标注的时候边界不清晰——有些图里半遮挡的头部不同标注员可能一个标成helmet一个标成head。这类标注歧义问题需要在数据集层面重新梳理而不是继续调参。4. PyQt5界面开发把模型能力封装成安全员能上手的工具模型训练好了只是完成了工程的一半。算法输出的是一串坐标和置信度安全员不可能去看命令行输出。PyQt5在这里的角色就是把“检测能力”变成“人机交互工具”——打开程序、选摄像头、点开始、看结果、收告警。4.1 界面布局的取舍项目源码的GUI界面通常是这样的整体结构我建议按功能区块来理解和设计┌─────────────────────────────────────────────┐ │ 标题栏智慧工地安全检测系统 │ ├───────────────┬─────────────────────────────┤ │ │ 检测结果信息栏 │ │ 视频显示区域 │ - 当前检测人数 │ │ (核心画面) │ - 未戴安全帽人数 │ │ │ - 危险区域入侵告警状态 │ ├───────────────┴─────────────────────────────┤ │ 控制按钮区选择视频源 | 开始检测 | 停止 | 截图 │ │ 日志信息区实时打印检测与告警事件 │ └─────────────────────────────────────────────┘视频显示区要占界面面积的60%以上因为安全员盯着屏幕的主要目的是实时观察画面信息栏是辅助。如果信息栏做得太宽画面被压缩变形反而影响观察。4.2 视频流接入与推理循环视频源的接入我推荐用OpenCV的VideoCapture它同时支持摄像头RTSP流、本地视频文件和USB摄像头接口统一不用改逻辑import cv2 from PyQt5.QtCore import QThread, pyqtSignal class VideoThread(QThread): change_pixmap_signal pyqtSignal(object) def __init__(self, video_source0): super().__init__() self.video_source video_source self._run_flag True self.model torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadFalse) self.model.conf 0.45 self.model.iou 0.45 def run(self): cap cv2.VideoCapture(self.video_source) while self._run_flag: ret, frame cap.read() if ret: results self.model(frame) annotated_frame results.render()[0] self.change_pixmap_signal.emit(annotated_frame) else: break cap.release()这部分有两个细节值得提醒推理放在QThread里绝不能在主线程做。否则模型单帧推理的几百毫秒会卡死整个GUI界面表现为“窗口未响应”。用QThread把视频采集、模型推理和UI刷新拆成不同线程界面才会流畅。模型加载只做一次。我看到很多新手把模型加载写在了每一帧的处理逻辑里相当于每帧都重新读取一次权重文件速度慢得离谱。模型应该是程序启动时加载一次之后所有帧共用这同一个模型实例。4.3 检测结果实时叠加与告警联动检测结果要在原画面上实时画框可以直接用YOLOv5的results.render()方法它会自动在图像上绘制检测框、类别标签和置信度。但如果你想做更精细的控制比如“戴了安全帽画绿框、没戴画红框”就需要自己解析检测结果results self.model(frame) boxes results.xyxy[0].cpu().numpy() for box in boxes: x1, y1, x2, y2, conf, cls_id box label self.model.names[int(cls_id)] if label helmet: color (0, 255, 0) elif label head: color (0, 0, 255) # 触发告警逻辑 alert_signal.emit(未佩戴安全帽) else: color (0, 255, 255) cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), color, 2)告警联动这里有个我强烈建议的优化告警不能单帧触发。模型偶尔会有一次误检比如把安全帽后面的背景纹理误判为裸露的头部如果每一帧都触发告警系统会频繁刷屏最终安全员会直接忽略所有告警——这就和系统建设的初衷背道而驰了。我的做法是引入一个“连续帧确认”机制ALERT_THRESHOLD 5 # 连续5帧出现未戴帽才算告警 unhelmeted_count 0 if no_helmet_detected: unhelmeted_count 1 if unhelmeted_count ALERT_THRESHOLD: trigger_alert() else: unhelmeted_count 0这样设置之后偶尔的一帧误检会被自动过滤而真正的持续违规行为能在0.2秒左右被确认并告警既保证了及时性又保证了准确性。5. 危险区域入侵检测从“人来了”到“人违规了”的判定逻辑危险区域入侵检测是智慧工地系统的另一个核心功能。塔吊回转半径、基坑边缘、爆破作业区、临时用电区这些地方普通工人误入的后果非常严重。而“进入危险区域”和“在危险区域附近”是两个不同的概念算法必须能精确区分。5.1 实现路径一基于检测框坐标的区域判定这是最简明的做法也最适合快速落地。原理是人力在GUI界面上预先画好危险区域的多边形通常是矩形然后检测到person之后判断人的位置是否落在多边形内部。用代码来表达就是这样import cv2 # 在视频画面中标记危险区域例如矩形 danger_zone [(300, 200), (800, 200), (800, 600), (300, 600)] def is_in_danger_zone(person_bbox, danger_zone): # person_bbox: [x1, y1, x2, y2] # 取检测框底部中心点作为人站立的位置 x_center (person_bbox[0] person_bbox[2]) // 2 y_bottom person_bbox[3] point (x_center, y_bottom) return cv2.pointPolygonTest( np.array(danger_zone, dtypenp.int32), point, False ) 0这里有个关键的工程细节为什么用“检测框底部中心点”而不是“检测框中心点”因为在实际物理空间中一个站着的人其脚底位置才是他真正“所在的位置”。检测框中心点大致在胸口高度如果危险区域是基坑边缘人在边缘外部但身体前倾检测框中心点可能已经越过警戒线进入区域内部这就造成了误报。用脚底点判断更符合物理直觉误报率会低很多。5.2 实现路径二像素级区域分割如果工地现场有固定的电子围栏可以通过摄像头标定的方式把围栏区域映射到像素坐标系中。这种方式比手动画矩形更精准但需要一次性做相机标定操作复杂度高并且摄像头一旦移位标定结果就失效了。对于入门项目和实际工期紧张的项目手动画矩形区域的方法完全够了这也是源码包里默认提供的方式。你只需要在界面上增加一个“配置危险区域”的交互点几个点连成一个闭合多边形保存到配置文件里之后所有帧都复用这个区域配置。5.3 告警去重与事件记录入侵告警如果处理不好会比安全帽告警更容易“刷屏”。人站在危险区域里无论是停留还是路过不应该每帧都触发一次告警。我的做法是为每个目标维护一个“告警状态机”目标进入区域 → 第一次触发告警记录时间戳和截图目标停留在区域内 → 不重复告警但每5秒更新一次“持续停留”日志目标离开区域 → 记录离开时间关闭告警状态这个逻辑实现起来不复杂用一个字典维护每个目标的tracking ID对应的状态即可。或者如果不想做目标追踪可以用一个更取巧的办法对同一区域设置一个告警冷却时间比如10秒内同一区域只触发一次告警冷却期内即使检测到入侵也不再弹窗但会在日志中记录。5.4 两条检测逻辑的联动效果当安全帽检测和危险区域入侵检测同时运行时系统的判定逻辑可以叠加出更智能的规则。比如检测到人员进入危险区域且该人员未佩戴安全帽 → 最高级别告警立即弹窗蜂鸣检测到人员进入危险区域但已佩戴安全帽 → 中等级别告警仅记录日志并弹窗检测到未戴安全帽但人不在危险区域 → 普通告警记录日志这种分级告警策略在实战中非常有用。安全员不需要对所有告警都做出同等紧急的反应分级之后真正危险的情况会立刻引起注意常规违规则汇总批量处理。这个逻辑用if-else判断嵌套就能实现不涉及复杂的算法但业务价值提升非常明显。6. 部署环境与源码包使用指南拿到项目后先做什么、再做什么最后这部分写给拿到源码包准备跑起来的朋友。压缩包里通常包含源码、训练好的模型权重、数据集和部署说明文档。不要急着双击运行按照正确的顺序操作会少踩很多坑。6.1 源码包的目录结构与必读文件正常的一个智慧工地项目源码包目录结构大致是这样的project/ ├── main.py # 程序入口 ├── ui/ │ ├── main_window.py # Qt主界面 │ └── video_thread.py # 视频处理线程 ├── models/ │ └── best.pt # 训练好的模型权重 ├── data/ │ ├── images/ # 数据集图片 │ ├── labels/ # 数据集标注 │ └── helmet.yaml # 数据配置文件 ├── utils/ │ ├── detector.py # YOLOv5推理封装 │ └── alert.py # 告警逻辑 ├── requirements.txt # Python依赖 └── README.md # 部署说明拿到源码包之后第一件要做的事是打开README.md看一遍重点看Python版本要求通常要求3.8及以上、PyQt5版本、PyTorch版本、torchvision版本。这几个版本如果和部署说明里的不一致后续会遇到各种稀奇古怪的报错。6.2 环境搭建的标准操作流程第一步创建独立的虚拟环境conda create -n safetyhelmet python3.8 conda activate safetyhelmet建议单独建一个环境不要和平时开发的环境混在一起。这个项目涉及YOLOv5、PyTorch、PyQt5等一堆依赖和已有的OpenCV、numpy版本容易冲突独立环境能省掉很多麻烦。第二步安装依赖pip install -r requirements.txt如果requirements.txt里的某些包安装失败大概率是版本太老或太新。我建议把PyQt5和PyTorch单独手动安装指定版本号。PyQt5推荐5.15系列这个版本对Windows的支持最稳定到目前也没有发现明显的兼容性问题。第三步验证模型文件能不能正常加载import torch model torch.hub.load(ultralytics/yolov5, custom, pathmodels/best.pt) img data/test.jpg results model(img) results.show()如果能正常显示检测结果说明模型文件和依赖库都没问题。如果这里就报错千万别继续往下跑GUI先把模型加载的问题解决掉。6.3 数据集训练环境验证拿到源码包里的数据集之后先看一下data/helmet.yaml中标签类别数量和实际标注文件的类别索引是否一致。这个检查非常重要——如果yaml文件里写了3个类别但某些标注文件里出现了类别索引3训练的时候会直接报错“Label class 3 exceeds nc3”。快速验证脚本import os labels_dir data/helmet/train/labels max_cls 0 for f in os.listdir(labels_dir): with open(os.path.join(labels_dir, f)) as fp: for line in fp.readlines(): cls_id int(line.strip().split()[0]) max_cls max(max_cls, cls_id) print(max class id:, max_cls)如果max_cls大于等于类别总数就需要检查标注文件是否有越界情况修正后再训练。别问我为什么强调这个——我第一次拿到类似数据集的时候就是被两个类别索引为3的脏标注卡了半天排查到最后才发现是标注导出的时候多了一个不在预期类别列表里的类型。6.4 常见运行报错与解决方案这个项目跑起来之后最常见的报错有三类我把排查思路整理成表报错信息原因解决方案ModuleNotFoundError: No module named PyQt5虚拟环境里没装PyQt5或装到了别的环境pip install PyQt55.15.10RuntimeError: CUDA out of memory显存不足或者batch_size设置太大推理时降低图片尺寸--img 480、关闭多余程序AttributeError: NoneType object has no attribute shape视频流读取失败摄像头索引错误或RTSP地址不可达检查VideoCapture的索引/地址测试cap.isOpened()torch.hub.load无法加载模型网络原因或模型路径错误优先用本地路径pathmodels/best.pt不要依赖网络下载6.5 打包成exe的实践经验如果项目最终要交付给工地使用不能要求对方安装Python环境然后跑命令行打包成独立的exe文件是更务实的方案。用PyInstaller打包PyQt5YOLOv5项目最核心的问题是打包体积大和模型文件路径问题。pip install pyinstaller pyinstaller -D main.py -n SafetyHelmetSystem --hidden-import torch --hidden-import PyQt5这里我用的是-D目录模式而不是-F单文件模式。单文件模式虽然看起来更干净但每次启动都要先把所有依赖解压到临时目录启动速度慢不少而且还容易被杀毒软件误报。目录模式打包出来是一个文件夹直接拷贝整个文件夹到目标机器上运行就好。模型路径在打包后尤其容易出问题。源码包默认是相对路径models/best.pt如果系统的当前工作目录不是项目根目录路径就会失效。一个稳妥的方法是在代码中把模型路径改成绝对路径或者用sys.argv[0]获取当前程序所在目录再加上模型路径import sys import os def get_resource_path(relative_path): base_dir os.path.dirname(sys.argv[0]) return os.path.join(base_dir, relative_path) model_path get_resource_path(models/best.pt)这样不管exe从哪个目录启动都能正确找到模型文件。7. 一些落地时的补充心得项目做完了、跑通了并不代表就“完事”了。这里最后聊几个我自己在实际部署中获得的经验。首先是阈值不要照搬默认值。YOLOv5的默认置信度阈值是0.25但安全帽检测和危险区域入侵这两个场景对置信度阈值的要求完全不同。安全帽检测宁缺毋滥——如果置信度阈值太低误检会把告警刷爆所以建议调到0.4到0.5之间而危险区域入侵则宁滥勿缺——真的漏掉一次入侵可能就是一个安全事故建议把阈值调到0.3左右多一些误报也比漏一次强。其次是告警信息一定要留痕。告警弹窗只是瞬时行为如果安全员刚好没在看屏幕告警就等于白报了。在代码里加一个把告警事件写入日志文件的功能每次告警都把时间戳、检测画面截图、告警类型存下来。这不仅是事后追溯的依据也是给甲方展示系统价值的关键材料——你做了一个月的系统到底拦住了多少次违规靠日志说话最有力。最后是系统要能断线重连。工地现场的摄像头RTSP流经常因为网络波动断掉如果程序没有重连机制画面卡住、界面“假死”安全员就只能重启软件。简单做法是每隔几秒检测一次cap.isOpened()如果发现视频流断开自动释放摄像头并重新初始化VideoCapture对象不需要重启程序就能恢复。这个功能看起来不起眼但在实际工地场景里它的使用频率比你想象的高得多。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价