新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于YOLOv4与PyTorch的口罩识别系统:从训练到PyQt5界面部署

发布时间:2026/9/27 23:11:57来源:尧图网络
基于YOLOv4与PyTorch的口罩识别系统:从训练到PyQt5界面部署
简介这份资源是一套基于YOLOv4与PyTorch构建的深度学习口罩识别系统面向希望将目标检测落地到实际场景的开发者与学习者尤其适合具备一定Python基础、想同时练习模型训练与桌面端GUI开发的人群。系统内置PyQt5登录界面与实时检测界面可调用摄像头对画面中是否佩戴口罩进行标注与反馈覆盖从数据准备、模型训练到推理部署的完整链路。压缩包共1286个文件以621个xml标注文件和617张jpg样本图像为主另含19个py脚本、2个pth权重、2个ui界面文件及若干txt说明与mp4演示整体约496.4MB目录结构便于按模块查阅。目前已有1332人学习下载。读者可借此掌握YOLOv4小目标检测的配置与训练流程、PyQt5界面与检测逻辑的联动方式并参考现成权重快速复现口罩识别效果对理解深度学习与GUI结合的综合项目具有较高参考价值。1. 从一次产线抽检翻车说起yolov4-pytorch 口罩识别系统到底在做什么去年帮一个做园区门禁的朋友调系统他们用开源 YOLOv4 权重直接跑口罩检测白天准确率能到 92%结果傍晚逆光时段把黑色口罩全判成“未佩戴”保安亭的告警灯闪个不停。这个翻车现场让我意识到一个能交付的口罩识别系统模型只是其中一环真正决定落地效果的是数据标注质量、PyTorch 训练时的 anchor 匹配策略以及 PyQt5 界面里摄像头帧的取流方式。这套yolov4-pytorch 框架做的深度学习口罩识别系统核心就是三块用 PyTorch 复现 YOLOv4 的 CSPDarknet53 主干做检测用 PyQt5 搭登录界面和实时检测界面中间靠 OpenCV 把摄像头帧喂给模型。它适合两类人一是想拿一个完整深度学习项目练手的学生或转行者二是需要在门禁、工地、医院入口做快速原型验证的工程师。你不需要从零写 Darknet 的 C 代码也不用纠结 PyQt5 和 PyTorch 的线程冲突怎么绕这套结构已经把“训练-推理-界面”串成了一条可复现的链路。接下来我会按环境搭建、数据准备、模型训练、界面集成、避坑排查的顺序把每个环节的参数和踩坑点讲透。2. 环境搭建与 yolov4-pytorch 依赖选型别在 CUDA 版本上赌运气2.1 PyTorch 与 CUDA 的版本对齐逻辑很多人装环境时习惯直接pip install torch结果跑训练时报CUDA error: no kernel image is available for execution on the device。这个报错的根源是 PyTorch 预编译轮子绑定的 CUDA 架构和你显卡算力不匹配。YOLOv4 的 CSPDarknet53 里有大量 3x3 和 1x1 卷积对 cuDNN 版本也敏感。我一般会先查显卡算力再倒推 CUDA 和 PyTorch 版本。显卡系列算力推荐 CUDA推荐 PyTorchGTX 10 系6.111.31.10.0RTX 20 系7.511.61.12.1RTX 30 系8.611.71.13.1RTX 40 系8.911.82.0.1这张表不是绝对的但能避开 90% 的版本冲突。如果你用 WSL 跑 PyTorch注意 WSL2 的 CUDA 驱动是透传 Windows 主机的不要在 WSL 里再装一遍显卡驱动否则会出libcuda.so找不到的玄学问题。2.2 创建隔离环境与安装核心依赖我习惯用 conda 建一个独立环境避免和系统里的 PyQt5 版本打架。下面这套命令在 Ubuntu 20.04 和 Windows 11 的 WSL2 里都验证过。# 创建 Python 3.8 环境YOLOv4 的某些算子对 3.9 兼容性一般 conda create -n mask_yolo python3.8 -y conda activate mask_yolo # 安装 PyTorch注意 cu117 对应 CUDA 11.7 pip install torch1.13.1cu117 torchvision0.14.1cu117 -f https://download.pytorch.org/whl/torch_stable.html # 安装 PyQt5 和 OpenCV pip install PyQt55.15.9 opencv-python4.8.1.78 # 安装 YOLOv4 训练需要的依赖 pip install numpy1.23.5 matplotlib3.5.3 tqdm4.65.0 pyyaml6.0这里torch1.13.1cu117的cu117后缀不能省它决定了 PyTorch 是否带 CUDA 支持。装完后用下面这段代码验证import torch print(torch.__version__) # 应输出 1.13.1cu117 print(torch.cuda.is_available()) # 应输出 True print(torch.cuda.get_device_name(0)) # 显示显卡型号如果is_available()返回 False先检查nvidia-smi能否正常输出再看 PyTorch 版本是否带cu后缀。很多人在这里翻车是因为装了 CPU 版的 torch界面能跑但训练慢到怀疑人生。2.3 PyQt5 在 PyCharm 里的配置要点PyQt5 界面设计通常用 Qt Designer 拖控件生成.ui文件后用pyuic5转成.py。在 PyCharm 里配置外部工具时Program填pyuic5的完整路径Arguments填$FileName$ -o $FileNameWithoutExtension$.pyWorking directory填$FileDir$。这样右键.ui文件就能直接生成界面代码。注意 PyQt5 的QApplication必须放在主线程而模型推理要放到QThread里否则实时检测界面会卡成 PPT。3. 口罩数据集准备与 YOLOv4 格式转换labelme 标注的四个边界坑3.1 用 labelme 标注口罩数据的正确姿势口罩检测一般分两类mask佩戴口罩和no_mask未佩戴口罩。标注时用矩形框不要用多边形因为 YOLOv4 的检测头输出的是矩形框回归。labelme 保存的 JSON 里shapes字段记录了每个框的label和points。我见过有人把口罩拉到下巴也标成mask这种数据训出来的模型在门禁场景会疯狂误报因为下巴口罩和未佩戴的视觉特征几乎一样。标注时注意四个边界坑遮挡超过 50% 的脸不要标标了反而拉低召回率夜间红外图像单独放一个文件夹不要和可见光混在一起训侧脸角度大于 60 度的样本控制在总数据量的 10% 以内每类至少 800 张否则 YOLOv4 的 anchor 聚类会偏3.2 从 labelme JSON 到 YOLO txt 的转换脚本YOLOv4 需要的标签格式是class_id x_center y_center width height且全部归一化到 0-1。下面这个脚本我用了三年处理过两万张口罩图没出过坐标越界。import json import os import numpy as np def labelme_to_yolo(json_dir, output_dir, class_names): json_dir: labelme JSON 文件夹 output_dir: 输出 txt 文件夹 class_names: 类别列表如 [mask, no_mask] if not os.path.exists(output_dir): os.makedirs(output_dir) for json_file in os.listdir(json_dir): if not json_file.endswith(.json): continue with open(os.path.join(json_dir, json_file), r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_names: continue class_id class_names.index(label) points shape[points] x1 min(points[0][0], points[1][0]) y1 min(points[0][1], points[1][1]) x2 max(points[0][0], points[1][0]) y2 max(points[0][1], points[1][1]) # 归一化并限制在 0-1 之间防止标注越界 x_center max(0, min(1, (x1 x2) / 2 / img_w)) y_center max(0, min(1, (y1 y2) / 2 / img_h)) width max(0, min(1, (x2 - x1) / img_w)) height max(0, min(1, (y2 - y1) / img_h)) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) txt_name json_file.replace(.json, .txt) with open(os.path.join(output_dir, txt_name), w) as f: f.write(\n.join(lines)) # 调用示例 labelme_to_yolo(./labelme_json, ./labels, [mask, no_mask])max(0, min(1, ...))这层钳位很关键labelme 有时候会因为图片旋转导致坐标超出边界不钳位的话训练时 loss 会变成 NaN。转换完后用wc -l检查每个 txt 的行数如果某张图标注了 5 个框但 txt 只有 3 行说明有类别名写错了。3.3 数据集划分与 YOLOv4 配置文件修改按 8:1:1 划分训练集、验证集、测试集生成train.txt、val.txt、test.txt每行是图片的绝对路径。然后改cfg/yolov4-mask.cfg里的几个关键参数classes2在三个 yolo 层里都要改filters21计算公式是(classes 5) * 3max_batches4000每类至少 2000 次迭代steps3200,3600max_batches 的 80% 和 90%filters算错是新手最常见的翻车点写成 18 或 24 都会在加载权重时报 shape mismatch。改完 cfg 后用darknet的partial层加载预训练权重只训练检测头冻结主干 50 个 epoch 后再解冻全量微调。4. PyQt5 登录界面与实时检测界面的线程集成4.1 登录界面的信号槽与密码校验登录界面看起来简单但很多人在这里埋雷把密码明文存在.py文件里或者用time.sleep模拟登录延迟导致界面假死。我一般用QSettings存加密后的哈希校验时用hashlib.sha256比对。import hashlib from PyQt5.QtWidgets import QDialog, QMessageBox from PyQt5.QtCore import QSettings class LoginDialog(QDialog): def __init__(self): super().__init__() self.settings QSettings(MaskSystem, Auth) # 首次运行时写入默认账号 if not self.settings.contains(admin_hash): self.settings.setValue(admin_hash, hashlib.sha256(admin123.encode()).hexdigest()) def check_login(self, username, password): if username ! admin: return False stored_hash self.settings.value(admin_hash) input_hash hashlib.sha256(password.encode()).hexdigest() return input_hash stored_hashQSettings在 Windows 下写注册表在 Linux 下写~/.config跨平台不用改代码。校验失败时用QMessageBox.warning弹窗不要用print否则打包成 exe 后用户看不到任何提示。4.2 实时检测界面的 QThread 取流与推理分离实时检测界面卡顿的根源通常是在 UI 线程里直接调cv2.VideoCapture.read()和模型推理。正确做法是把取流和推理放到QThread里通过信号把带框的QImage发给主线程显示。from PyQt5.QtCore import QThread, pyqtSignal import cv2 import numpy as np import torch class DetectThread(QThread): frame_signal pyqtSignal(np.ndarray) def __init__(self, model, device, conf_thresh0.5): super().__init__() self.model model self.device device self.conf_thresh conf_thresh self.running True def run(self): cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while self.running: ret, frame cap.read() if not ret: continue # 预处理BGR转RGB归一化转tensor img cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img cv2.resize(img, (416, 416)) img_tensor torch.from_numpy(img).float().permute(2, 0, 1).unsqueeze(0) / 255.0 img_tensor img_tensor.to(self.device) with torch.no_grad(): preds self.model(img_tensor)[0] # NMS 后画框这里省略具体解码逻辑 # ... self.frame_signal.emit(frame) cap.release() def stop(self): self.running False self.wait()cap.set设置 640x480 是为了降低 USB 带宽压力很多摄像头默认 1920x1080不设的话帧率会掉到 5 帧以下。torch.no_grad()必须加否则显存会随着帧数增加一路涨到 OOM。信号frame_signal传np.ndarray而不是QImage是因为QImage不能跨线程传递必须在主线程里转换。4.3 界面与模型的解耦设计我习惯把模型加载放在主窗口初始化时而不是检测线程里。这样切换摄像头或暂停检测时不用反复加载权重。模型用torch.jit.trace导出成 TorchScript 后加载速度能快 30%但 YOLOv4 的某些后处理算子不支持 trace所以还是用torch.load加载state_dict更稳。界面上的置信度滑块直接绑定conf_thresh变量用pyqtSignal通知检测线程更新阈值不要用全局变量否则多线程读写会出玄学 bug。5. 训练与推理中的避坑排查从 loss NaN 到界面闪退5.1 训练 loss 变成 NaN 的排查路径现象训练到第 200 个 batch 左右loss 突然从 2.3 跳到 NaN之后再也降不下来。原因口罩数据集里混入了标注框宽高为 0 的脏数据YOLOv4 在计算 CIoU loss 时除以零。另外学习率设成 0.01 而 batch_size 只有 8 时梯度爆炸也会导致 NaN。解决先用脚本过滤掉宽或高小于 2 像素的标注框再把学习率降到 0.001加torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm10)做梯度裁剪。5.2 实时检测界面闪退的三种诱因现象点击“开始检测”后界面正常过十几秒整个窗口消失终端报Segmentation fault。原因第一种是QThread对象被 Python 垃圾回收了因为DetectThread实例没有保存为成员变量第二种是 OpenCV 的cap.read()返回的 frame 在跨线程传递时被释放第三种是 PyQt5 和 OpenCV 的 GUI 事件循环冲突cv2.imshow和QApplication不能同时用。解决把self.detect_thread DetectThread(...)挂到主窗口上frame 用frame.copy()再 emit检测线程里绝对不要调cv2.imshow所有显示都走QLabel.setPixmap。5.3 模型在 GPU 上推理结果和 CPU 不一致现象同一张图CPU 推理能检出 3 个口罩GPU 推理只检出 1 个。原因YOLOv4 的 NMS 在 GPU 上用torchvision.ops.nms在 CPU 上用自定义 numpy 实现两者的 IoU 阈值计算精度不同。另外半精度half()在部分显卡上会导致小目标置信度偏移。解决统一用torchvision.ops.nms推理时关掉half()用float()跑。如果必须用半精度把置信度阈值从 0.5 降到 0.4 补偿。5.4 PyQt5 打包成 exe 后找不到模型文件现象PyCharm 里运行正常用 PyInstaller 打包后双击 exe 报FileNotFoundError: yolov4-mask.pt。原因PyInstaller 不会自动把.pt和.cfg文件打进单文件 exe需要手动在.spec里加datas。解决在 spec 文件里写datas[(yolov4-mask.pt, .), (cfg/yolov4-mask.cfg, cfg)]然后用sys._MEIPASS拼路径import sys import os def resource_path(relative_path): if hasattr(sys, _MEIPASS): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath(.), relative_path) model_path resource_path(yolov4-mask.pt)5.5 摄像头被其他程序占用导致黑屏现象检测界面一片黑终端无报错cap.isOpened()返回 True。原因Windows 下摄像头是独占设备微信、钉钉或浏览器可能后台占用了。另外 USB 3.0 接口插在 USB 2.0 口上也会导致取流失败。解决换一个摄像头索引cv2.VideoCapture(1)试试或者在设备管理器里禁用再启用摄像头。Linux 下用lsof /dev/video0查占用进程。6. 把 mAP 从 0.82 推到 0.91三个我反复验证过的调优习惯训练完第一版模型后用test.txt跑一遍 mAP如果只有 0.82 左右别急着加数据先按下面三个方向调。第一个习惯是重新聚类 anchor。YOLOv4 默认的 anchor 是基于 COCO 数据集的口罩的宽高比集中在 1:1 到 1:1.5 之间和 COCO 的 1:3 差很远。用 k-means 在自己的标注框上跑一遍把cfg里的anchors换成新值mAP 通常能涨 3 到 5 个点。import numpy as np from sklearn.cluster import KMeans def cluster_anchors(label_dir, n_clusters9): boxes [] for txt_file in os.listdir(label_dir): with open(os.path.join(label_dir, txt_file)) as f: for line in f: _, _, _, w, h map(float, line.strip().split()) boxes.append([w, h]) boxes np.array(boxes) kmeans KMeans(n_clustersn_clusters, random_state0).fit(boxes) anchors kmeans.cluster_centers_ # 按面积排序YOLOv4 要求 anchor 从小到大排列 anchors anchors[np.argsort(anchors[:, 0] * anchors[:, 1])] return anchors anchors cluster_anchors(./labels) print(anchors)第二个习惯是加马赛克增强。YOLOv4 原版训练里用了 Mosaic 数据增强把四张图拼成一张能显著提升小目标和遮挡场景的鲁棒性。在 PyTorch 的 Dataset 里实现时注意拼接后的图要重新计算所有框的坐标越界的框直接裁掉。我一般把 Mosaic 的概率设成 0.5太高会导致训练前期 loss 震荡。第三个习惯是余弦退火学习率。口罩数据集通常只有几千张用 step 衰减容易在后期陷入局部最优。换成torch.optim.lr_scheduler.CosineAnnealingLR初始学习率 0.001最小学习率 0.00001训练 100 个 epochmAP 曲线会比 step 衰减平滑很多。验证时每 5 个 epoch 跑一次val.txt保存 mAP 最高的那个权重不要用最后一个 epoch 的。这三个习惯我用了两年多在工地安全帽检测、医院口罩检测、园区门禁三个项目里都复现过mAP 稳定在 0.89 到 0.92 之间。如果你的模型在逆光或夜间红外场景下还是翻车优先检查训练集里有没有对应的样本而不是改模型结构。数据决定上限模型只是逼近上限的工具。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

