是否有使用 pyqt5 的实时视频 GUI 而不会冻结的解决方案?

问题描述 投票:0回答:0

下面的代码是有问题的代码。

  1. 接收和处理来自网络摄像头的视频数据的 ShowVideo 类
  2. ImageViewer 类,接收图像并在 GUI 中实时显示它们

当接收到的网络摄像头数据为 640x480 时,此代码可以正常工作。 -.左键单击应用程序窗口的标题栏并等待 -.左键单击并按住最小化、最大化、关闭按钮 在这种情况下,GUI 冻结,但在释放左键单击一段时间后,GUI 开始正常工作。

但是,当网络摄像头的数据以 1920x1080 接收时,此代码会导致问题。 在以上两个应用程序窗口中操作会导致GUI卡死,最终进程终止。

我想解决这个问题 我想知道如何解决它以避免 pyqt5 GUI 冻结。

import cv2
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from PyQt5 import QtGui



class ShowVideo(QtCore.QObject):

    flag = 0
    camera = cv2.VideoCapture(0)
    camera.set(cv2.CAP_PROP_FRAME_WIDTH, 1920 ) # 1920
    camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) # 1080
    ret, image = camera.read()
    height, width = image.shape[:2]
    print(f"{height} / {width}")
    VideoSignal1 = QtCore.pyqtSignal(QtGui.QImage)
    VideoSignal2 = QtCore.pyqtSignal(QtGui.QImage)

    def __init__(self, parent=None):
        super().__init__()


    @QtCore.pyqtSlot()
    def startVideo(self):
        global image

        run_video = True
        while run_video:
            ret, image = self.camera.read()
            color_swapped_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

            qt_image1 = QtGui.QImage(color_swapped_image.data,
                                    self.width,
                                    self.height,
                                    color_swapped_image.strides[0],
                                    QtGui.QImage.Format_RGB888)

            self.VideoSignal1.emit(qt_image1)


            if self.flag:
                img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
                img_canny = cv2.Canny(img_gray, 50, 100)

                qt_image2 = QtGui.QImage(img_canny.data,
                                         self.width,
                                         self.height,
                                         img_canny.strides[0],
                                         QtGui.QImage.Format_Grayscale8)

                self.VideoSignal2.emit(qt_image2)


            loop = QtCore.QEventLoop()
            QtCore.QTimer.singleShot(25, loop.quit) #25 ms
            loop.exec_()

    @QtCore.pyqtSlot()
    def canny(self):
        self.flag = 1 - self.flag



class ImageViewer(QtWidgets.QWidget):

    def __init__(self, parent=None):
        #     super(ImageViewer, self).__init__(parent)
        super().__init__()
        self.image = QtGui.QImage()
        self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)


    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        painter.drawImage(0, 0, self.image)
        # self.image = QtGui.QImage()

    def initUI(self):
        self.setWindowTitle('Test')

    @QtCore.pyqtSlot(QtGui.QImage)
    def setImage(self, image):

        image = QtGui.QImage(image).scaled(400, 300, QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation)

        if image.isNull():
            print("Viewer Dropped frame!")

        self.image = image
        if image.size() != self.size():
            self.setFixedSize(image.size())
        self.update()



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


    thread = QtCore.QThread()
    thread.start()
    vid = ShowVideo()
    vid.moveToThread(thread)

    image_viewer1 = ImageViewer()
    image_viewer2 = ImageViewer()


    vid.VideoSignal1.connect(image_viewer1.setImage)
    vid.VideoSignal2.connect(image_viewer2.setImage)



    push_button1 = QtWidgets.QPushButton('Start')
    push_button2 = QtWidgets.QPushButton('Canny')
    push_button1.clicked.connect(vid.startVideo)
    push_button2.clicked.connect(vid.canny)

    vertical_layout = QtWidgets.QVBoxLayout()
    horizontal_layout = QtWidgets.QHBoxLayout()
    horizontal_layout.addWidget(image_viewer1)
    horizontal_layout.addWidget(image_viewer2)
    vertical_layout.addLayout(horizontal_layout)
    vertical_layout.addWidget(push_button1)
    vertical_layout.addWidget(push_button2)

    layout_widget = QtWidgets.QWidget()
    layout_widget.setLayout(vertical_layout)

    main_window = QtWidgets.QMainWindow()
    main_window.setCentralWidget(layout_widget)
    main_window.show()
    sys.exit(app.exec_())
  1. 正如ShowVideo类作为一个线程运行一样,ImageViewer也创建并运行了各个线程,但是问题并没有解决
python multithreading user-interface pyqt5 freeze
© www.soinside.com 2019 - 2024. All rights reserved.