Home > OS >  Resuming a thread which was created using opencv , in pyqt5
Resuming a thread which was created using opencv , in pyqt5

Time:06-18

I am trying to design a gui which is related to my computer vision project. In that, the video I want to stop the web camera feed and I want to resume it by pressing a button. I managed to stop the feed, but I cannot resume it. The camera gets turned on but it is not working. This is the code for the program.

from PyQt5 import uic
from PyQt5 import QtCore, QtWidgets, QtGui
import cv2
import sys

class opencv_feed(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = uic.loadUi('../designs/design5_flexible_opencv_window2.ui', self)    #change this whenever u want... keep the ui file with you
        self.resize(900,600)

        self.worker1 = worker1()                                #creating an instance
        self.worker1.start()
        self.worker1.ImgUpdate.connect(self.ImageUpdateSlot)
        self.but_stop.clicked.connect(self.cancel_feed)
        self.but_resume.clicked.connect(self.resume_feed)
        
   
    def ImageUpdateSlot(self, Image):
        self.label.setPixmap(QtGui.QPixmap.fromImage(Image))
        
    def cancel_feed(self):
        self.worker1.stop()
    
    def resume_feed(self):
        self.__init__()
        #self.worker1.ImgUpdate.connect(self.ImageUpdateSlot)

class worker1(QtCore.QThread):
    ImgUpdate = QtCore.pyqtSignal(QtGui.QImage)
    
    @QtCore.pyqtSlot()
    def run(self):  #put self in every variable to stop crashing the gui, when we interact with gui
        self.ThreadActive = True
        self.feed = cv2.VideoCapture(0)
        while self.ThreadActive:
            self.ret, self.frm = self.feed.read()
            if self.ret:
                self.img = cv2.cvtColor(self.frm, cv2.COLOR_BGR2RGB)
                #print(img1.shape)
                self.img = cv2.flip(self.img,1)
                self.qtformat_conv_img = QtGui.QImage(self.img.data, self.img.shape[1], self.img.shape[0], QtGui.QImage.Format_RGB888)
                #print(self.img.shape)
                self.pic = self.qtformat_conv_img.scaled(self.img.shape[1],self.img.shape[0],QtCore.Qt.KeepAspectRatio)    #keep this as an attribute, else when resizing the app stops                                              
                self.ImgUpdate.emit(self.pic)
    def stop(self):
        self.ThreadActive = False
        self.feed.release()
        self.quit()
        #os._exit(0)  
        
if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    wind = opencv_feed()
    wind.show()
    sys.exit(app.exec_())

Can someone explain me what am I doing wrong.

Link to the UI file.. https://drive.google.com/file/d/1UP8RjQML1GzFA75eGURgWt4Y0o_Ip3sU/view?usp=sharing

CodePudding user response:

You can only start a thread once. Once it finishes you need to create another thread object to actually run. I would add another flag after self.ThreadActive called something like "pause" to keep the thread alive, just without doing anything.

@QtCore.pyqtSlot()
def run(self):  #put self in every variable to stop crashing the gui, when we interact with gui
    self.ThreadActive = True
    self.paused = False
    self.feed = cv2.VideoCapture(0)
    while self.ThreadActive:
        if not self.paused:
            self.ret, self.frm = self.feed.read()
            if self.ret:
                self.img = cv2.cvtColor(self.frm, cv2.COLOR_BGR2RGB)
                #print(img1.shape)
                self.img = cv2.flip(self.img,1)
                self.qtformat_conv_img = QtGui.QImage(self.img.data, 
                                                      self.img.shape[1], 
                                                      self.img.shape[0], 
                                                      QtGui.QImage.Format_RGB888)
                #print(self.img.shape)
                self.pic = self.qtformat_conv_img.scaled(self.img.shape[1],self.img.shape[0],QtCore.Qt.KeepAspectRatio)    #keep this as an attribute, else when resizing the app stops                                              
                self.ImgUpdate.emit(self.pic)

this way when you want to pause the thread you can pause and unpause using that flag

Either that or you need to always create another instance of the worker. Does it work if you create the instance outside of the init ? I'm unsure what happens to the GUI if the init is called twice.

EDIT: You'll also have to change the way you pause and start again

def cancel_feed(self):
    self.worker1.paused = True

def resume_feed(self):
    self.worker1.paused = False
  • Related