别花冤枉钱,手把手教你如何自己注册网站及安全选型 2026/9/28 0:59:21

别花冤枉钱,手把手教你如何自己注册网站及安全选型

别花冤枉钱,手把手教你如何自己注册网站及安全选型 别再被那些花里胡哨的模板网站骗了,真的,太丑且不够用。很多老板为了省那点服务器钱,随便拖个拖拽式建站工具,结果上线三天就被黑得页面乱码,或者加载慢到客户直接关掉。这时候你才意识到,问题根本不…

阅读更多 →
2026最新wordpress响应式相册主题报价全解,别被低价坑 2026/9/28 0:59:14

2026最新wordpress响应式相册主题报价全解,别被低价坑

2026最新wordpress响应式相册主题报价全解,别被低价坑 做视觉类官网,最怕什么?不是代码报错,是打开网页那一刻的廉价感。很多甲方拿着几块钱买的模板,觉得只要换上自己的图就能用,结果在手机上缩放变形,在高分屏上模糊不清,客户看一眼就…

阅读更多 →
温州网站设计制作避坑指南:不懂代码也能拿到靠谱建站报价 2026/9/28 0:58:55

温州网站设计制作避坑指南:不懂代码也能拿到靠谱建站报价

温州网站设计制作避坑指南:不懂代码也能拿到靠谱建站报价 自己不会代码想做网站,最头疼的不是功能多复杂,而是怕被忽悠。很多温州老板找温州网站设计制作公司,第一句话就问“多少钱”,结果对方要么报价低得离谱,要么高得吓人,心里完全没底。别急,今天…

阅读更多 →
避坑指南:5个wordpress微信插件实战案例,拒绝被割韭菜 2026/9/28 0:58:55

避坑指南:5个wordpress微信插件实战案例,拒绝被割韭菜

避坑指南:5个wordpress微信插件实战案例,拒绝被割韭菜 找建站公司最怕什么?不是技术牛不牛,而是怕被当“猪”宰。报价单上一行“微信集成开发”,轻则几千,重则上万,最后交付的往往是个只能收个关注、连菜单都改不了的半成品。很多老板花大价…

阅读更多 →
wordpress主题ruikedu多少钱?3个真实案例拆解费用陷阱 2026/9/28 0:58:49

wordpress主题ruikedu多少钱?3个真实案例拆解费用陷阱

wordpress主题ruikedu多少钱?3个真实案例拆解费用陷阱 改个需求建站公司拖一周,这种痛只有被坑过的人才懂。更扎心的是,当你拿着合同去问“到底多少钱能改好”,对方往往支支吾吾,报价单上那一栏“功能开发费”写得模棱两可,让你心里直…

阅读更多 →
网站开发的薪资是多少?不懂代码也能用免费工具搞定 2026/9/28 0:58:23

网站开发的薪资是多少?不懂代码也能用免费工具搞定

网站开发的薪资是多少?不懂代码也能用免费工具搞定 想做个网站展示产品,或者接个私单赚点外快,很多人第一反应是找外包。一问价格,几万块起步,还要等一个月。其实,如果你只是个人站长、小企业主,甚至是想转行的运营人员,完全不需要一上来就投入巨额资…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