第五节 Pyside6可视化界面

目录

[5.1 Pyside6](#5.1 Pyside6)

[5.2 界面设计](#5.2 界面设计)

[5.3 程序设计](#5.3 程序设计)

完整程序代码:

运行结果:

5.1 Pyside6

PySide6是Qt for Python项目的一部分,它提供了对Qt 6.0的官方Python绑定。Qt是一个跨平台的C++应用程序开发框架,以其丰富的UI组件、优秀的性能和跨平台能力而闻名。PySide6继承了Qt的这些优点,同时结合了Python的简洁性和开发效率。

博客: 【Python学习日记:PySide6】【持续更新】-CSDN博客

【Python桌面应用】PySide6 界面开发完全指南_pyside6中文手册-CSDN博客

Pyside6 安装指令:pip install pyside6

如何找到qtdesiger?

先输入指令: where python

这是当前环境下,能找到的python.exe。找到yolov5虚拟环境的路径:D:\miniconda\envs\yolov5\python.exe 在其路径下找/Libs/site-packages/PySide6/designer.exe 。并右击创建快捷方式。

由于designer.exe最后生成的文件是后缀是.ui,还不是python的编译文件,还需要下载qt来进行将文件转为可编译文件。

下面是在vscode安装qt for python

5.2 界面设计

(1)、先设计好界面。

(2)Ctrl+s将文件保存到yolov5-7.0中。

(3)、将.ui文件转化成.py文件,找到.ui文件,右键找到Compile Qt UI File并点击,就可以将文件进行转化了。

5.3 程序设计

程序功能描述:用户选择任意一张图片或一段视频(如荔枝品种图),程序自动调用训练好的 YOLOv5 模型进行推理,并将原图和检测结果分别显示在两个窗口中。

完整程序代码:

python 复制代码
import sys
from PySide6.QtWidgets import QMainWindow, QApplication, QFileDialog  # 导入 Qt 核心组件
from main_window_ui import Ui_MainWindow  # UI 设计文件(由 Qt Designer 生成)
from PySide6.QtGui import QPixmap, QImage  # 用于图像显示
import torch  # 加载 YOLOv5 模型
from PySide6.QtCore import QTimer  # 控制视频帧刷新频率
import cv2  # OpenCV 处理图像和视频

# -----------------------------
# 工具函数:将 OpenCV 图像转换为 QImage(供 Qt 显示)
# -----------------------------
def convert2QImage(img):
    """
    将 OpenCV 的 BGR 图像(numpy 数组)转换为 Qt 的 QImage
    注意:OpenCV 默认是 BGR 格式,需要转成 RGB 才能正确显示
    """
    height, width, channel = img.shape  # 获取图像尺寸和通道数
    return QImage(img, width, height, width * channel, QImage.Format_RGB888)

# -----------------------------
# 主窗口类:继承 QMainWindow 和 UI 界面
# -----------------------------
class Mainwindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(Mainwindow, self).__init__()
        self.setupUi(self)  # 初始化 UI 界面(从 .ui 文件加载)
        
        # 创建定时器,用于视频逐帧处理
        self.timer = QTimer()
        self.timer.setInterval(1)  # 设置间隔为 1ms(实际帧率由视频源决定)
        
        # 加载本地训练好的 YOLOv5 模型(路径需与训练时一致)
        self.model = torch.hub.load("./", "custom", path="runs/train/exp5/weights/best.pt", source="local")
        
        # 绑定按钮事件(信号槽连接)
        self.bind_slots()

    # -----------------------------
    # 图像预测函数:对单张图片进行推理并返回结果图像
    # -----------------------------
    def image_pred(self, file_path):
        """
        输入:图片路径(字符串)
        输出:YOLOv5 推理后的图像(QImage)
        """
        results = self.model(file_path)  # 使用模型进行推理(返回结果对象)
        image = results.render()[0]     # render() 返回一个包含原始图+框的 numpy 数组([0] 取第一张图)
        return convert2QImage(image)    # 转换为 QImage 供 Qt 显示

    # -----------------------------
    # 打开图片并执行检测
    # -----------------------------
    def open_image(self):
        print("点击了图片检测")  # 日志输出,方便调试
        self.timer.stop()       # 停止视频定时器(避免干扰)
        
        # 弹出文件选择对话框(默认目录:train 图片文件夹,支持 JPG/PNG/JPEG)
        file_path = QFileDialog.getOpenFileName(
            self,
            caption="选择图片",
            dir="./datasets/images/train",  # 默认打开目录
            filter="*.jpg;*.png;*.jpeg"     # 支持的文件格式
        )
        
        if file_path[0]:  # 如果用户选择了文件(file_path 是元组:(路径, 过滤器)
            file_path = file_path[0]  # 提取路径字符串
            
            # 执行图像检测并获取结果图像
            qimage = self.image_pred(file_path)
            
            # 显示原始图片到输入区域
            self.input.setPixmap(QPixmap(file_path))
            
            # 显示检测结果到输出区域
            self.output.setPixmap(QPixmap.fromImage(qimage))

    # -----------------------------
    # 视频帧预测函数:逐帧处理视频流
    # -----------------------------
    def video_pred(self):
        """
        每次调用都会读取一帧视频,进行推理并更新界面
        """
        ret, frame = self.video.read()  # 读取下一帧(ret=True 表示成功读取)
        
        if not ret:  # 如果视频结束或读取失败
            self.timer.stop()  # 停止定时器
            self.video.release()  # 释放摄像头资源
            self.video = None  # 清空视频对象引用
            return
        
        #  关键修复:OpenCV 默认是 BGR 格式,Qt 需要 RGB,必须转换
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # 转换颜色空间
        
        # 显示当前帧到输入区域(原始视频画面)
        self.input.setPixmap(QPixmap.fromImage(convert2QImage(frame)))
        
        # 对当前帧进行目标检测
        results = self.model(frame)
        image = results.render()[0]  # 获取渲染后的图像(带边界框)
        
        # 显示检测结果到输出区域
        self.output.setPixmap(QPixmap.fromImage(convert2QImage(image)))

    # -----------------------------
    # 打开视频文件并开始播放
    # -----------------------------
    def open_video(self):
        print("点击视频检测")
        self.timer.stop()  # 停止之前可能正在运行的定时器
        
        # 弹出文件选择对话框(只允许选择 MP4 文件)
        file_path = QFileDialog.getOpenFileName(
            self,
            caption="选择视频",
            dir="./datasets",  # 默认打开 datasets 目录
            filter="*.mp4"     # 只允许选择 mp4 视频文件(注意:这里原来是 *.mp4,不是 *.mpg)
        )
        
        if file_path[0]:  # 用户选择了文件
            file_path = file_path[0]
            self.video = cv2.VideoCapture(file_path)  # 打开视频文件
            self.timer.start()  # 启动定时器,每隔 1ms 调用一次 video_pred()

    # -----------------------------
    # 绑定按钮事件(信号 -> slot)
    # -----------------------------
    def bind_slots(self):
        self.det_image.clicked.connect(self.open_image)   # "图片检测"按钮点击触发 open_image
        self.pushButton_2.clicked.connect(self.open_video) # "视频检测"按钮点击触发 open_video
        self.timer.timeout.connect(self.video_pred)      # 定时器超时触发 video_pred(用于视频帧处理)

# -----------------------------
# 主程序入口
# -----------------------------
if __name__ == "__main__":
    app = QApplication(sys.argv)  # 创建应用实例
    window = Mainwindow()         # 创建主窗口
    window.show()                 # 显示窗口
    app.exec()                    # 启动事件循环(等待用户操作)

运行结果: