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

Pyqt crashes when trying to show opencv videostream

我尝试了 答案中的代码,一段时间后(2-10 秒)它崩溃并出现错误 Process finished with exit code -1073740771 (0xC000041D),有时出现 0xC0000005。如果我尝试拖动 window,它会立即崩溃。 但是,当我将 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_())

我认为问题出在 signals/slots 中的某处,但未能找到任何相关内容。

使用 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_())

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