尝试显示OpenCV视频流时Pyqt崩溃

时间:2019-03-22 19:33:23

标签: python python-3.x opencv pyqt5 qthread

我尝试了this答案中的代码,经过一段时间(2-10秒),有时是Process finished with exit code -1073740771 (0xC000041D),它因错误0xC0000005而崩溃。如果我尝试拖动窗口,它将立即崩溃。 但是,当我将time.sleep(0.1)放在run中时,它可以正常工作。如果我使用的睡眠时间少于0.1,则会再次崩溃。

from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel,QMessageBox
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot, Qt
import cv2
import sys
import time

class CamThread(QThread):
    changemap = pyqtSignal('QImage')

    def run(self):
        cap = cv2.VideoCapture(0)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

        while True:
            ret, img_rgb = cap.read()
            if ret:
                self.rgb = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2RGB)
                self.convert = QImage(self.rgb.data, self.rgb.shape[1], self.rgb.shape[0], QImage.Format_RGB888)
                self.p = self.convert.scaled(640, 480, Qt.KeepAspectRatio)
                self.changemap.emit(self.p)
                #time.sleep(0.1)


class App(QWidget):
    def __init__(self):
        super().__init__()
        self.title = 'webcam'

        self.initUI()

    @pyqtSlot('QImage')
    def setImage(self, image):
        self.label.setPixmap(QPixmap.fromImage(image))

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(100, 100, 640, 480)
        self.resize(640, 480)
        self.label = QLabel(self)
        self.label.resize(640, 480)
        thr = CamThread(self)
        thr.changemap.connect(self.setImage)
        thr.start()

app = QApplication(sys.argv)
win = App()
#win.setAttribute(Qt.WA_DeleteOnClose, True)
win.show()
app.exit(app.exec_())

我认为问题出在信号/插槽中,但是找不到任何相关的东西。

  • Windows 10

  • Python-3.7

  • Pyqt-5.12

  • OpenCV-3.4.5.20

1 个答案:

答案 0 :(得分:0)

使用QMutexQWaitCondition修复了该问题,以防止在主线程已经更新时进行更新调用。显然,问题出在那。 eyllanesc,如您所见,我是新来的,我应该在原始主题中回答吗?

from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QMessageBox
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot, Qt, QMutex, QWaitCondition
import cv2
import sys
import time


class CamThread(QThread):
    changemap = pyqtSignal('QImage')

    def __init__(self, mutex, condition):
        super().__init__()
        self.mutex = mutex
        self.condition = condition

    def run(self):
        cap = cv2.VideoCapture(0)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
        while True:
            try:
                ret, img_rgb = cap.read()
                if ret:
                    rgb = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2RGB)

                    #any other image processing here

                    convert = QImage(rgb.data, rgb.shape[1], rgb.shape[0], QImage.Format_RGB888)
                    p = convert.scaled(640, 480, Qt.KeepAspectRatio)
                    self.changemap.emit(p)
                    self.condition.wait(self.mutex)

            except:
                print('error')


class App(QWidget):
    time = 0

    def __init__(self):
        super().__init__()
        self.title = 'webcam'
        self.mutex = QMutex()
        self.condition = QWaitCondition()
        self.initUI()

    @pyqtSlot('QImage')
    def setImage(self, image):
        self.mutex.lock()
        try:
            self.label.setPixmap(QPixmap.fromImage(image))
        finally:
            self.mutex.unlock()
            self.condition.wakeAll()

    def initUI(self):
        self.mutex.lock()
        self.setWindowTitle(self.title)
        self.setGeometry(100, 100, 640, 480)
        self.resize(640, 480)
        self.label = QLabel(self)
        self.label.resize(640, 480)
        self.thr = CamThread(mutex = self.mutex,condition=self.condition)
        self.thr.changemap.connect(self.setImage)
        self.thr.start()


app = QApplication(sys.argv)
win = App()
win.show()
app.exit(app.exec_())

在此示例中,您仍然需要正确地停止线程并关闭相机连接。