Pyqt和opencv联调

本文介绍了一个基于PyQt5的应用,实现模型选择、摄像头控制与算法检测的功能。用户可以选择加载模型,通过摄像头实时获取图像,并进行算法检测,结果显示在界面上。着重讲解了如何通过线程处理避免程序阻塞,以及如何在不同状态间切换操作。
摘要由CSDN通过智能技术生成

说明

功能需求说明:
1、选择模型按键,选择需要加载的模型
2、打开摄像头按键,打开摄像头并开始显示图像
3、算法检测按键,将摄像头图像进行算法检测后返回检测结果
实现说明:
1、选择模型
1.1、本地端,选择需要加载的模型后,返回模型所在地址,供调用;服务器端,发送指令给服务器进行模型配置
2、打开摄像头
2.1、读取图像可能会造成程序阻塞,故需要新建线程
2.2、关闭摄像头后,结束对应的线程
3、算法检测
3.1、flag变量,当摄像头打开,且按下‘开始算法检测’按钮后,摄像头获得的数据经过处理传入算法模型内部.

代码

代码分为两部分,一部分是主窗口,一部分是捕获线程。未集成算法部分代码,模拟了算法被调用过程。

Main_UI.py

import sys
from PyQt5.QtWidgets import QMainWindow, QWidget, QApplication, QGridLayout, QPushButton, QGraphicsView, QGraphicsScene, \
    QFileDialog, QLineEdit, QLabel, QHBoxLayout
# 导入自定义库-摄像头捕获线程
from ThreadCapture import ThreadCapture

# 主窗口类
class MyWindow(QMainWindow):
    def __init__(self):
        super(MyWindow, self).__init__()

        # 状态
        self.openCameraText = '打开摄像头'
        self.closeCameraText = '关闭摄像头'
        self.startAlgDetectText = '开始算法检测'
        self.stopAlgDetectText = '停止算法检测'

        # 初始化UI
        self.initUI()

        self.filePath = None    # 模型文件

    def initUI(self):
        self.resize(800, 600)
        self.setWindowTitle('test')
        # 创建UI上的控件
        self.creatInterface()
        # 显示UI
        self.show()

    def creatInterface(self):
        # 创建状态栏
        self.mainStatusBar = self.statusBar()
        self.mainStatusBarLabel = QLabel(self.mainStatusBar)
        self.mainStatusBar.addPermanentWidget(self.mainStatusBarLabel)
        self.mainStatusBarLabel.setText('None')

        # 创建所需的组件
        self.selectModelBtn = QPushButton('选择模型')

        self.cameraNumText = QLineEdit('0')
        self.cameraBtn = QPushButton(self.openCameraText)

        self.algDetectBtn = QPushButton(self.startAlgDetectText)
        self.algDetectBtn.setEnabled(False)     # 防止误操作

        self.cameraNumText.setMaximumWidth(int(100))     # 如果不限制,则显示的过宽
        self.imageScene = QGraphicsScene()      # 场景用于添加图像
        self.imageView = QGraphicsView()        # 视图中添加场景

        # 配置控件初始状态以及绑定动作
        self.setWidget()

        # 布局
        gridLayout = QGridLayout()
        gridLayout.addWidget(self.selectModelBtn, 0, 0)
        gridLayout.addWidget(self.cameraNumText, 1, 0)
        gridLayout.addWidget(self.cameraBtn, 2, 0)
        gridLayout.addWidget(self.algDetectBtn, 3, 0)
        gridLayout.addWidget(self.imageView, 0, 1, 8, 8)

        widget = QWidget(self)
        widget.setLayout(gridLayout)
        self.setCentralWidget(widget)

    # 配置控件初始状态以及绑定动作
    def setWidget(self):
        self.selectModelBtn.clicked.connect(self.actionSelectModelBtn)
        self.cameraBtn.clicked.connect(self.actionCameraBtn)
        self.algDetectBtn.clicked.connect(self.actionDetectBtn)
        self.imageView.setScene(self.imageScene)

    def actionSelectModelBtn(self):
        # 选择文件
        print('actionSelectModel')
        # folderPath = QFileDialog.getExistingDirectory(self, '选取文件夹')    # 文件夹路径
        # print(folderPath)

        # 选择文件,返回文件的路径
        self.filePath, _ = QFileDialog.getOpenFileName(self, caption="选取文件", filter="Image Files (*.jpg);;Text Files (*.txt)")
        print(self.filePath)

        # 状态栏显示模型路径
        self.mainStatusBarLabel.setText(self.filePath)

        if self.cameraBtn.text() == self.closeCameraText:
            # 如果摄像头已经打开,则允许‘开始算法检测’
            self.algDetectBtn.setEnabled(True)

    def actionCameraBtn(self):
        """
        如果当前状态为“打开摄像头”,则创建线程进行图像捕获,更新显示为“关闭摄像头”。
        如果当前状态为“关闭摄像头”,则结束打开的线程,更新显示为“打开摄像头”。
        :return:
        """
        print('actionOpenCamera')
        if self.cameraBtn.text() == self.openCameraText:
            # 创建线程
            self.threadCapture = ThreadCapture(int(self.cameraNumText.text()))
            self.threadCapture.signal_image.connect(self.showImage)
            self.threadCapture.start()
        else:
            # 结束线程
            self.threadCapture.terminate()
            self.threadCapture.quit()

        if self.cameraBtn.text() == self.openCameraText:
            self.cameraBtn.setText(self.closeCameraText)
            # 当选择了模型以及摄像头处于打开状态时才允许进行算法检测
            if self.filePath is not None:
                self.algDetectBtn.setEnabled(True)
        else:
            self.cameraBtn.setText(self.openCameraText)
            self.algDetectBtn.setEnabled(False)                 # 算法检测失能,且更新显示
            self.algDetectBtn.setText(self.startAlgDetectText)
            self.selectModelBtn.setEnabled(True)                # 允许选择模型

    def actionDetectBtn(self):
        if self.algDetectBtn.text() == self.startAlgDetectText:
            self.threadCapture.algDetectFlag = True
        else:
            self.threadCapture.algDetectFlag = False

        if self.algDetectBtn.text() == self.startAlgDetectText:
            self.algDetectBtn.setText(self.stopAlgDetectText)
            self.selectModelBtn.setEnabled(False)   # 算法检测期间不允许更换模型
        else:
            self.algDetectBtn.setText(self.startAlgDetectText)
            self.selectModelBtn.setEnabled(True)  # 算法检测期间不允许更换模型

    def showImage(self, image):
        self.imageScene.addPixmap(image)



