简单实现PyQt调用YOLOv11

PyQt5简单调用YOLO v1算法

通过简单代码实现PyQt5调用YOLO v1算法

首先通过PyQt设计窗口界面:

基础功能:打开相机、关闭相机、启用检测、拍照、清理窗口、保存图像、保存录像、停止录像、选择保存路径等

设置初始化参数:

   # 初始化参数
    def __init__(self):                                     # 构造函数
        super().__init__()                                  # 调用基类的构造函数进行初始化
        self.setupUi(self)                                  # 调用setupUi方法,根据Ui_MainWindow设计设置界面
        self.label_ShowCam.setScaledContents(True)          # 设置窗口自适应
        self.label_ShowPhoto.setScaledContents(True)     # 设置窗口自适应
        self.timer_camera = QtCore.QTimer()                 # 定义定时器,控制视频帧率
        self.cap = cv2.VideoCapture()                       # 初始化视频流
        self.CAM_NUM = 0                                    # 设置相机索引
        self.model = YOLO("yolo11l.pt")
        Timer = QtCore.QTimer(self)
        Timer.timeout.connect(self.showtime)
        Timer.start()
        self.Stop_Record = False
        self.action()

开启相机:

    # 开启相机
    def OpenCamera_button(self):
        if not self.timer_camera.isActive():                # 判断定时器是否启动
            flag = self.cap.open(self.CAM_NUM)              # 打开摄像头
            if not flag:
                self.label_ShowCam.setText("相机连接失败")
            else:
                self.timer_camera.start(40)                 # 设置定时器30ms,每过40ms读取一帧
                self.label_ShowCam.setText("相机正在打开...")

    def OpenCamera_Thread(self):
        flag, img = self.cap.read()                         # 读取视频流
        frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        # 色彩转换RGB
        flip_img = cv2.flip(frame, 1)                       # 画面镜像翻转
        if self.checkBox_AIdetect.isChecked():
            result_img = self.model.predict(flip_img, conf=0.5, device="0")        # 导入模型检测
            return result_img
        return flip_img

显示结果:

 # 显示相机实时画面
    def show_camera(self):
        re_img = self.OpenCamera_Thread()
        if self.checkBox_AIdetect.isChecked():
            detect_img = re_img[0].plot()  # 输出检测结果图片(含外框)
        else:
            detect_img = re_img                           # 输出检测结果图片(含外框)
        # 视频图像格式转换为QImage
        img01 = QImage(detect_img.tobytes(), detect_img.shape[1], detect_img.shape[0], QImage.Format_RGB888)
        pixmap = QPixmap.fromImage(img01)
        self.label_ShowCam.setPixmap(pixmap)                # 在label上显示QImage

关闭相机:

    # 关闭相机
    def CloseCam(self):
        if self.timer_camera.isActive():
            self.timer_camera.stop()                        # 关闭定时器
            self.cap.release()                              # 释放视频流
            self.label_ShowCam.setText("相机已关闭")

完整代码

import sys                                  # 导入系统模块,用于访问命令行参数和系统相关功能
import cv2
from PyQt5 import QtCore, QtWidgets         # 导入PyQt5的主要模块
from PyQt5.QtGui import *                   # 导入QtGui模块的所有内容,用于图形功能
from PyQt5.QtWidgets import QMainWindow, QMessageBox  # 导入QtWidgets模块中的一些特定类
from ultralytics import YOLO
import time
import os
from threading import Thread
"""以下是唯一需要更改的地方——> from 你ui文件的文件名 Ui_MainWindow"""
from CamDetectShow import Ui_MainWindow       # 导入UI类,这个类包含了你的主窗口设计
'''
    QFileDialog可以帮助用户选择文件路径
    QMainWindow则是创建具有菜单、工具栏和状态栏的主窗口的起点。
    QMessageBox可以用于向用户显示提示或警告信息
'''


