基于YOLOv5与PyQt5的智慧工地安全帽检测及危险区域入侵系统实战解析 📅 发布时间:2026/8/31 18:14:03 👁 浏览次数: 简介这是一套面向计算机及相关专业在校学生、教师与企业开发者的智慧工地安全监管实战项目资源聚焦施工现场安全帽佩戴识别与危险区域入侵告警两大核心需求融合YOLOv5目标检测与PyQt5桌面应用开发技术兼具毕设、课程设计与工程原型验证价值。压缩包共2000个文件含406张标注图像jpg、743份PASCAL VOC格式标注xml、743个标签文本txt、49个Python主程序与配置脚本py/yaml、以及部署说明、操作文档等整体大小236.04MB图像与标注数据已覆盖多角度、光照与遮挡场景模型权重与GUI界面代码开箱即用。目前已有4147人学习下载资源提供完整可运行源码、自定义危险区域绘制功能、实时声光告警逻辑、详细部署说明及测试验证记录特别适合深度学习入门者理解工业场景落地全流程亦可作为二次开发基础框架快速适配其他安防检测任务。 做智慧工地的朋友跟我吐槽过一件事几十路监控屏幕挂在墙上安全员轮流盯着看但还是会漏掉没戴安全帽的工人更别说危险区域闯入这种只要几秒就能出大事的情况。后来他换了一套基于YOLOv5和PyQt5的安全帽佩戴检测及危险区域入侵检测系统效果立刻不一样了——工人没戴安全帽镜头前实时弹框报警有人翻进塔吊下方禁区系统马上告警并把截图存下来。这篇文章就想完整拆解这个源码包带GUI界面、带数据集、带训练好的模型、还带部署说明的智慧工地项目从算法选型、数据标注、模型训练到PyQt5界面实现、危险区入侵判定逻辑再到环境部署和常见坑一次性讲透。这套东西适合谁如果你正在做安防监控、人员合规检测、工地智慧化改造或者想用YOLOv5做真实场景落地但不想只停留在跑通demo那这篇内容应该能帮你省掉大量试错时间。哪怕你只是Python入门、想看看目标检测怎么跟桌面软件结合里面的思路也值得抄作业。1. 项目整体设计与功能拆解1.1 智慧工地安全管理的真实痛点建筑工地的安全事故里高处坠落和物体打击占了相当大比例而没戴安全帽往往就是加重后果的直接原因。传统办法是安全员来回巡逻、盯监控但工地动辄几十路摄像头人眼盯久了必然疲劳漏报是早晚的事。加上塔吊、基坑、配电房这些危险区域不可能时刻派人把守单靠人力很难做到全天候无死角。智慧工地想解决的就是把“人盯屏”变成“算法盯屏”。摄像头采集画面模型实时判断画面里有没有人没戴安全帽有没有人进入禁区一旦触发规则就弹窗、响铃、推送给管理人员。这套项目正是围绕这两个需求展开的一个是人员防护装备合规检测一个是区域入侵行为预警。两个功能都跑在一个桌面GUI里双击就能用不需要什么高深部署背景。1.2 两个核心检测任务的技术本质安全帽佩戴检测本质上是目标检测任务——在图像中定位出人、以及人的头部区域同时判断这个头部有没有被安全帽覆盖。数据集的类别设计一般是三类person人体、hat戴安全帽的头部、head未戴安全帽的头部。这样设计的好处是模型学会的是“区分带帽与不带帽的头部”这件事而不是简单二分类实际场景里泛化能力更强。危险区域入侵检测本质上是目标检测加空间判断的组合。首先用同一个YOLOv5模型把画面里的“人”找出来然后拿这个人的位置信息去和预先划定的危险区域做几何计算判断落脚点是否落在区域内。这个算法不复杂真正的难点在于区域怎么划、人的位置怎么取、以及如何控制误报和重复报警。1.3 技术选型思路YOLOv5处理视觉PyQt5处理交互整个项目的技术栈并不花哨但都是在真实工程里被验证过、社区资料完备的组合。YOLOv5选得很稳。它不像YOLOv8/v11那样频繁更新导致大量代码依赖变动网络结构收敛、训练流程稳定生态非常成熟。预训练权重、官方训练脚本、各种推理封装都有现成资料遇到问题基本都能搜到答案。对于做项目交付来说稳定和可维护性比追新版本重要得多。PyQt5则是Python桌面应用的事实标准。它不是最炫酷的界面框架但在Windows工地现场电脑上跑稳定性、控件丰富度、OpenCV图像显示的兼容性都经得起考验。尤其是信号槽机制天然适合做视频流实时检测的UI刷新——采集线程把检测结果发信号传回主线程界面更新不会跟算法计算抢资源。2. 核心算法选型YOLOv5在安全帽检测中的应用2.1 数据集准备与标注规范拿到源码包后数据集一般是一个已经整理好的标注目录但如果你需要自己扩展训练数据或者后续要换工地场景做微调得先搞清楚数据集结构。推荐目录结构是这样safety_helmet_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/images里放jpg图片labels里放同名txt标注文件。每个txt文件的每一行表示一个目标类别索引 x_center y_center width height注意这些值是归一化到0~1之间的格式是YOLO标准格式不是VOC的xml。类别索引对应顺序很重要比如0是person1是hat2是head那么labels里的第一列就只能是0、1或2。公开数据集方面SHWDSafety Helmet Wearing Dataset是很多人用的基础数据大概七千多张图覆盖工地常见角度和光线但里面也有不少标注噪音。如果项目要求高建议在正式训练前花时间清洗一遍数据把明显标错或漏标的图片删掉再补充一部分现场摄像头截图效果会完全不一样。我在做类似项目时把现场两周的监控片段抽帧出来手工补充了两千多张白天和夜间的样本最终模型在夜间场景的漏检率明显下降。注意一定不要让训练集和验证集里有重复图片。很多时候大家从监控视频抽帧生成数据相邻帧几乎一样如果不按时间间隔抽样验证集会出现“假高分”实际场景泛化却很差。2.2 模型训练流程与超参数设置YOLOv5的训练步骤很成熟关键是几个核心参数要理解透。首先数据集描述文件data.yaml要写好train: safety_helmet_dataset/images/train val: safety_helmet_dataset/images/val nc: 3 names: [person, hat, head]训练命令示例python train.py --img 640 --batch 16 --epochs 150 --data safety_helmet.yaml --weights yolov5s.pt --name helmet_exp这里重点说一下参数选择逻辑输入尺寸img设640。安全帽在监控中通常是小目标太低会丢失细节太高训练显存扛不住。640是精度和资源消耗的最佳平衡点。batch size看显存。8G显存跑yolov5s16基本到头如果显存不够优先降batch不要降分辨率。初始权重选yolov5s.pt还是yolov5m.pt取决于你对精度的要求和部署硬件。工地场景如果摄像头角度好、距离近yolov5s完全够用推理速度快很多如果摄像头装在很高的杆子上人头很小那至少要用m起步。训练过程中的loss曲线需要盯着看。正常情况下train loss和val loss会同步下降如果出现train loss降了但val loss反弹大概率是过拟合了考虑增加数据增强、增加数据量或者提前终止。YOLOv5默认开启了马赛克增强这对小目标检测帮助很大但最后一个epoch会自动关闭马赛克做最终评估所以不用自己手动调。2.3 从检测结果到业务判定head与hat的后处理逻辑模型输出的是三类框不是直接的“是否戴帽”结论。业务层需要写一个逻辑转换如果某个person框周围没有对应的head框也没有hat框说明这张图没检测到人头只能标记为“人员未识别到头部”不能贸然判定为未戴帽。如果person关联到了head框说明这个人没戴安全帽触发未佩戴告警。如果关联到了hat框判定为已佩戴。这里的难点是“关联”这件事。简单做法是计算每个head/hat框的中心点与person框底部中心的欧氏距离取最近的进行匹配。更稳的做法是直接用IoU或者给定一个距离阈值。但不管怎样单一帧的匹配都可能出错所以我建议在告警模块里加状态平滑——比如连续3帧都判定为未戴帽才真正发出告警这样可以过滤掉因为抖动、遮挡导致的孤立误判。3. 基于PyQt5的检测界面设计与实现3.1 界面布局与核心交互这套源码包里的GUI典型的功能模块包括视频源选择区、实时画面显示区、检测结果状态区、告警信息列表、以及按钮控制栏。整体不用做得花哨实用优先。视频源选择一般用QComboBox下拉框支持三种输入本地视频文件.mp4、.avi等USB摄像头设备编号0、1等RTSP网络摄像头地址画面显示区用QLabel或自定义QWidget通过setPixmap显示OpenCV转换过来的QImage。注意一个坑OpenCV读出来的图像是BGR格式必须先转成RGB再显示否则画面颜色会偏蓝偏红看着像加了滤镜。按钮控制栏至少要包含开始检测、暂停检测、停止检测、截图保存。告警信息列表用QTableWidget或QListWidget每行记录报警时间、报警类型、截图路径。3.2 多线程与信号槽不让界面卡死的核心PyQt5写实时检测最忌讳的就是把视频读取和模型推理都塞在主线程。视频流是阻塞操作YOLOv5推理在GPU上还好说如果CPU推理单帧可能几百毫秒主线程一卡住界面直接假死用户体验极差。所以要拆线程。通用的做法是创建一个QThread子类比如DetectionThread在run方法里循环做读帧、预处理、推理、后处理然后把结果通过pyqtSignal发回主线程主线程只做UI刷新。信号里传一个dict包含画面帧、检测框列表、是否告警、FPS等字段。class DetectionThread(QThread): frame_signal pyqtSignal(dict) def run(self): cap cv2.VideoCapture(self.video_source) while not self.isInterruptionRequested(): ret, frame cap.read() if not ret: break results self.model.detect(frame) self.frame_signal.emit({ frame: results.annotated_frame, boxes: results.boxes, alert: results.alert }) cap.release()主线程里连接信号槽self.det_thread.frame_signal.connect(self.update_ui)这样界面刷新永远只有几十毫秒不会因为模型推理变慢而卡死。注意信号传大图片对象也可以但要避免高频copy尽量复用同一个缓冲区对象。如果怕传帧太频繁造成UI队列积压可以在信号里加一个递增的frame_id槽函数里判断跳过旧帧。3.3 检测结果可视化画框、置信度与状态标签检测结果的绘制逻辑OpenCV一套搞定。给每个检测框画矩形、类别名、置信度。但业务层最好在画框上做区分person框用绿色hat框用蓝色head框用红色。这样管理员一眼能看出问题在哪。状态显示区可以放几个大号标签比如“当前安全人数: 8”“未佩戴人数: 1”“最近告警: 10秒前”。这些标签通过QLabel的setStyleSheet实现颜色变化比如未佩戴超过0标签背景变红整个监控画面的紧迫感就出来了。截图功能建议存成带时间戳的文件名比如alert_20240115_143205.jpg同时把当时帧上的检测框也画进截图里方便事后追责。实测下来带检测框的截图比原始截图有用得多管理人员一眼就能看出当时模型的判断依据。4. 危险区域入侵检测的逻辑与实现4.1 危险区域如何划定危险区域入侵检测的第一步是让用户把“禁区”告诉系统。源码包里通常提供了两种方案方案一是固定区域配置文件。在config.json里写多个多边形的顶点坐标{ danger_zones: [ {name: 塔吊下方, points: [[100, 200], [350, 200], [350, 480], [100, 480]]}, {name: 配电房, points: [[700, 150], [900, 150], [900, 400], [700, 400]]} ] }方案二是GUI里交互画区域。在画面显示控件上监听鼠标事件点击落点双击闭合生成多边形然后保存到配置文件。这种交互对现场人员友好得多不用打开json手写坐标。注意多边形坐标的坐标空间要和视频帧的像素坐标系一致。如果视频源分辨率是1920x1080画区域时用的也是这个画面下的坐标那么推理帧也要resize到这个尺寸下做判断。实际项目里最常遇到的“区域漂移”问题就是resize后忘了换算坐标。4.2 入侵判定的核心算法判断一个点是否在某个多边形内部OpenCV有现成函数cv2.pointPolygonTestresult cv2.pointPolygonTest(zone_contour, point, False) # result 0 表示点在内部 # result 0 表示点在边界上 # result 0 表示点在外部这个函数很快对每个检测到的人判断一次即可。但这里有个工程细节用人的哪个点来代表“位置”如果摄像头是俯拍用中心点没问题如果是巷口或门口那种平视或斜视机位人的中心点会偏向画面中的身体中部可能导致人明明在区域门口中心点已经在区域外。更稳妥的做法是用人的脚部中心点——也就是检测框的底部中点——作为落脚点因为入侵行为的本质是“脚跨进了禁区”。实际测试中底部中点明显比中心点更符合人的直觉。唯一的特例是人坐下或蹲下时检测框会变形脚部中点误差会变大这种情况可以退回到中心点或者用相邻帧的均值平滑。4.3 告警联动与记录触发入侵后的动作不只是画个框报警。一个完整的告警流程应该是画红色闪烁框、播放语音提示可以用pyttsx3或QSound播放wav、弹出一个提示窗口、把告警截图存到历史记录目录、把告警信息追加到日志表格。告警去重是管理体验的关键。如果不做去重一个人站在禁区里1分钟系统会刷50条报警管理人员直接崩溃。我实际落地时采用的策略是对每个目标维护一个“最后告警时间”同一目标连续出现在同一个区域内如果距离上次告警不足30秒就不再重复报警但画面上的红色高亮保留。如果目标移出区域再进入或者目标跟踪ID变了重新计时。还有一个小技巧告警截图可以由两张拼在一起原始画面加上带检测框和区域线画面的对比拼接图。这样既能看清现场真实情况也能看清算法的判断逻辑现场人员反馈特别好。5. 环境配置与整体部署指南5.1 环境清单与版本匹配这个项目的部署最磨人的往往是依赖版本。我建议环境组合如下实测兼容性很好组件推荐版本说明Python3.8 或 3.9YOLOv5官方支持最稳的版本PyTorch1.10 ~ 1.132.x也可以但部分旧代码逻辑要改CUDA11.3 或 11.7需和PyTorch版本严格对应PyQt55.15.7不要太老QMediaPlayer有坑opencv-python4.5.x ~ 4.8.x4.9后个别API调整要留意numpy1.21 ~ 1.24与opencv的兼容性最稳定安装PyQt5时经常碰到的问题就是pip下载慢或者安装包过大用国内镜像源会好很多pip install pyqt5 -i https://pypi.tuna.tsinghua.edu.cn/simpleCUDA和PyTorch版本对不上是刚入手最容易翻车的地方。先确定自己显卡驱动支持的CUDA版本然后选择对应版本的PyTorch。NVIDIA控制面板里能直接看到CUDA版本信息不要凭感觉装。5.2 快速启动流程拿到源码包后的正确解包顺序我按自己的经验整理了一遍解压到纯英文路径。路径里带中文在PyTorch加载权重和OpenCV读文件时都会出一些莫名其妙的问题比如权重文件读不出来或者数据加载失败。按上面的版本表创建conda环境conda create -n helmet python3.8。在项目根目录执行pip install -r requirements.txt。如果源码包没带requirements.txt自己整理一份核心依赖就那几个。确认权重文件路径。源码包里的模型文件可能是best.pt或yolov5s_helmet.pt需要在代码里找到模型加载那行把路径改成实际路径建议写绝对路径。运行主程序python main.py或python gui_main.py看入口文件名。加载模型后在界面里选择视频源点开始检测。如果第一次运行就卡在“模型加载”那一步八成是权重文件路径不对或者PyTorch版本太新导致的权重兼容问题。前者改路径后者就老实换回1.13。5.3 部署成本与性能实测参考模型推理速度yolov5s在GTX 1060这类中端卡上640x640输入单帧推理大约20~30毫秒加上前后处理和时间戳画面能跑到20帧以上。这个帧率在工地监控场景里完全够用——安全帽没戴这个状态不会一秒内就消失又不是追踪高速运动的物体。CPU推理就慢多了yolov5s在i5-10400上单帧大概300~500毫秒只能做到每3~5帧检测一次。在实际项目里如果现场没有GPU机器我的做法是画面显示走实时流检测线程做跳帧检测每5帧检测一次并把检测结果叠加在最近一帧上。视觉体验上会有一点延迟但告警功能不受影响。6. 常见问题排查与性能优化心得6.1 运行报错速查表拿到源码包后跑起来的路上基本会遇到这几类问题整理成速查表方便对照。报错现象可能原因处理方法ModuleNotFoundError: PyQt5没装PyQt5pip安装注意用Python3.8/3.9环境AttributeError: Upsample object has no attribute recompute_scale_factorPyTorch版本太新换PyTorch 1.10~1.13FileNotFoundError: best.pt权重路径不对检查权重文件是否存在改用绝对路径CUDA out of memorybatch太大或分辨率太高降低输入尺寸或换yolov5s/yolov5ncv2.VideoCapture(0) returns False摄像头被占用或驱动问题释放摄像头换设备编号检查权限QWidget: Must construct a QApplication在非主线程创建了QWidgetUI操作只能放主线程用信号槽传数据画面偏蓝或偏红OpenCV的BGR转RGB没做在setPixmap前执行cv2.cvtColorAttributeError: partially initialized module cv2opencv与numpy版本冲突按上表统一版本或重装依赖这里面最坑的是PyTorch版本导致的Upsample报错。很多源码包是用旧版PyTorch训练的新版本框架里底层实现变了直接加载会报错而报错提示跟你的业务代码毫无关系容易让人误判。6.2 误检漏检调优思路模型在训练集里表现很好到了现场工地却各种漏检这类问题很常见不外乎几个方向第一训练数据的场景覆盖不够。工地光线变化大逆光、夜间、粉尘天气都会让检测效果退化。方案是现场采集数据跟原数据混合后做增量训练。第二目标尺度分布和anchor不匹配。如果摄像头安装在很远的杆子上人非常小默认anchor对大目标更友好小目标召回率会很低。可以在YOLOv5的训练配置里增加小目标anchor权重或者直接用yolov5n这类更适合小目标的模型。第三置信度阈值太高或太低。检测头输出的置信度阈值在GUI里应该做成可调参数。实测中安全帽检测阈值设0.35~0.4比较合适太高会把部分被遮挡的帽子漏掉太低会把安全帽倒影、黄色塑料布误判成帽子。第四真正稳定的方案是加追踪。当模型出现单帧误检漏检时配合DeepSORT跟踪算法一个目标在多帧间的检测结果做投票可以显著降低告警抖动。如果觉得集成DeepSORT太重至少在告警逻辑里加上连续N帧判定效果提升也非常明显。6.3 打包成exe的几个坑给工地现场部署不能要求对方电脑上装Python环境所以打包成独立exe几乎是必须的。PyInstaller是主要工具打包命令大概这样pyinstaller -F -w --add-data best.pt;. --add-data config.json;. main.py-w表示不启动命令行窗口--add-data把权重和配置一起包进去。但这里有几个坑一是YOLOv5的动态import问题。YOLOv5的utils模块里大量使用从字符串动态import的方式PyInstaller的静态分析抓不全依赖打包后经常报ModuleNotFoundError: utils.*。解决方法是手工在代码入口显式import一遍所有会用的模块或者在spec文件的hiddenimports里逐个加上。二是资源文件路径问题。打包成exe后代码里写相对路径找不到文件必须用sys._MEIPASS来定位临时解压目录def resource_path(relative_path): base_path getattr(sys, _MEIPASS, os.path.abspath(.)) return os.path.join(base_path, relative_path)三是体积问题。一个带PyTorch和PyQt5的exe打包出来至少1.5G起步启动时间也长。第一次启动时如果没反应其实是后台在解压资源耐心等20~30秒。交付给客户时最好提前说明这一点。6.4 个人建议从demo到可交付的三点经验把这类项目从“自己能跑”变成“现场能稳定跑”我总结出三条经验。第一一定要在真实场景采集数据做微调。公开数据集只是起点现场摄像头的高度、角度、光线、尘土遮挡每一个变量都会影响模型表现。宁可花一周时间做数据采集和数据清洗也不要指望模型一次训练就适配所有工地。第二告警和记录机制比检测模型本身更影响用户体验。管理人员真正在意的是有没有告警告警证据清不清晰能不能追溯。哪怕检测精度稍微差一点只要告警截图清晰、日志完整、误报可控产品口碑就不会差。第三GUI和算法解耦设计后面扩展才轻松。这个项目做扎实后很容易扩展出抽烟检测、反光衣检测、车辆违规进入检测。只要把YOLOv5的检测类别扩充一下数据准备好重新训练GUI和后处理逻辑基本不动就能很快出一个新功能。我自己的体会是这套项目的价值不在于代码本身跑起来有多炫而在于它把一个完整的智慧工地安防闭环打通了算法识别、GUI交互、告警记录、部署交付每个环节都是实际项目里绕不开的硬骨头。如果你打算长期做这类场景把它跑透、改明白后面的扩展就是水到渠成的事。本文还有配套的精品资源点击获取