if __name__ == '__main__':
    app = QApplication(sys.argv)

    w = MyWindow()

    sys.exit(app.exec_())

ThreadCapture.py

import cv2
from PyQt5.QtCore import QThread, pyqtSignal, QMutex
from PyQt5.QtGui import QImage, QPixmap

import random

class ThreadCapture(QThread):
    # 定义信号,用于传输图像
    signal_image = pyqtSignal(QPixmap)
    def __init__(self, cameraNum):
        super(ThreadCapture, self).__init__()
        self.cameraNum = cameraNum
        self.qmutex = QMutex()  # 进行锁

        self.algDetectFlag = False  # 算检测标志位

    def run(self):
        self.cap = cv2.VideoCapture(self.cameraNum, cv2.CAP_DSHOW) # cv2.CAP_DSHOW 可以消除警告
        while True:
            print('thread id:', QThread.currentThreadId())
            # 读取图像是,锁住线程
            self.qmutex.lock()
            ret, self.image = self.cap.read()
            self.qmutex.unlock()

            if ret:
                # 处理图像
                self.dealImage()
                # 处理图像数据,符合算法要求后传入模型,等待返回结果
                if self.algDetectFlag:
                    print('start alg detect')
                    cv2.rectangle(self.image, (100, 100), (300, 300),
                                  (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)),)

                # 转换为qt的图像格式
                pixmap = self.imageCv2Qt(self.image)
                self.signal_image.emit(pixmap)

    def dealImage(self):
        self.image = cv2.resize(self.image, (400, 400))
        height, width, depth = self.image.shape
        # cv2.putText(self.image, 'height-{}:width-{}'.format(height, width), (10, 100), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255 ,0))


    # 转换为qt的图像格式
    def imageCv2Qt(self, image):
        rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        height, width, depth = rgb.shape
        bytesPerLine = width * depth
        qrgb = QImage(rgb.data, width, height, bytesPerLine, QImage.Format_RGB888)
        pixmap = QPixmap.fromImage(qrgb)

        return pixmap

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值