0

I'm using two threads Camera and NetworkProcessor in Qt application, which displayes their actual state in QLabel (there is one label for each thread: camStatusLabel, nnStatusLabel). To update text in label I am using signals and slots. There is also 6 labels to display images, which are updated in while loop periodically (cameraView, k1, k2, k3, k4, k5) with signals and slots as well.

import cv2
import sys
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
import threading as th

from PIL import Image
import copy

class SecondPage(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.bigSize = QSize(640, 480)
        self.smallSize = QSize(320, 240)

        blackPic = QPixmap(self.bigSize)
        blackPic.fill(Qt.black)

        self.layoutTop = QVBoxLayout()
        self.layoutTop.setAlignment(Qt.AlignCenter)

        self.topRowLayout = QHBoxLayout()
        self.buttonBack = QPushButton("Back")
        self.camStatusLabel = QLabel("Camera status: not running...")
        self.nnStatusLabel = QLabel("Neural net status: not running...")
        self.topRowLayout.addWidget(self.buttonBack, alignment=Qt.AlignRight)
        self.topRowLayout.addWidget(self.camStatusLabel, alignment=Qt.AlignLeft)
        self.topRowLayout.addWidget(self.nnStatusLabel, alignment=Qt.AlignLeft)

        self.cameraView = QLabel()
        self.cameraView.setFixedSize(self.bigSize)
        self.cameraView.setPixmap(blackPic)

        self.knnLayout = QHBoxLayout()

        self.layoutTop.addLayout(self.topRowLayout, alignment=Qt.AlignLeft)
        self.layoutTop.addWidget(self.cameraView, alignment=Qt.AlignCenter)
        self.layoutTop.addLayout(self.knnLayout, alignment=Qt.AlignCenter)

        self.k1 = QLabel(alignment=Qt.AlignCenter)
        self.k1.setFixedSize(self.smallSize)
        self.k1.setPixmap(blackPic)
        self.k2 = QLabel(alignment=Qt.AlignCenter)
        self.k2.setFixedSize(self.smallSize)
        self.k2.setPixmap(blackPic)
        self.k3 = QLabel(alignment=Qt.AlignCenter)
        self.k3.setFixedSize(self.smallSize)
        self.k3.setPixmap(blackPic)
        self.k4 = QLabel(alignment=Qt.AlignCenter)
        self.k4.setFixedSize(self.smallSize)
        self.k4.setPixmap(blackPic)
        self.k5 = QLabel(alignment=Qt.AlignCenter)
        self.k5.setFixedSize(self.smallSize)
        self.k5.setPixmap(blackPic)

        self.knnLayout.addWidget(self.k1)
        self.knnLayout.addWidget(self.k2)
        self.knnLayout.addWidget(self.k3)
        self.knnLayout.addWidget(self.k4)
        self.knnLayout.addWidget(self.k5)

        self.setLayout(self.layoutTop)

        self.frame = [None]
        self.frameLock = QMutex()

        startExecute = th.Event()
        threadIsLoadedEvent = th.Event()

        self.cameraThread = Camera()
        self.connect(self.cameraThread, SIGNAL("updateCameraView(QImage)"), self.updateCameraView)
        self.connect(self.cameraThread, SIGNAL("updateCameraStatus(QString)"), self.updateCameraStatus)
        self.cameraThread.startCapturing(self.frame, self.frameLock, startExecute, threadIsLoadedEvent)

        self.processingThread = NetworkProcessor()
        self.connect(self.processingThread, SIGNAL("updateResults(QImage,QImage,QImage,QImage,QImage)"), self.updateResults)
        self.connect(self.processingThread, SIGNAL("nnStatusLabel(QString)"), self.updateNNStatus)
        self.processingThread.startAnalyzing(self.frame, self.frameLock, self.smallSize.toTuple(), startExecute, threadIsLoadedEvent)

        startExecute.set()


    def updateCameraStatus(self, text):
        self.camStatusLabel.setText(text)
        self.camStatusLabel.update()

    def updateNNStatus(self, text):
        self.nnStatusLabel.setText(text)
        self.nnStatusLabel.update()

    def updateCameraView(self, image):
        self.cameraView.setPixmap(QPixmap.fromImage(image).scaled(self.bigSize))
        self.cameraView.update()

    def updateResults(self, p1, p2, p3, p4, p5):
        self.k1.setPixmap(QPixmap.fromImage(p1))
        self.k1.update()

        self.k2.setPixmap(QPixmap.fromImage(p2))
        self.k2.update()

        self.k3.setPixmap(QPixmap.fromImage(p3))
        self.k3.update()

        self.k4.setPixmap(QPixmap.fromImage(p4))
        self.k4.update()

        self.k5.setPixmap(QPixmap.fromImage(p5))
        self.k5.update()

    def killPage(self):
        self.cameraThread.stopThread()
        self.processingThread.stopThread()

class Camera(QThread):
    def __init__(self, parent = None):
        QThread.__init__(self, parent)
        self.exit = False
        self.frame = None
        self.frameLock = None
        self.initSuccessEvent = None
        self.startEvent = None

    def stopThread(self):
        self.exit = True
        self.wait()

    def startCapturing(self, frame, frameLock, startEvent, initSuccessEvent):
        self.frame = frame
        self.frameLock = frameLock
        self.initSuccessEvent = initSuccessEvent
        self.startEvent = startEvent
        self.start()

    def run(self):
        self.startEvent.wait()

        self.emit(SIGNAL("updateCameraStatus(QString)"), "Camera status: Opening...")
        cap = cv2.VideoCapture(0)
        cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

        #initialize frame and signal success to main thead
        self.frameLock.lock()
        _, self.frame[0] = cap.read()
        self.frameLock.unlock()
        self.initSuccessEvent.set()

        self.emit(SIGNAL("updateCameraStatus(QString)"), "Camera status: Running...")

        #enter into loop
        while True:
            _, img = cap.read()
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

            self.frameLock.lock()
            self.frame[0] = copy.deepcopy(img)
            self.frameLock.unlock()

            img = QImage(img, img.shape[1], img.shape[0], img.strides[0], QImage.Format_RGB888)
            self.emit(SIGNAL("updateCameraView(QImage)"), img)

            if self.exit:
                cap.release()
                break

class NetworkProcessor(QThread):
    def __init__(self, parent = None):
        QThread.__init__(self, parent)
        self.exit = False
        self.frame = None
        self.frameLock = None
        self.imgSize = (100,100)
        self.initSuccessEvent = None
        self.startEvent = None

    def stopThread(self):
        self.exit = True
        self.wait()

    def startAnalyzing(self, frame, frameLock, imgSize, startEvent, initSuccessEvent):
        self.frame = frame
        self.frameLock = frameLock
        self.imgSize = imgSize
        self.initSuccessEvent = initSuccessEvent
        self.startEvent = startEvent
        self.start()

    def run(self):
        import pydevd;pydevd.settrace(suspend=False)
        self.startEvent.wait()
        self.emit(SIGNAL("nnStatusLabel(QString)"), "Neural net status: Waiting for camera...")
        self.initSuccessEvent.wait()

        self.emit(SIGNAL("nnStatusLabel(QString)"), "Neural net status: Loading nn and dataset...")

        QThread.msleep(1000) #to simulate initialization

        self.emit(SIGNAL("nnStatusLabel(QString)"), "Neural net status: Running...")

        while True:
            QThread.msleep(1000)

            if self.exit:
                break

            self.frameLock.lock()
            camImg = copy.deepcopy(self.frame[0])
            self.frameLock.unlock()

            products = self._processImg(Image.fromarray(camImg), 5)

            data1 = products[0].tobytes('raw', 'RGB')
            k1 = QImage(data1, products[0].size[0], products[0].size[1], QImage.Format_RGB888)

            data2 = products[1].tobytes('raw', 'RGB')
            k2 = QImage(data2, products[1].size[0], products[1].size[1], QImage.Format_RGB888)

            data3 = products[2].tobytes('raw', 'RGB')
            k3 = QImage(data3, products[2].size[0], products[2].size[1], QImage.Format_RGB888)

            data4 = products[3].tobytes('raw', 'RGB')
            k4 = QImage(data4, products[3].size[0], products[3].size[1], QImage.Format_RGB888)

            data5 = products[4].tobytes('raw', 'RGB')
            k5 = QImage(data5, products[4].size[0], products[4].size[1], QImage.Format_RGB888)

            self.emit(SIGNAL("updateResults(QImage,QImage,QImage,QImage,QImage)"), k1, k2, k3, k4, k5)

            if self.exit:
                break

    def _processImg(self, queryImg, k):
        imgs = []
        for i in range(k):
            im = queryImg.rotate(20*i)
            im = im.resize(self.imgSize)
            imgs.append(im)

        return imgs

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.loadSecondPage()


    def loadSecondPage(self):
        widget = SecondPage()
        self.setCentralWidget(widget)
        self.setWindowTitle("Metriclearning demo - Visualisation")

    def closeEvent(self, event):
        print("Closing app")
        self.centralWidget().killPage()
        event.accept()



if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


The problem is that, when I am updating text labels containing thread state (camStatusLabel, nnStatusLabel), the content does not remain as I have set it, but randomly changes to previous texts and back, even though the text is not updated never again once the thread enters into while loop.

The same problem is observable on labels containing images.

Does anyone know what might cause this problem?

EDIT: I eddited the code above to be executable. The problem is same as I have already described: The text in QLabel nnStatusLabel changes even though it is not supposed to and similar behavior is occasionally observable on displayed images as well - displayed images returns back in time (cameraView, k1, k2, k3, k4, k5).

sipinho
  • 1
  • 4
  • I've tested your code, I can't manage to reproduce the behavior you see... Everything seems to work fine here. – Trap Sep 09 '19 at 19:52
  • So, when you run the code there is 'Neural net status: Running...' in top right label all the time since thread NetworkProcessor enters while loop? If so might it be bug in particular version of PySide2? What version are you using? I have PySide2 v5.13.0 installed by pip – sipinho Sep 10 '19 at 16:17

0 Answers0