Search code examples
pythonpyqt5qthread

Changing QThread variable from a sub window


I am writing a WebCam Gui, which is supposed to take pictures and manipulate with WebCam parameters. After the video stream is activated on the main GUI window, an additional window can be opened to change the WebCamera parameters Screenshot 1, Screenshot 2.

I am using Qthread to stream on QLabel. Also, I was able to set the initial camera parameters on the camera properties' changing window. My problem is changing the Exposure parameter by using a slider on the sub-window and seeing results in real-time on the main window.

Please see the code.

import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import cv2


class MainFrame(QMainWindow):

    def __init__(self):
        super(MainFrame, self).__init__()
        # Loading UI
    
        uic.loadUi("MainFrame.ui", self)
    
        # Remove maximize button to prevent crushing
        self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint)
    
        # Define Widgets
        self.Video_Feed = self.findChild(QLabel, 'Video_Feed')
        self.Case_Name = self.findChild(QLineEdit, "Case_Name")
        self.Pictures_List = self.findChild(QListWidget, "Pictures_List")
        self.Start_Video = self.findChild(QAction, 'actionStart_Video')
        self.Start_Video.setShortcut('Shift+S')
        self.Stop_Video = self.findChild(QAction, 'actionStop_Video')
        self.Stop_Video.setShortcut('Shift+F')
        self.Take_a_Picture = self.findChild(QAction, 'actionTake_a_picture')
        self.Take_a_Timed_Picture = self.findChild(QAction, 'actionTake_a_timed_picture')
        self.Camera_Properties = self.findChild(QAction, 'actionProperties')
    
        # Initializing Video
        self.Start_Video.triggered.connect(self.Start_Video_Clicked)
        self.Stop_Video.triggered.connect(self.Stop_Video_Clicked)
        self.Camera_Properties.triggered.connect(self.Camera_Properties_Clicked)
    
    def Video_Feed_Update(self, Image):
        self.Video_Feed.setPixmap(QPixmap.fromImage(Image))
    
    def Start_Video_Clicked(self):
        self.Video_Feed_is_Running = True
        self.thread = QThread()
        self.Video_Thread = Worker()
        self.Video_Thread.moveToThread(self.thread)
        self.Video_Thread.ImageUpdate.connect(self.Video_Feed_Update)
        self.thread.started.connect(self.Video_Thread.run)
        self.thread.start()
    
    def Stop_Video_Clicked(self):
        self.Video_Thread.stop_video()
        self.Video_Feed.setText("Your video starts here")
    
    def Camera_Properties_Clicked(self):
        self.CP = CameraParameters()
        Initial_Exposure = self.Video_Thread.Camera_Initial_Parameters()
        self.CP.Setup_Exposure(int(Initial_Exposure))
        self.CP.Exposure_Calibration.connect(self.Video_Thread.Exposure_update)
        self.CP.show()


class Worker(QObject):
    ImageUpdate = pyqtSignal(QImage)

    def run(self):
        self.ThreadActive = True
        self.Capture = cv2.VideoCapture(1, cv2.CAP_DSHOW)
        self.Capture.set(3, 1920)
        self.Capture.set(4, 1080)
        while self.ThreadActive:
            ret, frame = self.Capture.read()
            if ret:
                image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                # Converting Video into QT5 readable format
                qt_video_format = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888)
                qt_picture = qt_video_format.scaled(1280, 720, Qt.KeepAspectRatio)
                self.ImageUpdate.emit(qt_picture)
    
    def stop_video(self):
        self.ThreadActive = False
        self.Capture.release()
    
    def Camera_Initial_Parameters(self):
        return self.Capture.get(cv2.CAP_PROP_EXPOSURE)
    
    def Exposure_update(self, value):
        self.Capture.set(cv2.CAP_PROP_EXPOSURE, value)


class CameraParameters(QDialog):
    Exposure_Calibration = pyqtSignal(int)
    
    def __init__(self):
        super().__init__()
        uic.loadUi('Cam_Parameters.ui', self)
    
        # Sliders
        self.Exposure_Slider = self.findChild(QSlider, 'ExposureSlider')
        self.Exposure_Slider.setRange(-10, 10)
        self.White_Balance_Slider = self.findChild(QSlider, 'WBSlider')
        self.White_Balance_Slider.setMinimum(-10)
        self.White_Balance_Slider.setMaximum(10)
        self.Brightness_Slider = self.findChild(QSlider, 'BrightnessSlider')
        self.Brightness_Slider.setMinimum(0)
        self.Brightness_Slider.setMaximum(300)
        self.Saturation_Slider = self.findChild(QSlider, 'SaturationSlider')
        self.Saturation_Slider.setMinimum(0)
        self.Saturation_Slider.setMaximum(300)
        self.Contrast_Slider = self.findChild(QSlider, 'ContrastSlider')
        self.Contrast_Slider.setMinimum(-10)
        self.Contrast_Slider.setMaximum(10)
        self.Gamma_Slider = self.findChild(QSlider, 'GammaSlider')
        self.Gamma_Slider.setMinimum(-10)
        self.Gamma_Slider.setMaximum(10)
        self.Sharpness_Slider = self.findChild(QSlider, 'SharpnessSlider')
        self.Sharpness_Slider.setMinimum(0)
        self.Sharpness_Slider.setMaximum(100)
        # Sliders values
        self.Exposure_Value = self.findChild(QLabel, 'Exposure_Value')
        self.White_Balance_Value = self.findChild(QLabel, 'WB_value')
        self.Brightness_Value = self.findChild(QLabel, 'Brightness_value')
        self.Saturation_Value = self.findChild(QLabel, 'Saturation_value')
        self.Contrast_Value = self.findChild(QLabel, 'Contrast_value')
        self.Gamma_Value = self.findChild(QLabel, 'Gamma_value')
        self.Sharpness_Value = self.findChild(QLabel, 'Sharpness_value')
    
        # Connections
        self.Exposure_Slider.valueChanged.connect(self.Exposure_sliding)
    
    def Setup_Exposure(self, value):
        self.Exposure_Slider.setValue(value)
        self.Exposure_Value.setText(str(value))
    
    def Exposure_sliding(self, value):
        self.Exposure_Value.setText(str(value))
        self.Exposure_Calibration.emit(value)


if __name__ == "__main__":
    App = QApplication(sys.argv)
    Root = MainFrame()
    Root.show()
    sys.exit(App.exec())

Cam_Parameters.ui, MainFrame.ui for the GUI


Solution

  • I admit I don't know why this worked, but changing the connect to a lambda function did the trick.

    self.CP.Exposure_Calibration.connect(lambda x: self.Video_Thread.Exposure_update(x))