class PyQtMainEntry(QMainWindow, Ui_MainWindow):            # 定义一个继承自QMainWindow和Ui_MainWindow的类
    # 初始化参数
    def __init__(self):                                     # 构造函数
        super().__init__()                                  # 调用基类的构造函数进行初始化
        self.setupUi(self)                                  # 调用setupUi方法,根据Ui_MainWindow设计设置界面
        self.label_ShowCam.setScaledContents(True)          # 设置窗口自适应
        self.label_ShowPhoto.setScaledContents(True)     # 设置窗口自适应
        self.timer_camera = QtCore.QTimer()                 # 定义定时器,控制视频帧率
        self.cap = cv2.VideoCapture()                       # 初始化视频流
        self.CAM_NUM = 0                                    # 设置相机索引
        self.model = YOLO("yolo11l.pt")
        Timer = QtCore.QTimer(self)
        Timer.timeout.connect(self.showtime)
        Timer.start()
        self.Stop_Record = False
        self.action()

    # 激活按钮
    def action(self):
        self.pushButton_OpenCam.clicked.connect(self.OpenCamera_button)     # 设置开启相机
        self.timer_camera.timeout.connect(self.show_camera)                 # 开启相机
        self.pushButton_CloseCam.clicked.connect(self.CloseCam)             # 关闭相机
        self.pushButton_TakePhoto.clicked.connect(self.TakePhoto)           # 拍照
        self.pushButton_SaveImg.clicked.connect(self.Save_Img)              # 保存图片
        self.pushButton_SaveVideo.clicked.connect(self.open_SaveVideo_thread1)          # 保存视频
        self.pushButton_SelectFile.clicked.connect(self.Select_File)         # 选择文件夹
        self.pushButton_StopSaveVideo.clicked.connect(self.Stop_Record_button)
        self.checkBox_AIdetect.setChecked(False)

    def showtime(self):
        self.label_Time.setText(str(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))

    # 开启相机
    def OpenCamera_button(self):
        if not self.timer_camera.isActive():                # 判断定时器是否启动
            flag = self.cap.open(self.CAM_NUM)              # 打开摄像头
            if not flag:
                self.label_ShowCam.setText("相机连接失败")
            else:
                self.timer_camera.start(40)                 # 设置定时器30ms,每过40ms读取一帧
                self.label_ShowCam.setText("相机正在打开...")

    def OpenCamera_Thread(self):
        flag, img = self.cap.read()                         # 读取视频流
        frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)        # 色彩转换RGB
        flip_img = cv2.flip(frame, 1)                       # 画面镜像翻转
        if self.checkBox_AIdetect.isChecked():
            result_img = self.model.predict(flip_img, conf=0.5, device="0")        # 导入模型检测
            return result_img
        return flip_img


    # 显示相机实时画面
    def show_camera(self):
        re_img = self.OpenCamera_Thread()
        if self.checkBox_AIdetect.isChecked():
            detect_img = re_img[0].plot()  # 输出检测结果图片(含外框)
        else:
            detect_img = re_img                           # 输出检测结果图片(含外框)
        # 视频图像格式转换为QImage
        img01 = QImage(detect_img.tobytes(), detect_img.shape[1], detect_img.shape[0], QImage.Format_RGB888)
        pixmap = QPixmap.fromImage(img01)
        self.label_ShowCam.setPixmap(pixmap)                # 在label上显示QImage

    # 关闭相机
    def CloseCam(self):
        if self.timer_camera.isActive():
            self.timer_camera.stop()                        # 关闭定时器
            self.cap.release()                              # 释放视频流
            self.label_ShowCam.setText("相机已关闭")

    # 拍照
    def TakePhoto(self):
        if self.cap.isOpened():                             # 读取单帧
            result_img = self.OpenCamera_Thread()  # 输出检测结果图片(含外框)
            if not self.checkBox_AIdetect.isChecked():
                detect_img = result_img
            else:
                detect_img = result_img[0].plot()
            # 视频图像格式转换为QImage
            img = QImage(detect_img.tobytes(), detect_img.shape[1], detect_img.shape[0], QImage.Format_RGB888)
            pixmap = QPixmap.fromImage(img)
            self.label_ShowPhoto.setPixmap(pixmap)          # 在label上显示QImage
        else:
            self.label_ShowPhoto.setText("相机打开失败")

    def Select_File(self):
        p = QtWidgets.QFileDialog.getExistingDirectory(self, "选择文件", "/")   # 获取文件夹地址
        self.lineEdit_SavePath.setText(p)                                     # 显示文件地址

    def Save_Img(self):
        FilesPath = self.lineEdit_SavePath.text()               # 获取文件夹地址
        if len(FilesPath) == 0:
            QMessageBox.information(self, "消息对话框", "请先选择文件保存地址!", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
        else:
            if os.path.isdir(FilesPath):
                local_time = time.strftime('%Y-%m-%d-%H-%M-%S')
                # 满足文件名唯一性且符合文件名定义规范
                new_name = str(local_time) + ".png"
                try:
                    save_pix = self.label_ShowPhoto.pixmap()
                    save_pix.save(os.path.join(FilesPath, new_name))
                except Exception as e:
                    QMessageBox.warning(self, "警告对话框", "请先选择拍照!", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
            else:
                QMessageBox.information(self, "消息对话框", "所选文件夹不存在!", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

    def Create_Save_Video(self):
        FilesPath = self.lineEdit_SavePath.text()                # 获取文件夹地址
        frame_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        frame_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        fps = int(self.cap.get(cv2.CAP_PROP_FPS))
        if len(FilesPath) == 0:
            QMessageBox.information(self, "消息对话框", "请先选择文件保存地址!", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
        elif os.path.isdir(FilesPath):
            local_time = time.strftime('%Y_%m_%d')
            # 满足文件名唯一性且符合文件名定义规范
            new_name = "Record_" + str(local_time) + ".avi"
            # initialize the FourCC and a video writer object
            fourcc = cv2.VideoWriter_fourcc(*'XVID')
            writer = cv2.VideoWriter(os.path.join(FilesPath, new_name), fourcc, fps, (frame_width, frame_height))
            return writer
        else:
            QMessageBox.information(self, "消息对话框", "所选文件夹不存在!", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

    def SaveVideo_Thread(self):
        while True:
            result_img = self.OpenCamera_Thread()
            if self.checkBox_AIdetect.isChecked():
                detect_img = result_img[0].plot()  # 输出检测结果图片(含外框)
            else:
                detect_img = result_img  # 输出检测结果图片(含外框)
            rgb_img = cv2.cvtColor(detect_img, cv2.COLOR_BGR2RGB)
            save_wr = self.Create_Save_Video()
            save_wr.write(rgb_img)
            Stop_Record = self.Stop_Record_button()
            if Stop_Record:
                save_wr.release()
                break

    def Stop_Record_button(self):
        self.Stop_Record = True
        return self.Stop_Record

    def open_SaveVideo_thread1(self):
        T1 = Thread(target=self.SaveVideo_Thread, args=())
        T1.start()


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)  # 创建应用程序实例
    window = PyQtMainEntry()                # 创建主窗口实例
    window.show()                           # 显示主窗口
    sys.exit(app.exec_())                   # 进入事件循环,并确保在退出时清理

### PyQt5调用YOLOv11模型进行视频检测时程序崩溃的解决方案 在处理此类问题时,可以考虑以下几个方面来排查并解决问题: #### 1. CUDA与Tensor转换问题 如果YOLOv11模型运行在GPU上,则可能会涉及CUDA Tensor与NumPy之间的数据格式转换。根据已知的信息,在将CUDA Tensor转换为NumPy数组之前,必须先将其移动到CPU上[^1]。因此,可以在代码中查找类似的张量操作部分,并确保进行了正确的转换。 例如,假设存在如下代码片段: ```python result_tensor = model(input_data) numpy_result = result_tensor.numpy() ``` 应修改为: ```python result_tensor = model(input_data) numpy_result = result_tensor.cpu().numpy() # 添加 .cpu() 方法以确保兼容性 ``` 此更改可防止因直接尝试将CUDA Tensor转换为NumPy而导致的错误。 --- #### 2. 多线程冲突 PyQt5应用程序通常在一个主线程中运行GUI事件循环。然而,当执行耗时任务(如视频帧推理)时,如果不小心引入多线程逻辑,可能导致资源争抢或未定义行为。为了规避这一风险,建议采用`QThread`或其他异步机制分离计算密集型任务。 以下是基于`QThread`的一个简单实现框架: ```python from PyQt5.QtCore import QThread, pyqtSignal import cv2 class VideoProcessingThread(QThread): frame_processed = pyqtSignal(object) def __init__(self, video_path, yolo_model): super().__init__() self.video_path = video_path self.yolo_model = yolo_model def run(self): cap = cv2.VideoCapture(self.video_path) while True: ret, frame = cap.read() if not ret: break results = self.yolo_model(frame) # 使用 YOLO 模型推断 annotated_frame = results.render()[0] # 渲染结果 self.frame_processed.emit(annotated_frame) # 发送信号给 GUI 主线程 cap.release() # 在主窗口类中实例化该线程对象并与槽函数绑定 video_thread = VideoProcessingThread(video_path="example.mp4", yolo_model=model_instance) video_thread.frame_processed.connect(update_ui_with_frame) video_thread.start() ``` 通过这种方式,可以有效避免阻塞UI线程以及潜在的崩溃问题。 --- #### 3. 视频流解码异常 某些情况下,视频文件可能损坏或者编码不被OpenCV支持,这也会引发程序崩溃。为此,需验证输入视频的有效性和兼容性。可以通过以下方法测试视频加载情况: ```python cap = cv2.VideoCapture("input_video.mp4") if not cap.isOpened(): raise ValueError("无法打开视频文件") while True: ret, frame = cap.read() if not ret: print("视频结束") break # 显示每一帧图像 (仅用于调试目的) cv2.imshow('Frame', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() ``` 上述脚本可用于确认是否存在读取失败的情况;若有任何异常发生,则应及时调整源素材或更新依赖库版本。 --- #### 4. GPU内存不足 对于大型视频文件而言,连续不断地向显卡分配新缓冲区而未能及时释放旧空间的话,最终会造成OOM(Out Of Memory)。为了避免这种情况的发生,应当定期清理无用变量并将不必要的张量移回主机端存储器之中。具体做法包括但不限于设置合理的批量大小、关闭梯度追踪功能等措施。 示例优化策略如下所示: ```python with torch.no_grad(): # 停止记录反向传播所需信息从而节省显存开销 outputs = [] for batch in data_loader: output = model(batch.to(device)) outputs.append(output.detach().cpu()) # 将每批预测结果拷贝至 CPU 上保存起来 del batch, output # 手动删除临时引用以便立即回收资源 torch.cuda.empty_cache() # 强制清空缓存区域内的闲置碎片 ``` 以上技巧有助于缓解由于硬件限制所引起的性能瓶颈现象。 --- #### 总结 综上所述,针对PyQt5调用YOLOv11模型开展实时视频目标识别过程中遭遇的应用终止状况,可以从多个角度切入分析原因所在——比如修正不当的数据类型映射关系、重构业务流程架构设计思路、甄别外部媒体资料质量水平以及合理调配算力资源配置比例等方面入手逐一排除干扰因素直至恢复正常运作状态为止。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值