ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PyQt5与YOLOv5交互界面开发:从模型推理到图形化系统落地

PyQt5与YOLOv5交互界面开发:从模型推理到图形化系统落地 简介PyQt5与YOLOv5结合的多目标检测图形界面项目面向刚接触PyQt5开发及YOLO算法的初学者以可直接运行的完整项目演示界面设计与后端逻辑分离的开发思路覆盖常用控件、模型加载、检测结果展示等环节适合作为毕业设计或课程练手模板帮助读者从零搭建自己的检测工具。资源包共112个文件压缩后83.46MB内含26个Python源码、25个YAML配置、33个编译缓存文件、3个模型权重以及测试视频、图片和界面文件其中源码对应界面与业务逻辑配置与权重支撑模型调用视频图片便于运行效果验证整体结构层次清晰便于按需定位。目前已有8873人学习下载通过项目可掌握PyQt5信号槽与布局管理、理解YOLOv5检测流程与源码组织并学习拆分界面与逻辑层的方法让代码更易维护和扩展。建议搭配PyTorch与PyQt5开发书籍研读理论与实践结合快速将算法封装为图形工具是目标检测方向入门不可多得的实战素材。1. pyqt5yolov5python命令行的检测模型怎么变成你说得清的界面系统很多人把 YOLOv5 跑通之后就卡住了模型在终端里能出框、能打印坐标但真正要交给别人用、要演示效果、要录一段画面出来命令行那套东西拿不出手。pyqt5yolov5python 这个组合本质上就是给检测模型包一层能落地、能交付的图形界面。我拆过不少这类项目最常见的需求是打开软件、选一张图或一段视频、点一下按钮看检测结果再把结果导出来。看起来简单真正做完你才知道界面线程和推理线程的协调、图像格式来回转换、模型路径和权重加载这几件事随便一个细节没处理好整套东西就翻车。这套组合适合三类人做毕设需要展示系统的学生手头有检测需求但不想用现成 Web 服务的开发者以及想把内部算法封装给非技术同事用的工程师。下面按我从环境搭建到打包发布的一整套实操顺序来讲每一步都给你能直接复现的命令和代码。2. 环境搭建Python 版本、PyQt5 与 YOLOv5 的依赖三角关系2.1 虚拟环境隔离Python 3.8 与 torch 的版本匹配YOLOv5 官方仓库对 Python 版本的要求不算苛刻但实践下来最稳的是 Python 3.8 或 3.9。Python 3.10 以上也能跑但部分依赖编译容易出问题尤其是 Windows 上没有预编译轮子的时候报错能把你绕晕。PyQt5 本身对 Python 版本没有太多限制3.8 到 3.12 都有对应轮子所以我把版本锚定在 3.8主要是迁就 torch 和 torchvision 的选择空间。conda create -n yolo_gui python3.8 -y conda activate yolo_gui pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117这里我选的是 CUDA 11.7 对应的 torch 1.13.1这个组合在 YOLOv5 官方 requirements.txt 标注的兼容范围内和 PyQt5 5.15 系列也共处得很好。如果你机器没装 CUDA把--index-url换成 CPU 版的安装源就行推理速度会慢一些但整个流程不受影响。安装完先确认一下 torch 能不能正常调用 GPUpython -c import torch; print(torch.cuda.is_available())这一步输出True再往后走。我见过有人装完 torch 没验证就一路往下最后训练时发现用的是 CPU白白浪费几天时间。2.2 PyQt5 安装与验证pip 源、designer 工具链PyQt5 的安装比想象中容易踩坑。直接pip install pyqt5在国内网络环境下经常卡住解决方法是换 pip 国内镜像源。我一般习惯在虚拟环境里把全局源配好免得每次安装都折腾。pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyqt55.15.9 pyqt5-toolspyqt5-tools这个包里带了 Qt Designer就是可视化拖拽界面的设计器。清华源上 5.15.9 这个版本比较稳其他版本在部分 Windows 环境下会出现QT_QPA_PLATFORM_PLUGIN相关报错。装完验证一下能不能正常创建 QApplicationimport sys from PyQt5.QtWidgets import QApplication, QLabel app QApplication(sys.argv) label QLabel(PyQt5 OK) label.show() app.exec_()如果这段能弹出一个窗口说明 PyQt5 基础环境没问题。这里的QApplication是所有 Qt 界面程序必须创建的对象它管理整个事件循环exec_()是进入事件循环的入口窗口显示之后程序不会立刻退出而是等待用户交互。2.3 YOLOv5 依赖清单requirements 里藏着哪些坑YOLOv5 仓库根目录下有个requirements.txt里面列了它运行时需要的全部依赖。但你直接pip install -r requirements.txt会遇到一个现实问题它会再次安装 torch 和 torchvision把刚才装好的 GPU 版本覆盖掉。因为 requirements.txt 里对 torch 的约束是torch1.7.0pip 会自动装最新版这就破坏了版本一致性。sed -i /^torch/d;/^torchvision/d requirements.txt pip install -r requirements.txt我的做法是先装好 GPU 版 torch然后删掉 requirements.txt 里跟 torch 相关的行再安装其余依赖。这个过程会遇到几个经典问题pyyaml版本过低导致yaml.load报错numpy版本不兼容导致np.int属性缺失matplotlib版本太新导致某些绘图函数变更。后两个是升级依赖时最常见的翻车点解决办法是把 numpy 锁在 1.23 左右。pip install numpy1.23.5 matplotlib3.7.1 pyyaml5.4.1这一套下来检测部分需要的环境就齐了。YOLOv5 本身是个 Python 包它的核心检测逻辑在detect.py和models目录下不依赖额外服务所以环境配好就等于基础就绪。验证环境是否完整的办法是跑一次官方的预训练推理python detect.py --weights yolov5s.pt --source data/images/bus.jpg如果能在runs/detect/exp下生成带框的图片说明模型推理链路是通的。3. 数据与训练从 labelme 标注到 YOLOv5 可用的数据集3.1 标注工具选型与格式转换脚本训练自己的数据集之前标注是绕不开的一步。YOLO 系列用的标注格式是 txt 文件每行一个目标类别id cx cy w h坐标都是归一化到 0 到 1 的比值。labelme 默认输出的是 JSON 格式记录的是多边形顶点的绝对坐标不能直接丢给 YOLOv5 训练需要转一道。我用 labelme 标注后用脚本统一转换格式转换这一步是整个数据集准备过程中最容易出错的地方坐标计算错了模型训练出来完全乱套。转换脚本如下import json import os def convert_labelme_json(json_path, class_names, output_dir): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w, img_h data[imageWidth], data[imageHeight] txt_name os.path.splitext(os.path.basename(json_path))[0] .txt txt_path os.path.join(output_dir, txt_name) with open(txt_path, w) as out: for shape in data[shapes]: label shape[label] if label not in class_names: continue class_id class_names.index(label) points shape[points] # 取多边形外接矩形 xs [p[0] for p in points] ys [p[1] for p in points] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) cx (x_min x_max) / 2 / img_w cy (y_min y_max) / 2 / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h out.write(f{class_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n) class_names [person, car, bicycle] # 按你的类别顺序定义逻辑说明先读取 labelme JSON 里的图片宽高和每个标注形状对每个多边形取外接矩形的四角坐标再把矩形中心点坐标和宽高分别除以图片宽高做归一化。类别顺序class_names必须和训练时的 data.yaml 保持一致这里定义的是person、car、bicycle假如你后面训练时把顺序改了之前转换的所有 txt 文件全部作废这个我有过血泪经验。3.2 data.yaml 与训练超参数YOLOv5 训练前需要整理数据目录结构标准做法是一个根目录下分images/train、images/val、labels/train、labels/val四个子目录图片放 images 下的对应子目录txt 标签放 labels 下对应子目录两个子目录里同名文件一一对应。# data.yaml train: ./dataset/images/train val: ./dataset/images/val nc: 3 names: [person, car, bicycle]data.yaml 里面train和val指向数据集路径nc是类别总数names是类别名列表。路径可以用绝对路径也可以用相对路径但相对路径是相对于你执行训练命令时所在目录建议直接用绝对路径省得换目录后莫名其妙找不到图片。训练启动命令python train.py --img 640 --batch 16 --epochs 100 --data dataset/data.yaml --weights yolov5s.pt --cache参数说明--img是训练输入图像的缩放尺寸640 是速度和精度的常规平衡点--batch是批大小受显存限制16 对应大约 8GB 显存显存小就降到 8--epochs是训练轮数100 轮对中小数据集基本够--weights表示用预训练权重yolov5s.pt做迁移学习--cache把图片预加载到内存能明显加快训练速度代价是多吃内存。超参数文件data/hyps/hyp.scratch-low.yaml里有一堆训练参数我用过默认值也能有不错的收敛效果但有两个需要手动调整超参数默认值建议调整依据lr00.010.005~0.01数据集小时调低防震荡mosaic1.00.5~1.0目标极小场景建议保持 1.0大幅提升泛化batch_size 在命令行处修改168~32以显存不溢出为准lr0是初始学习率学习率太高会出现 loss 曲线前期暴涨、后期震荡不收敛mosaic是马赛克增强概率它把四张图拼成一张训练对检测小目标和密集场景特别有效但训练耗时约增加两成。3.3 训练恢复、早停与模型导出训练到一半中断是家常便饭断电、显存溢出、手误关了终端都会发生。YOLOv5 的--resume参数就是后悔药python train.py --resume runs/train/exp/weights/last.pt它会读取训练状态接着上次的 epoch 继续跑。我用这个参数多次训练轮数、学习率调度、best 和 last 权重的选择都会从 checkpoint 里恢复不存在断点续训丢进度的问题。训练完成后的模型导出YOLOv5 提供了 export.pypython export.py --weights runs/train/exp/weights/best.pt --include torchscript onnx导出为 TorchScript 的好处是部署阶段不需要源模型文件结构一个 .pt 文件就能加载推理导出 ONNX 格式则是为了后来转成其他推理引擎。我这里一般导出 TorchScript因为 PyQt5 里加载最省事不需要额外装 onnxruntime。4. PyQt5 界面集成视频实时检测与结果展示4.1 界面布局与信号槽设计界面布局我用 Qt Designer 拖出来再转成 .py 文件也有人喜欢纯代码写界面。对检测工具类的软件核心控件就三样一个用来显示画面的 QLabel一个选择文件或开启摄像头的按钮一个显示检测统计信息的文本区。下面这段代码演示了如何用纯代码搭一个最小可用的窗口import sys from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout, QFileDialog class DetectorWindow(QWidget): def __init__(self): super().__init__() self.setWindowTitle(YOLOv5 检测) self.setGeometry(100, 100, 800, 600) self.btn_open QPushButton(选择图片) self.btn_open.clicked.connect(self.open_image) self.label_display QLabel(图片显示区域) self.label_info QLabel(检测结果) layout QVBoxLayout() layout.addWidget(self.btn_open) layout.addWidget(self.label_display) layout.addWidget(self.label_info) self.setLayout(layout) def open_image(self): file_path, _ QFileDialog.getOpenFileName( self, 选择图片, , 图片文件 (*.jpg *.png *.bmp) ) if file_path: self.label_info.setText(f已选择{file_path}) if __name__ __main__: app QApplication(sys.argv) window DetectorWindow() window.show() sys.exit(app.exec_())clicked.connect是 Qt 的信号槽机制按钮点击后自动调用open_image函数QFileDialog.getOpenFileName弹出文件选择窗口返回用户选中的路径。这里self.setLayout(layout)把纵向布局装到窗口上控件会随着窗口缩放自动调整。4.2 QThread 推理线程与防卡死界面和推理在同一个线程是最常见的翻车点。YOLOv5 加载模型要几秒钟单张图推理也要几百毫秒如果直接在主线程里跑界面会卡死——窗口无响应、按钮点了没反应严重时直接被系统标成「未响应」。解决这个问题的标准方案是开一个专门做推理的 QThread 子线程import cv2 import torch from PyQt5.QtCore import QThread, pyqtSignal class DetectThread(QThread): result_ready pyqtSignal(object, object) # 原图, 检测结果 def __init__(self, weights_path, image_path): super().__init__() self.image_path image_path self.model torch.hub.load(ultralytics/yolov5, custom, pathweights_path, force_reloadFalse) def run(self): img cv2.imread(self.image_path) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results self.model(img_rgb, size640) self.result_ready.emit(img, results)这里pyqtSignal(object, object)定义了带两个参数的自定义信号run()方法在start()调用后在子线程中执行。模型在__init__里加载只加载一次每次run只做推理。torch.hub.load(ultralytics/yolov5, custom, pathweights_path)是加载本地训练好的权重文件size640指定推理时输入尺寸。推理完成后用emit把结果发回主线程主线程里连接这个信号更新界面。这样界面不会卡因为耗时操作全在子线程完成。4.3 图像显示组件与结果保存检测结果要显示到 QLabel 里需要经历 OpenCV 图像 → QImage → QPixmap 的类型转换这一步写错会出现图片倒置、颜色变蓝、显示不出来的问题from PyQt5.QtGui import QImage, QPixmap def show_result_on_label(self, cv_img, results, label_widget): # 把检测框画在图上 img results.render()[0] # YOLOv5 自带画框方法返回 numpy 数组 h, w, ch img.shape bytes_per_line ch * w qimage QImage(img.data, w, h, bytes_per_line, QImage.Format_RGB888) pixmap QPixmap.fromImage(qimage) scaled_pixmap pixmap.scaled(label_widget.width(), label_widget.height()) label_widget.setPixmap(scaled_pixmap)results.render()[0]是 YOLOv5 推理结果对象自带的方法直接在原图上画好框和标签返回 numpy 格式的图片省去手动调 cv2.rectangle 的繁琐。QImage.Format_RGB888对应三通道彩色图如果你传的是 BGR 图显示出来颜色就全反了必须在前面用cv2.cvtColor转成 RGB。pixmap.scaled把图片缩放到 QLabel 的尺寸不改这一行的话大图会直接把界面撑爆。结果保存按检测到的目标数量走不同的路径静态图片直接cv2.imwrite保存画框后的图视频则用cv2.VideoWriter逐帧写入帧率保持原来视频的帧率。5. 常见坑位排查从安装到推理的六条血泪记录5.1 PyQt5 安装后启动报could not load the Qt platform plugin windows现象装了 PyQt5 之后跑最简单的窗口程序直接弹出could not load the Qt platform plugin windows程序崩溃。原因pip 装 PyQt5 时 platform plugin 的路径没有被正确识别常见于多版本 Python 混装环境。解决先确认 PyQt5 相关包是否完整安装缺哪个补哪个pip install pyqt5-plugins pyqt5-qt5如果还不行加环境变量QT_QPA_PLATFORM_PLUGIN_PATH指向 site-packages 下 PyQt5 的 plugins 目录。我一般在代码开头加一段兼容逻辑import os os.environ[QT_QPA_PLATFORM_PLUGIN_PATH] os.path.join( os.path.dirname(__file__), venv, Lib, site-packages, PyQt5, Qt5, plugins, platforms )5.2 labelme 安装把 PyQt5 环境搞坏了现象先装 PyQt5 跑通了界面后来为了标注数据pip install labelme再启动原来程序发现界面样式突变甚至模块冲突。原因labelme 会在安装时拉它的 PyQt5 依赖pip 为了满足依赖把 PyQt5 升级或降级到兼容版本和原来的版本不一致。解决给标注单独建一个虚拟环境跟界面开发环境彻底隔离。从那以后我手动给每个项目都建独立 conda 环境避免任何两个项目共用一套 site-packages。如果已经坏掉的就重新建环境装一遍。5.3 界面一推理就卡死现象点击检测按钮后整个窗口变成白屏无法操作等几秒后恢复视频检测时画面一顿一顿的。原因推理和 UI 刷新在同一个线程。YOLOv5 推理要占用 CPU 或者 GPUQt 事件循环被阻断界面自然就死了。解决把推理放进 QThread 子线程界面只用信号槽接收结果。这个方法前面已经写过了这是所有 PyQt5 集成 YOLOv5 项目里最重要的一步没有之一。5.4 图片显示颜色变蓝现象检测框和标签都在但整张图偏蓝色调看起来很不自然。原因OpenCV 的imread读出来是 BGR 格式没有转换就把数据塞进QImage.Format_RGB888Qt 把 BGR 当 RGB 解析红和蓝通道互换了。解决推理前把图转成 RGB或者构造 QImage 时用Format_BGR888格式。前者更通用因为 YOLOv5 的推理输入按 RGB 预处理转一次解决了显示和推理的双重问题。5.5 训练时显存溢出 OOM现象训练跑了一半报CUDA out of memory进程直接退出。原因--batch设置过大或--workers数据加载线程数过多超出显存容量。这问题在我用单卡 8GB 显存训 YOLOv5s 时经常出现。解决batch 减半从 32 降到 16再不行降到 8--workers从默认 8 降到 4不要用--cache以外的--rect矩形训练组合。YOLOv5 还有个--device 0参数明确指定 GPU。5.6 导出 ONNX 后推理结果对不上现象TorchScript 推理正常但 ONNX 导出后同一张图检测框位置偏移置信度明显下降。原因ONNX 输入的通道顺序或归一化方式与 PyTorch 原始模型不一致常见于转其他推理框架时预处理没对齐。解决导出时固定好opset版本推理端严格按 YOLOv5 源码的预处理方式BGR 转 RGB、除以 255 归一化、letterbox 缩放。如果不做推理引擎部署直接用 TorchScript 格式就够用了别折腾 ONNX。我自己用 TorchScript 格式从没出过这样的问题。6. 进阶把界面打成 exe 与推理速度优化交付给别人的时候不可能要求对方配 Python 环境、装 CUDA、下载模型权重。打成 exe 是必走的一步。PyInstaller 是目前最稳的打包工具但 YOLOv5 这种带 torch 和 PyQt5 的项目打包体积通常 2GB 起步过程和踩坑点非常固定。pip install pyinstaller pyinstaller -n YOLODetector --windowed --add-data models;models --add-data yolov5s.pt;. main.py--windowed表示不显示命令行窗口--add-data把模型权重文件打包进可执行文件分号前面是源路径分号后面是目标目录打包 torch 项目经常遇到ModuleNotFoundError需要在 spec 文件里手动加 hidden imports--hidden-import numpy --hidden-import cv2 --hidden-import torch我用 PyInstaller 打包过几个界面程序有一条经验很重要尽量用英文路径打包相关文件和输出目录不要出现中文。PyInstaller 对中文路径的支持一直不好打包过程能跑完但生成的 exe 启动时报各种奇怪的错。推理速度优化方面实际操作中性价比最高的是切换半精度推理。YOLOv5 的模型在加载时支持半精度self.model torch.hub.load(ultralytics/yolov5, custom, pathweights_path) self.model.half() # 转为 FP16 推理half()把模型权重和输入都转到torch.float16推理速度提升明显显存占用直接减半代价是检测精度损失很小在目标较大、场景简单的业务场景里完全感知不到差异。另一个技巧是把--img-size从 640 降到 320检测速度提升约 3 到 4 倍但对小目标的漏检率会升高。项目里如果检测对象距离近、尺寸大我一般直接降到 416速度和精度平衡得不错。模型加载耗时也值得优化。torch.hub.load每次启动时如果不加force_reloadFalse它会去检查远程仓库版本导致启动慢几秒。设置force_reloadFalse会直接读本地缓存。我把权重路径写进配置文件程序启动时先读配置再加载模型换模型不用改代码。最后验收阶段我有两个固定动作先在目标机器上跑一段压力测试连续检测 100 张不同场景的图片看是否出现内存暴涨或显存泄漏再把打包好的 exe 在一个干净环境里双击运行验证模型路径、依赖库是否都内置齐全。从那以后我每次做完检测界面程序都会强制走一遍这两项验收流程宁可多花半小时也不要在交付现场出洋相。这套流程从环境搭建到打包交付一条线走下来绝大多数坑都提前踩平了希望帮到你。本文还有配套的精品资源点击获取
返回列表