1

I want to use python OpenCV bindings to display webcam stream in a QLabel. I found some previous posts here:

In the beginning I tried a simple "while" loop:

def onRun(self):
    self.playing = True
    capture = cv2.VideoCapture(0)
    while self.playing:
        _, data = capture.read()
        data = cv2.cvtColor(data, cv2.cv.CV_BGR2RGB)
        qImage = QtGui.QImage(data, data.shape[1], data.shape[0], 
            QtGui.QImage.Format_RGB888)
        self.lblImage.setPixmap(QtGui.QPixmap.fromImage(qImage))
        self.lblImage.adjustSize()
        time.sleep(0.02)

But I met with a "white-window" problem. I found that proper way to solve this is to create a new thread. My question is: what is it all about new thread? should I create QThread or something? And what is it signal/slot emitting in a thread?

I've never used threads so it's totally new thing to me.

Community
  • 1
  • 1
hebius
  • 133
  • 1
  • 14
  • You may want to read up on how Markdown works and how to format posts here. :-) Also, we already have a tags field, no need to repeat them in the title. – Martijn Pieters Nov 30 '13 at 11:50
  • Sorry for my formatting and title - it's my first time here, I will remember about it next time :) – hebius Nov 30 '13 at 11:57

2 Answers2

0

I can't test this myself, but would it not be enough to simply process the pending events within the loop?

That is:

def onRun(self):
    self.playing = True
    capture = cv2.VideoCapture(0)
    while self.playing:
        ...
        QtGui.qApp.processEvents()
        time.sleep(0.02)
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
0

A solution is to use pyqtSignal. Here is an example:

import time
from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout
from PyQt5.QtGui import QPixmap, QImage
import sys
import threading
import numpy as np


class FakeCamera(QWidget):
    """Simulate a camera"""
    image_taken = pyqtSignal(np.ndarray)

    def __init__(self, callback, time_cost=0.01, image_shape=(256, 256)):
        super(FakeCamera, self).__init__()
        self.time_cost = time_cost  # the time cost to take a frame, determine the frame rate
        self.image_shape = image_shape
        self.image_taken.connect(callback)
        self._stop = threading.Event()

    def start(self):
        """start a thread to take images"""

        def run():
            while not self._stop.is_set():
                time.sleep(self.time_cost)
                image = np.random.randint(0, 256, self.image_shape, np.uint8)
                self.image_taken.emit(image)

        threading.Thread(target=run).start()

    def stop(self):
        self._stop.set()


class WindowDemo(QWidget):
    def __init__(self):
        super(WindowDemo, self).__init__()

        # label
        self.label = QLabel()
        self.label.setScaledContents(True)
        self.label.setMinimumSize(1, 1)
        # layout
        vbox = QVBoxLayout()
        vbox.addWidget(self.label)
        self.setLayout(vbox)
        # camera
        self.camera = FakeCamera(self.show_image)
        # start a thread to take images
        self.camera.start()

    @pyqtSlot(np.ndarray)
    def show_image(self, image):
        qimage = QImage(image, image.shape[1], image.shape[0], QImage.Format_Grayscale8)
        self.label.setPixmap(QPixmap.fromImage(qimage))

    def closeEvent(self, e):
        self.camera.stop()
        e.accept()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = WindowDemo()
    win.show()
    sys.exit(app.exec_())