基于YOLOv8与PyQt5的安全帽佩戴检测系统开发实践

基于YOLOv8与PyQt5的安全帽佩戴检测系统开发实践 安全帽佩戴检测在工地安全管理中一直是个刚需场景。传统人工巡检依赖安全员现场盯防效率低、覆盖面有限遇到多作业面同时施工时很容易漏检。近年来深度学习目标检测算法发展很快尤其是 YOLO 系列从 YOLOv5 到 YOLOv8检测精度和速度都提升明显。PyQt5 则非常适合用来快速搭建桌面端检测界面把模型能力封装成可操作的软件工具。本文围绕“YOLOv8 PyQt5 安全帽佩戴检测系统”展开从数据准备、模型训练到桌面应用开发逐步带大家搭建一套可运行的检测系统。1. 背景与核心概念1.1 为什么要做安全帽佩戴检测建筑工地、工厂车间、电力检修等场景中安全帽是保护头部免受坠落物伤害的关键防护装备。工地安全事故中因未佩戴安全帽导致的重伤甚至死亡案例并不少见。传统管理手段依赖安全员现场巡检很难做到 7×24 小时全覆盖尤其是多个作业面同时施工时管理人员数量有限容易出现监管盲区。视频监控在工地已经基本普及但监控画面人工盯防成本高、注意力容易疲劳。通过计算机视觉技术自动识别画面中的人员是否佩戴安全帽可以在异常发生时及时告警辅助管理人员快速响应。这种“AI 视频监控”的巡检方式正在成为智慧工地建设的重要内容之一。1.2 YOLOv8 在目标检测中的优势YOLOYou Only Look Once系列是目标检测领域最流行的算法之一核心思想是把目标检测当作回归问题一次前向推理直接输出目标类别和位置。YOLOv8 是 Ultralytics 公司在 2023 年推出的版本相比前代版本有几个明显改进网络结构上引入了 C2f 模块取代了 YOLOv5 中的 C3 模块增强了特征提取能力。分类分支和回归分支解耦使用 Anchor-Free 检测头减少了 Anchor 参数调优的烦恼。支持目标检测、实例分割、姿态估计等多种任务统一了训练和推理接口。训练流程更完善自适应锚框、数据增强策略都有改进。对安防检测类项目来说YOLOv8 兼顾了精度和速度模型体积可控部署到普通 GPU 或 CPU 机器上都能获得不错的实时性非常适合安全帽检测这类相对单一类别的场景。1.3 PyQt5 在桌面应用开发中的角色PyQt5 是 Qt 框架的 Python 绑定可以用来开发跨平台桌面图形界面。选择 PyQt5 主要看重以下几点控件丰富文件选择、视频播放、按钮、状态栏、表格等都有现成组件。信号槽机制让界面交互逻辑清晰适合处理视频帧刷新、检测结果更新这类异步任务。与 OpenCV、PyTorch 等 Python 库配合顺畅可以直接在界面中调用模型推理。打包发布成熟可以使用 PyInstaller 将应用打包成 exe方便部署到现场电脑。在检测系统中PyQt5 负责提供人机交互入口用户选择图片、视频或打开摄像头触发模型推理界面显示检测结果和统计信息。YOLOv8 和 PyQt5 的组合等于把深度学习模型封装成了一个真正可用的桌面工具。2. 系统整体设计2.1 系统功能拆解从用户视角看安全帽佩戴检测系统需要支持以下几种输入方式和反馈输出功能模块说明图片检测选择本地图片文件识别图中人员是否佩戴安全帽视频文件检测打开本地视频逐帧或抽帧推理实时显示标注结果摄像头实时检测调用本机摄像头或 RTSP 网络摄像头实时检测画面检测结果展示在画面中绘制边界框、类别名称和置信度安全帽佩戴统计统计当前画面中佩戴安全帽人数、未佩戴人数、总人数报警提示当检测到未佩戴安全帽人员时界面给出预警状态2.2 技术架构系统整体分为模型层、服务层、界面层三部分。模型层由 YOLOv8 训练好的权重文件承担负责目标检测推理服务层封装模型加载、推理、结果解析逻辑界面层基于 PyQt5 实现负责与用户交互。界面层PyQt5主窗口、按钮、Label、状态栏 ↓ 调用 服务层inference.py加载模型、图片/视频/摄像头推理 ↓ 调用 模型层YOLOv8best.pt 权重文件detect 推理这种解耦设计的好处是如果后续要换成其他检测模型只需修改服务层如果界面要加新功能也不用改动模型推理代码。2.3 开发环境说明本文示例环境如下读者可以根据自己的环境调整操作系统Windows 10/11 或 Ubuntu 20.04Python3.8 或 3.9深度学习框架PyTorch 2.xYOLO 工具库ultralyticsGUI 框架PyQt5计算机视觉库OpenCV开发工具PyCharm 或 VS Code需要注意的是不同版本的 PyTorch、CUDA、ultralytics 之间可能存在兼容性差异建议先确认显卡驱动和 CUDA 版本再安装对应版本的 PyTorch。没有 NVIDIA GPU 的机器也可以使用 CPU 推理只是速度会慢一些。3. 环境准备与安装3.1 创建 Python 虚拟环境为了避免依赖冲突建议为项目单独创建虚拟环境。conda create -n helmet_det python3.9 conda activate helmet_det或者使用 venvpython -m venv helmet_env helmet_env\Scripts\activate3.2 安装 PyTorchPyTorch 安装命令需要根据 CUDA 版本选择。先执行以下命令查看本机 CUDA 版本nvidia-smi如果有 NVIDIA GPU可以安装带 CUDA 支持的 PyTorch 版本比如pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118如果没有 GPU安装 CPU 版本即可pip install torch torchvision装完可以验证一下import torch print(torch.__version__) print(torch.cuda.is_available())torch.cuda.is_available()返回True说明 CUDA 可用训练和推理都能用上 GPU 加速。3.3 安装 ultralytics 与 PyQt5ultralytics 是 YOLOv8 的官方 Python 包封装了训练、验证、推理、导出等功能。pip install ultralytics pip install pyqt5 pip install opencv-python pip install pillow验证安装yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg如果能正常输出检测结果说明 ultralytics 安装成功。3.4 项目目录结构建议项目使用如下结构代码分层清晰后续扩展方便helmet_detection/ │ ├── main.py # PyQt5 界面入口 ├── detector.py # 模型推理封装类负责模型加载和 detect ├── utils.py # 工具函数如绘图、规则判断 ├── weights/ │ └── best.pt # 训练好的模型权重 ├── datasets/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── data/ │ └── helmet.yaml # 数据集配置文件 ├── runs/ │ └── detect/ # 模型训练输出目录 │ └── train/ └── test_data/ ├── test_image.jpg └── test_video.mp44. 数据集准备与模型训练4.1 数据集说明训练 YOLOv8 检测模型需要标注好的数据集。安全帽检测一般标注两个类别helmet佩戴安全帽head未佩戴安全帽裸露头部有的项目还会把person单独作为一个类别用来辅助统计人数但为了简化问题两个类别足够完成核心功能。数据来源可以是网上开源的安全帽检测数据集也可以自己采集工地视频帧进行标注。自己标注时推荐使用 LabelImg 工具标注格式导出为 YOLO 格式即每个目标一个 txt 文件内容为class_id x_center y_center width height坐标值都是归一化到 [0,1] 的相对坐标。例如0 0.512 0.384 0.128 0.2144.2 数据集配置文件在data/helmet.yaml中指定训练集、验证集路径和类别名称# 文件路径data/helmet.yaml train: datasets/images/train val: datasets/images/val nc: 2 names: [helmet, head]nc表示类别数量names列表中的顺序必须和标注时的 class_id 一一对应。如果标注时0是 helmet1是 head这里的列表顺序就不能颠倒。4.3 训练命令在项目根目录执行训练命令yolo train modelyolov8n.pt datadata/helmet.yaml epochs100 imgsz640 batch16 device0参数说明参数含义model预训练权重可选用 yolov8n.pt、yolov8s.pt 等data数据集 yaml 文件路径epochs训练轮数根据数据量调整imgsz输入图片分辨率默认 640batch批次大小显存不够时降低device设备编号0 表示第一块 GPUcpu 表示用 CPU 训练训练过程会在runs/detect/train/目录下生成权重文件其中best.pt是验证集上表现最好的权重last.pt是最后一轮保存的权重。部署时一般选择best.pt。如果是 CPU 训练可以把devicecpu但训练速度会慢很多建议数据量不大时先跑一个较小迭代数验证流程。4.4 训练结果评估训练完成后在输出目录中可以看到results.png、confusion_matrix.png、val_batch0_pred.jpg等文件。重点关注以下指标mAP50IoU 阈值为 0.5 时的平均精度一般达到 0.9 左右效果就很不错。mAP50-95IoU 阈值从 0.5 到 0.95 的平均精度更严格。precision查准率预测为正样本中有多少是真正的正样本。recall查全率真实正样本中有多少被正确预测出来。安全帽检测场景中漏检的后果比误检更严重因为漏检意味着未佩戴安全帽的人没有被发现。因此调参时要关注 recall 指标在 precision 和 recall 之间找平衡。5. 推理模块编写5.1 加载模型在detector.py中封装模型推理类。先看模型加载部分# 文件路径detector.py import cv2 from ultralytics import YOLO class HelmetDetector: def __init__(self, weights_path: str, conf_thres: float 0.4): self.model YOLO(weights_path) self.conf_thres conf_thres self.class_names [helmet, head]YOLO(weights_path)会加载训练好的模型权重支持.pt格式和.onnx格式。conf_thres是置信度阈值只有置信度大于该值的目标才会被保留。5.2 图片推理图片推理方法接收一张 BGR 格式的图片返回标注后的图片和检测统计信息。def detect_image(self, image): results self.model.predict(image, confself.conf_thres, verboseFalse) result results[0] # 统计安全帽佩戴情况 helmet_count 0 head_count 0 for box in result.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) x1, y1, x2, y2 map(int, box.xyxy[0]) if cls_id 0: helmet_count 1 label fhelmet {conf:.2f} color (0, 255, 0) else: head_count 1 label fhead {conf:.2f} color (0, 0, 255) cv2.rectangle(image, (x1, y1), (x2, y2), color, 2) cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) status PASS if head_count 0 else WARNING return image, helmet_count, head_count, status这里对每个检测框做了类别判断helmet绘制绿色框head绘制红色框。status用于后续界面显示预警状态。5.3 视频和摄像头推理视频文件检测时可以逐帧推理。为了保持界面流畅通常使用独立线程处理避免阻塞 UI。def detect_video_frame(self, frame): return self.detect_image(frame)这种方法把一帧图片的推理逻辑复用过来。实际视频处理时读取视频帧的循环放在界面线程或工作线程中每取到一帧就调用detect_video_frame然后把结果显示在界面控件上。6. PyQt5 界面开发6.1 主窗口设计主窗口包含以下控件顶部按钮栏选择图片、选择视频、打开摄像头、停止检测。中间显示区域用 QLabel 显示检测结果画面。底部状态栏显示检测到的佩戴人数、未佩戴人数和预警状态。在main.py中创建主窗口# 文件路径main.py import sys import cv2 from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QFileDialog, QStatusBar) from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtCore import QTimer, Qt from detector import HelmetDetector class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(工地安全帽佩戴检测系统) self.setGeometry(100, 100, 1000, 700) # 初始化检测器 self.detector HelmetDetector(weights/best.pt, conf_thres0.4) # 视频处理相关 self.cap None self.timer QTimer() self.timer.timeout.connect(self.update_frame) self.init_ui() def init_ui(self): central_widget QWidget() self.setCentralWidget(central_widget) # 按钮栏 btn_image QPushButton(检测图片) btn_video QPushButton(检测视频) btn_camera QPushButton(打开摄像头) btn_stop QPushButton(停止) btn_image.clicked.connect(self.open_image) btn_video.clicked.connect(self.open_video) btn_camera.clicked.connect(self.open_camera) btn_stop.clicked.connect(self.stop_detection) btn_layout QHBoxLayout() btn_layout.addWidget(btn_image) btn_layout.addWidget(btn_video) btn_layout.addWidget(btn_camera) btn_layout.addWidget(btn_stop) btn_layout.addStretch() # 显示区域 self.image_label QLabel(请选择图片、视频或打开摄像头) self.image_label.setAlignment(Qt.AlignCenter) self.image_label.setMinimumSize(800, 500) # 状态栏 self.status_label QLabel(就绪) self.statusBar().addWidget(self.status_label, 1) # 布局 main_layout QVBoxLayout() main_layout.addLayout(btn_layout) main_layout.addWidget(self.image_label) central_widget.setLayout(main_layout)这段代码搭建了主界面的基本骨架。QTimer用于周期性读取摄像头或视频帧实现连续显示。6.2 图片检测逻辑点击“检测图片”按钮弹出文件选择框选择图片后调用检测器把结果转换并显示到image_labeldef open_image(self): file_path, _ QFileDialog.getOpenFileName( self, 选择图片, , Image Files (*.jpg *.jpeg *.png *.bmp) ) if not file_path: return image cv2.imread(file_path) result_image, helmet_count, head_count, status self.detector.detect_image(image) self.show_image(result_image) self.update_status(helmet_count, head_count, status) def show_image(self, image_bgr): h, w, ch image_bgr.shape bytes_per_line ch * w # BGR 转 RGB否则颜色会失真 rgb_image cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB) qt_image QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888) self.image_label.setPixmap(QPixmap.fromImage(qt_image).scaled( self.image_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))注意QImage默认不识别 OpenCV 的 BGR 颜色排列cv2.cvtColor转成 RGB 后再交给界面显示否则检测框的颜色和原图颜色都会偏差。6.3 视频和摄像头实时检测视频和摄像头共用一个定时器流程。打开视频文件时用cv2.VideoCapture(file_path)打开摄像头时用cv2.VideoCapture(0)0 表示默认摄像头如果有多个摄像头可以尝试 1、2。def open_video(self): file_path, _ QFileDialog.getOpenFileName( self, 选择视频, , Video Files (*.mp4 *.avi *.mov) ) if not file_path: return self.cap cv2.VideoCapture(file_path) self.timer.start(30) # 约 33 毫秒一帧 def open_camera(self): self.cap cv2.VideoCapture(0) self.timer.start(30) def update_frame(self): ret, frame self.cap.read() if not ret: self.timer.stop() self.cap.release() return result_frame, helmet_count, head_count, status self.detector.detect_video_frame(frame) self.show_image(result_frame) self.update_status(helmet_count, head_count, status) def stop_detection(self): self.timer.stop() if self.cap: self.cap.release() self.image_label.setText(检测已停止) self.status_label.setText(就绪)timer.start(30)表示每 30 毫秒触发一次update_frame。实际帧率取决于推理速度如果模型推理耗时超过 30 毫秒界面帧率会降低这是正常的。6.4 状态栏信息更新def update_status(self, helmet_count, head_count, status): text f佩戴安全帽: {helmet_count} 人 | 未佩戴: {head_count} 人 | 状态: {status} self.status_label.setText(text)当status为WARNING时可以在后续扩展中触发声音报警、截图保存、日志记录等功能。6.5 程序入口if __name__ __main__: app QApplication(sys.argv) window MainWindow() window.show() sys.exit(app.exec_())7. 模型推理性能优化7.1 使用 ONNX 导出加速推理PyTorch 原生模型在 CPU 和 GPU 上都有不错的表现但在某些生产场景下ONNX Runtime 推理速度更快且部署时不需要安装完整 PyTorch 环境。导出 ONNX 模型yolo export modelweights/best.pt formatonnx imgsz640导出后修改HelmetDetector的加载代码# 使用 ONNX 模型时ultralytics 同样支持加载 self.model YOLO(weights/best.onnx)使用 ONNX 模型推理时需要安装onnxruntime或onnxruntime-gpupip install onnxruntime-gpu7.2 推理时关闭不必要的后处理在predict调用中verboseFalse可以关闭日志输出减少不必要的耗时。如果只是做检测不涉及分割或关键点任务YOLOv8 默认的检测头输出已经足够。7.3 画面尺寸与帧率平衡检测画面的分辨率越高推理耗时越长。在实际工地场景中摄像头画面通常是 1080p但检测时可以先把帧缩放到 640x640 或 960x960 再推理既能保证检测精度又能减少计算量。def detect_video_frame(self, frame): # 缩放帧到推理尺寸 resized cv2.resize(frame, (640, 640)) result_image, helmet_count, head_count, status self.detect_image(resized) # 将结果缩放回原始尺寸显示 result_image cv2.resize(result_image, (frame.shape[1], frame.shape[0])) return result_image, helmet_count, head_count, status需要注意的是缩放后坐标是相对于缩放后图片的显示时要把坐标映射回原图尺寸否则检测框位置会偏移。上面的简化示例直接对整幅结果图再缩放在实际项目中也可以对每个检测框坐标做比例换算这样文字和框不会模糊。8. 常见问题与排查思路8.1 PyQt5 界面卡顿现象视频检测时界面无响应拖动窗口卡顿。原因推理运算阻塞了 UI 主线程update_frame中的检测耗时较长界面事件无法及时处理。解决思路把视频读取和模型推理放到工作线程中通过信号把结果帧传给主线程刷新界面。PyQt5 的QThread或QThreadPool都可以实现。简化版本可以使用QTimer降低刷新频率。8.2 摄像头打不开现象点击“打开摄像头”后黑屏或无画面。排查步骤检查摄像头是否被其它程序占用。检查cv2.VideoCapture(0)的编号是否正确。在命令行单独运行cap cv2.VideoCapture(0); ret, frame cap.read()验证摄像头是否可用。如果是笔记本部分型号需要关闭摄像头隐私开关。8.3 模型检测效果差现象安全帽和头部检测不准漏检多或误检多。可能原因训练数据量太少场景单一。标注质量不高边界框不精确。摄像头安装角度与训练数据差异大。置信度阈值设置过高或过低。解决思路补充现场场景数据继续训练回看训练集标注是否正确把置信度阈值调整到 0.3-0.5 之间观察效果。8.4 CUDA 不可用现象torch.cuda.is_available()返回False。原因PyTorch 版本不是 CUDA 版或者显卡驱动版本过低。解决思路卸载 PyTorch 后重新安装对应 CUDA 版本的版本注意 CUDA 驱动版本和 PyTorch 编译版本的匹配关系。8.5 打包 exe 时 PyQt5 资源缺失现象打包后的 exe 运行时提示缺少 Qt 平台插件。解决思路使用 PyInstaller 打包时需要把 PyQt5 的插件目录加入打包路径常见做法是使用--hidden-import或修改.spec文件。新手阶段建议先用 PyCharm 等工具直接运行源码验证功能后再考虑打包。问题现象常见原因解决思路启动报错没有模组虚拟环境未激活或依赖未安装激活环境后重新pip install -r requirements.txt模型加载失败权重路径错误或权重文件损坏检查路径是否存在重新下载权重推理时显存不足batch 大小或输入分辨率过高降低 imgsz 或换更小模型界面显示颜色异常BGR/RGB 未转换使用cv2.cvtColor转换后再交给 QImage视频检测结束时卡住未处理read返回 False 的情况在update_frame中判断ret并停止定时器9. 工程最佳实践9.1 数据层面安全帽检测的数据集要覆盖不同光照、不同角度、不同距离下的情况。白天强光、夜间补光、阴天、雨雾天气都会影响检测效果。如果现场摄像头位置固定建议采集一段该场景下的真实视频抽帧后补充到训练集中。标注时遵循一致性原则一个目标只标一个框遮挡过大时可以适当放宽边界框但类别不要标错。安全帽颜色各异但类别统一为helmet不需要按颜色细分。9.2 模型层面从 YOLOv8n 开始尝试如果精度不达标再换 YOLOv8s 或 YOLOv8m。不要一上来就用大模型因为工地现场部署的机器性能参差不齐大模型推理速度会明显下降。训练时使用早期停止early stopping可以避免过拟合。ultralytics 默认会在验证指标连续多轮不提升时自动停止训练直接在train方法中设置patience参数即可。9.3 界面和工程层面使用独立配置文件管理权重路径、置信度阈值、摄像头编号等参数不要硬编码在代码里。摄像头断线要能自动重连并提示用户检查网络。报警信息要记录日志方便事后追溯。系统中涉及告警推送、截图存储的功能需要结合具体业务场景设计避免误报过多导致管理人员忽略报警。在真实工地部署时摄像头接入需要网络权限和安防授权必须遵循现场安全规范在合法授权范围内使用。9.4 关于浮点数格式和推理精度训练和推理过程中PyTorch 默认使用 FP3232 位浮点数计算权重和中间张量。FP32 精度高但占用显存和带宽较大。实际部署时可以考虑使用 FP16半精度或 INT8 量化来加速推理主流 GPU 对 FP16 计算有加速优化。在 YOLOv8 推理时可以通过设置halfTrue使用半精度推理results self.model.predict(image, confself.conf_thres, halfTrue, verboseFalse)但要注意FP16 在某些 GPU 上精度损失可能导致小目标检测效果下降。INT8 量化需要校准数据安全帽这类小目标检测任务中量化后精度波动需要实测验证。稳妥的做法是先跑 FP32 保证效果性能不满足要求时再优化。9.5 安全边界说明本系统用于工地安全管理辅助不替代人工安全管理流程。检测结果只作为参考信息告警处理后应由现场安全管理人员复核确认。涉及摄像头监控和人员信息分析的系统需要遵守单位的隐私保护规定不得随意泄露监控数据和人员信息。10. 总结与进阶方向本文从工地安全帽佩戴检测的业务需求出发介绍了基于 YOLOv8 PyQt5 的完整开发流程。重点内容包括数据集准备和 YOLO 格式标注说明YOLOv8 模型训练命令和评估指标解读PyQt5 桌面界面搭建设计图片、视频、摄像头三种检测方式的实现模型推理性能优化思路常见问题和工程实践建议读者可以按照文章流程先准备数据训练自己的安全帽检测模型再基于模型编写 PyQt5 界面一套完整的桌面检测工具就搭起来了。下一步可以尝试的方向添加检测结果统计报表功能输出每日未佩戴安全帽次数。接入 RTSP 网络摄像头实现多路视频同时检测。使用 ONNX Runtime 或 TensorRT 加速推理提升实时性。将检测结果推送到 Web 端或手机端实现远程查看。在检测模型中添加person类别精确统计工地现场作业人数。安全帽检测是深度学习落地工业场景的典型例子技术栈并不复杂但真正要稳定运行在真实环境中还需要考虑数据、模型、部署、告警联动等一系列工程问题。希望这篇文章能帮你快速搭建出自己的安全帽佩戴检测系统。