pycapture2 video capture and threading

Viewed 714

I have made a video capture program using by pycapture2 and PyQt5. It seems to work, but console shows errors:

QObject::killTimer: Timers cannot be stopped from another thread

QBasicTimer::stop: Failed. Possibly trying to stop from a different thread

I solved this by using QTimer but it was slow (2 frames/seconds).

I want use QThread, how to solve this problem ?

# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
import cv2
import PyCapture2
import numpy as np

class Ui_MainWindow(object):
    def __init__(self, parent=None):

        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(600, 400)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")

        self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
        self.graphicsView.setGeometry(QtCore.QRect(150, 20, 400, 300))
        self.graphicsView.setObjectName("graphicsView")

        MainWindow.setCentralWidget(self.centralwidget)

        self.Thread = CapThread()
        self.Thread.start()     

class CapThread(QThread):
    def __init__(self):
        QThread.__init__(self)

    def run(QMainWindow):
        bus = PyCapture2.BusManager()
        uid = bus.getCameraFromIndex(0)

        c = PyCapture2.Camera()
        c.connect(uid)         

        while True:
            c.startCapture()
            img = c.retrieveBuffer()
            c.stopCapture()

            cv_img1 = np.array(img.getData(), dtype="uint8").reshape((img.getRows(), img.getCols()));
            cv_img = cv2.cvtColor(cv_img1, cv2.COLOR_BAYER_BG2BGR)
            cv_img = cv2.resize(cv_img,(380,270))

            height, width, dim = cv_img.shape
            bytesPerLine = dim * width
            image = QtGui.QImage(cv_img.data, width, height, bytesPerLine, QtGui.QImage.Format_RGB888)
            item = QtWidgets.QGraphicsPixmapItem(QtGui.QPixmap.fromImage(image))
            scene = QtWidgets.QGraphicsScene()
            scene.addItem(item)
            ui.graphicsView.setScene(scene)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    MainWindow.show()
    sys.exit(app.exec_())
1 Answers

Your code does not have logic, for example because run() has QMainWinodw as a parameter, also in theory you try to create a scene every time you get an image and that is incorrect since your program is going to consume memory unnecessarily, the solution is to reuse the item . And last but not least the GUI can not be updated in another thread, Qt points out that it has to be sent by a signal to the GUI thread and there to do the update:

# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
import cv2
import PyCapture2
import numpy as np


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.resize(600, 400)
        scene = QtWidgets.QGraphicsScene()
        graphicsView = QtWidgets.QGraphicsView(scene)
        self.setCentralWidget(graphicsView)
        self._item = QtWidgets.QGraphicsPixmapItem()
        scene.addItem(self._item)
        thread = CapThread(self)
        thread.imageChanged.connect(self.on_imageChanged)
        thread.start()     

    @QtCore.pyqtSlot(QtGui.QImage)
    def on_imageChanged(self, image):
        pixmap = QtGui.QPixmap.fromImage(image)
        self._item.setPixmap(pixmap)


class CapThread(QtCore.QThread):
    imageChanged = QtCore.pyqtSignal(QtGui.QImage)

    def run(self):
        bus = PyCapture2.BusManager()
        uid = bus.getCameraFromIndex(0)
        c = PyCapture2.Camera()
        c.connect(uid)        

        while True:
            c.startCapture()
            img = c.retrieveBuffer()
            c.stopCapture()

            cv_img1 = np.array(img.getData(), dtype="uint8").reshape((img.getRows(), img.getCols()))
            cv_img = cv2.cvtColor(cv_img1, cv2.COLOR_BAYER_BG2BGR)
            cv_img = cv2.resize(cv_img, (380,270))

            height, width, dim = cv_img.shape
            bytesPerLine = dim * width
            image = QtGui.QImage(cv_img.data, width, height, bytesPerLine, QtGui.QImage.Format_RGB888)
            self.imageChanged.emit(image)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())
Related