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