Python/PyQt5/Picamera2 to control Raspberry Pi Cameras with GUI, with camera_controls.

Follow my previous exercise Python/PyQt5 GUI to control Raspberry Pi Camera using picamera2 lib, added function to change camera_controls for brightness at runtime.


This video also show two instances run to control two cameras at the same time.

Because my Camera Module 3 (with Auto-Focus) is assigned to Picamera2(1), so I make 1 as default. If you have one camera only, or you want 0 as default, set:
DEFAULT_CAM_NUM = 0

picam2_qt5_2024-01-13.py
"""
Python 3/PyQt5 + picamera2 to control Raspberry Pi Camera Modules
Tested on Raspberry Pi 5/64-bit Raspberry Pi OS (bookworm)
# in my setup:
# Picamera2(0) - HQ Camera
# Picamera2(1) - Camera Module 3

picam2_qt5_2023-12-28.py first exercise
picam2_qt5_2024-01-03.py Added Auto-Focus feature detection, and switch AF Mode between Continuous & Manual
picam2_qt5_2024-01-07.py Display Preview in seperated window, both Main/Preview windows have Capture button.
picam2_qt5_2024-01-13.py Add camera_controls to adjust brightness at runtime.
                         Handle sys.argv, such that user can select cam at command line.
"""
import sys, platform, os
from PyQt5.QtWidgets import (QMainWindow, QApplication, QPushButton, QLabel, QCheckBox,
                             QWidget, QTabWidget, QVBoxLayout, QGridLayout,
                             QGroupBox, QSlider)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont

from picamera2 import Picamera2
from picamera2.previews.qt import QGlPicamera2
from picamera2 import __name__ as picamera2_name
from libcamera import controls

import time
from importlib.metadata import version

os.environ["LIBCAMERA_LOG_LEVELS"] = "3"

"""
Because my Camera Module 3 (with Auto-Focus) is assigned to Picamera2(1),
so I make 1 as default

command line usage:
python picam2_qt5_xxx.py    # using default cam
python picam2_qt5_xxx.py 0  # using cam 0
python picam2_qt5_xxx.py 1  # using cam 1
"""

DEFAULT_CAM_NUM = 1
cam_num = DEFAULT_CAM_NUM # default Picamera2(DEFAULT_CAM_NUM)

if len(sys.argv)==2:
    if sys.argv[1] == "1":
        cam_num = 1
    if sys.argv[1] == "0":
        cam_num = 0

print("picam2 = Picamera2("+str(cam_num)+")")
picam2 = Picamera2(cam_num)
#picam2 = Picamera2()   #default to Picamera2(0) without parameter passed
#picam2 = Picamera2(1)
#=====================================
preview_width= 800
preview_height = int(picam2.sensor_resolution[1] * preview_width/picam2.sensor_resolution[0])
preview_config_raw = picam2.create_preview_configuration(main={"size": (preview_width, preview_height)},
                                                         raw={"size": picam2.sensor_resolution})
picam2.configure(preview_config_raw)
#=====================================
#Detect if AF function is available
AF_Function = True
AF_Enable = True
try:
    picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous})
    print("Auto-Focus Function Enabled")
except RuntimeError as err:
    print("RuntimeError:", err)
    AF_Function = False
#=====================================
class App(QMainWindow):

    def __init__(self):
        super().__init__()
        self.title = sys.argv[0]  #__file__
        self.left = 0
        self.top = 0
        self.setWindowTitle(self.title)

        self.main_widget = MyMainWidget(self)
        self.setCentralWidget(self.main_widget)
        self.show()
        
# factors to convert control's values in float to int for PyQt5 Widgets
FACTOR_BRIGHTNESS = 10
class MyMainWidget(QWidget):

    #--- MyPreviewWidget ---
    #inner class for Preview Window
    class MyPreviewWidget(QWidget):
        
        def __init__(self, subLayout):
            super(QWidget, self).__init__()
            self.setLayout(subLayout)
    #--- End of MyPreviewWidget ---
    
    def read_f(self, file):
        with open(file, encoding='UTF-8') as reader:
            content = reader.read()
        return content
    
    def read_pretty_name(self):
        with open("/etc/os-release", encoding='UTF-8') as f:
            os_release = {}
            for line in f:
                k,v = line.rstrip().split("=")
                os_release[k] = v.strip('"')
        return os_release['PRETTY_NAME']

    def AF_Enable_CheckBox_onStateChanged(self):
        if self.AF_Enable_CheckBox.isChecked():
            picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous})
        else:
            picam2.set_controls({"AfMode": controls.AfModeEnum.Manual})

    def on_Brightness_valueChanged(self):
        sender = self.sender()
        valueBrightness = float(sender.value())/FACTOR_BRIGHTNESS
        self.labelBrightness.setText("Brightness: " + str(valueBrightness))

    def on_Brightness_sliderReleased(self):
        sender = self.sender()
        valueBrightness = float(sender.value())/FACTOR_BRIGHTNESS
        with picam2.controls as controls:
            controls.Brightness = valueBrightness
        print("on_Brightness_sliderReleased:", valueBrightness)
        
    def on_Capture_Clicked(self):
        # There are two buttons on Main/Child Window connected here,
        # identify the sender for info only, no actual use.
        sender = self.sender()
        if sender is self.btnCapture:
            print("Capture button on Main Window clicked")
        if sender is self.btnChildCapture:
            print("Capture button on Child Preview Window clicked")

        self.btnCapture.setEnabled(False)
        
        cfg = picam2.create_still_configuration()
        
        timeStamp = time.strftime("%Y%m%d-%H%M%S")
        targetPath="/home/pi/Desktop/img_"+timeStamp+".jpg"
        print("- Capture image:", targetPath)
        
        picam2.switch_mode_and_capture_file(cfg, targetPath, signal_function=self.qpicamera2.signal_done)

    def capture_done(self, job):
        result = picam2.wait(job)
        self.btnCapture.setEnabled(True)
        print("- capture_done.")
        print(result)
    
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        
        #--- Prepare child Preview Window ----------
        self.childPreviewLayout = QVBoxLayout()
        
        # Check Auto-Focus feature
        if AF_Function:
            self.AF_Enable_CheckBox = QCheckBox("Auto-Focus (Continuous)")
            self.AF_Enable_CheckBox.setChecked(True)
            self.AF_Enable_CheckBox.setEnabled(True)
            self.AF_Enable_CheckBox.stateChanged.connect(self.AF_Enable_CheckBox_onStateChanged)
            self.childPreviewLayout.addWidget(self.AF_Enable_CheckBox)
            print("show Auto-Focus Mode Change QCheckBox")
        else:
            self.AF_Enable_CheckBox = QCheckBox("No Auto-Focus function")
            self.AF_Enable_CheckBox.setChecked(False)
            self.AF_Enable_CheckBox.setEnabled(False)
            print("No Auto-Focus Mode Change QCheckBox")
            
        # Preview qpicamera2
        self.qpicamera2 = QGlPicamera2(picam2,
                          width=preview_width, height=preview_height,
                          keep_ar=True)
        self.qpicamera2.done_signal.connect(self.capture_done)
        
        self.childPreviewLayout.addWidget(self.qpicamera2)
        
        # Capture button on Child Window
        self.btnChildCapture = QPushButton("Capture Image" + str(cam_num))
        self.btnChildCapture.setFont(QFont("Helvetica", 13, QFont.Bold))
        self.btnChildCapture.clicked.connect(self.on_Capture_Clicked)
        
        self.childPreviewLayout.addWidget(self.btnChildCapture)
        
        # pass layout to child Preview Window
        self.myPreviewWindow = self.MyPreviewWidget(self.childPreviewLayout)
        # roughly set Preview windows size according to preview_width x preview_height
        self.myPreviewWindow.setGeometry(10, 10, preview_width+10, preview_height+100)
        self.myPreviewWindow.setWindowTitle("Preview size (" + str(cam_num) + ") - " +
                                            str(preview_width) + " x " + str(preview_height))
        self.myPreviewWindow.show()
        #--- End of Prepare child Preview Window ---

        self.layout = QVBoxLayout()

        # Initialize tab screen
        self.tabs = QTabWidget()
        self.tabControl = QWidget()
        self.tabInfo = QWidget()

        # Add tabs
        self.tabs.addTab(self.tabControl,"Control")
        self.tabs.addTab(self.tabInfo,   " Info  ")
        
        #=== Tab Capture ===
        # Create first tab
        self.tabControl.layout = QVBoxLayout()
        
        self.btnCapture = QPushButton("Capture Image " + str(cam_num))
        self.btnCapture.setFont(QFont("Helvetica", 15, QFont.Bold))
        self.btnCapture.clicked.connect(self.on_Capture_Clicked)
        
        self.tabControl.layout.addWidget(self.btnCapture)
        
        # Prepre camera_controls
        cam_controls = picam2.camera_controls
        
        # gboxCamControls: QGroupBox to hold all controls
        self.gboxCamControls = QGroupBox()
        self.gboxCamControls.setTitle("picam2.camera_controls")
        self.vboxCamControls = QVBoxLayout()
        self.gboxCamControls.setLayout(self.vboxCamControls)
        self.tabControl.layout.addWidget(self.gboxCamControls)
        
        # - Control Brightness -
        self.sliderBrightness = QSlider(Qt.Horizontal)
        self.sliderBrightness.setMinimum(int(cam_controls["Brightness"][0]*FACTOR_BRIGHTNESS))
        self.sliderBrightness.setMaximum(int(cam_controls["Brightness"][1]*FACTOR_BRIGHTNESS))
        value = cam_controls["Brightness"][2]
        self.sliderBrightness.setValue(int(value*FACTOR_BRIGHTNESS))
        self.sliderBrightness.setTickPosition(QSlider.TicksBelow)
        self.sliderBrightness.setTickInterval(1)
        self.sliderBrightness.sliderReleased.connect(self.on_Brightness_sliderReleased)
        self.sliderBrightness.valueChanged.connect(self.on_Brightness_valueChanged)
        
        self.labelBrightness = QLabel("Brightness: " + str(value))
        
        self.vboxCamControls.addWidget(self.labelBrightness)
        self.vboxCamControls.addWidget(self.sliderBrightness)
        # - End of Control Brightness -
        
        self.labelMore = QLabel("...more controls will be placed here in coming exercises.")
        self.vboxCamControls.addWidget(self.labelMore)     
        # End of Prepre camera_controls

        self.tabControl.layout.addStretch()
        
        self.tabControl.setLayout(self.tabControl.layout)

        #=== Tab Info ===
        self.tabInfo.layout = QVBoxLayout()
        
        infoGridLayout = QGridLayout()
        
        rowSpan = 1
        columnSpan0 = 1
        columnSpan1 = 5
        infoGridLayout.addWidget(QLabel('Python', self), 0, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(platform.python_version(), self), 0, 1, rowSpan, columnSpan1)
        
        infoGridLayout.addWidget(QLabel(picamera2_name, self), 1, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(version(picamera2_name), self), 1, 1, rowSpan, columnSpan1)
        
        infoGridLayout.addWidget(QLabel(' ', self), 2, 0, rowSpan, columnSpan0)        
        infoGridLayout.addWidget(QLabel('Camera Module:', self), 3, 0, rowSpan, columnSpan0)
        
        cam_properties = picam2.camera_properties
        cam_Model = cam_properties['Model']
        infoGridLayout.addWidget(QLabel('Model', self), 4, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(cam_Model, self), 4, 1, rowSpan, columnSpan1)
        cam_PixelArraySize = str(cam_properties['PixelArraySize'][0]) + " x " + str(cam_properties['PixelArraySize'][1])
        infoGridLayout.addWidget(QLabel('PixelArraySize', self), 5, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(cam_PixelArraySize, self), 5, 1, rowSpan, columnSpan1)
        
        infoGridLayout.addWidget(QLabel(' ', self), 6, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel('Machine:', self), 7, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel('Board', self), 8, 0, rowSpan, columnSpan0, Qt.AlignTop)
        board_def = "/proc/device-tree/model"
        board_info = self.read_f("/proc/device-tree/model") +"\n(" + board_def +")"
        infoGridLayout.addWidget(QLabel(board_info, self), 8, 1, rowSpan, columnSpan0)
        
        infoGridLayout.addWidget(QLabel('OS', self), 9, 0, rowSpan, columnSpan0, Qt.AlignTop)
        
        os_info = self.read_pretty_name() + "\n" + os.uname()[3] +"\n" + os.uname()[4] \
                  + (" (64-bit)" if sys.maxsize > 2**32 else " (32-bit)")
        infoGridLayout.addWidget(QLabel(os_info, self), 9, 1, rowSpan, columnSpan1)
        
        self.tabInfo.layout.addLayout(infoGridLayout)
        self.tabInfo.layout.addStretch()
        
        self.tabInfo.setLayout(self.tabInfo.layout)
        
        #==================================
        # Add tabs to widget
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)
        
        picam2.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())




Updated 2024-01-15: Add camera_controls: brightness, Contrast, ExposureValue, Saturation & Sharpness.


picam2_qt5_2024-01-15.py
"""
Python 3/PyQt5 + picamera2 to control Raspberry Pi Camera Modules
Tested on Raspberry Pi 5/64-bit Raspberry Pi OS (bookworm)
# in my setup:
# Picamera2(0) - HQ Camera
# Picamera2(1) - Camera Module 3

picam2_qt5_2023-12-28.py first exercise
picam2_qt5_2024-01-03.py Added Auto-Focus feature detection, and switch AF Mode between Continuous & Manual
picam2_qt5_2024-01-07.py Display Preview in seperated window, both Main/Preview windows have Capture button.
picam2_qt5_2024-01-13.py Add camera_controls to adjust brightness at runtime.
                         Handle sys.argv, such that user can select cam at command line.
picam2_qt5_2024-01-15.py Add camera_controls: brightness, Contrast, ExposureValue, Saturation & Sharpness.
"""
import sys, platform, os
from PyQt5.QtWidgets import (QMainWindow, QApplication, QPushButton, QLabel, QCheckBox,
                             QWidget, QTabWidget, QVBoxLayout, QGridLayout,
                             QGroupBox, QSlider)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont

from picamera2 import Picamera2
from picamera2.previews.qt import QGlPicamera2
from picamera2 import __name__ as picamera2_name
from libcamera import controls

import time
from importlib.metadata import version

os.environ["LIBCAMERA_LOG_LEVELS"] = "3"

"""
Because my Camera Module 3 (with Auto-Focus) is assigned to Picamera2(1),
so I make 1 as default

command line usage:
python picam2_qt5_xxx.py    # using default cam
python picam2_qt5_xxx.py 0  # using cam 0
python picam2_qt5_xxx.py 1  # using cam 1
"""

DEFAULT_CAM_NUM = 1
cam_num = DEFAULT_CAM_NUM # default Picamera2(DEFAULT_CAM_NUM)

if len(sys.argv)==2:
    if sys.argv[1] == "1":
        cam_num = 1
    if sys.argv[1] == "0":
        cam_num = 0

print("picam2 = Picamera2("+str(cam_num)+")")
picam2 = Picamera2(cam_num)
#picam2 = Picamera2()   #default to Picamera2(0) without parameter passed
#picam2 = Picamera2(1)
#=====================================
preview_width= 800
preview_height = int(picam2.sensor_resolution[1] * preview_width/picam2.sensor_resolution[0])
preview_config_raw = picam2.create_preview_configuration(main={"size": (preview_width, preview_height)},
                                                         raw={"size": picam2.sensor_resolution})
picam2.configure(preview_config_raw)
#=====================================
#Detect if AF function is available
AF_Function = True
AF_Enable = True
try:
    picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous})
    print("Auto-Focus Function Enabled")
except RuntimeError as err:
    print("RuntimeError:", err)
    AF_Function = False
#=====================================
class App(QMainWindow):

    def __init__(self):
        super().__init__()
        self.title = sys.argv[0]  #__file__
        self.left = 0
        self.top = 0
        self.setWindowTitle(self.title)

        self.main_widget = MyMainWidget(self)
        self.setCentralWidget(self.main_widget)
        self.show()
        
# factors to convert control's values in float to int for PyQt5 Widgets
FACTOR_Brighness = 10
FACTOR_1  = 1
FACTOR_10 = 10
class MyMainWidget(QWidget):

    #--- MyPreviewWidget ---
    #inner class for Preview Window
    class MyPreviewWidget(QWidget):
        
        def __init__(self, subLayout):
            super(QWidget, self).__init__()
            self.setLayout(subLayout)
    #--- End of MyPreviewWidget ---
    
    # --- SliderSetting ---
    #inner class for picam2.controls of float with slider setting
    class SliderSetting:

        def on_Setting_valueChanged(self):
            value = float(self.sliderSetting.value())/self.factor
            self.labelSetting.setText(self.setting_name + ": " + str(value))

        def on_Setting_sliderReleased(self):
            valueSetting = float(self.sliderSetting.value())/self.factor
            self.callback(self.setting_name, valueSetting)

        def __init__(self, setting_name, factor, callback):
            self.setting_name = setting_name
            self.factor = factor
            self.callback = callback
            
            cam_controls = picam2.camera_controls
            
            self.sliderSetting = QSlider(Qt.Horizontal)
            self.sliderSetting.setMinimum(int(cam_controls[self.setting_name][0]*self.factor))
            self.sliderSetting.setMaximum(int(cam_controls[self.setting_name][1]*self.factor))
            value = cam_controls[self.setting_name][2]
            self.sliderSetting.setValue(int(value*self.factor))
            self.sliderSetting.setTickPosition(QSlider.TicksBelow)
            self.sliderSetting.setTickInterval(1)
            self.sliderSetting.sliderReleased.connect(self.on_Setting_sliderReleased)
            self.sliderSetting.valueChanged.connect(self.on_Setting_valueChanged)
        
            self.labelSetting = QLabel(self.setting_name + ": " + str(value))
    #--- End of SliderSetting ---
    
    def read_f(self, file):
        with open(file, encoding='UTF-8') as reader:
            content = reader.read()
        return content
    
    def read_pretty_name(self):
        with open("/etc/os-release", encoding='UTF-8') as f:
            os_release = {}
            for line in f:
                k,v = line.rstrip().split("=")
                os_release[k] = v.strip('"')
        return os_release['PRETTY_NAME']

    def AF_Enable_CheckBox_onStateChanged(self):
        with picam2.controls as cam_controls:
            if self.AF_Enable_CheckBox.isChecked():
                cam_controls.AfMode = controls.AfModeEnum.Continuous
            else:
                cam_controls.AfMode = controls.AfModeEnum.Manual
        
    def on_Capture_Clicked(self):
        # There are two buttons on Main/Child Window connected here,
        # identify the sender for info only, no actual use.
        sender = self.sender()
        if sender is self.btnCapture:
            print("Capture button on Main Window clicked")
        if sender is self.btnChildCapture:
            print("Capture button on Child Preview Window clicked")

        self.btnCapture.setEnabled(False)
        
        cfg = picam2.create_still_configuration()
        
        timeStamp = time.strftime("%Y%m%d-%H%M%S")
        targetPath="/home/pi/Desktop/img" + str(cam_num) + "_"+timeStamp+".jpg"
        print("- Capture image:", targetPath)
        
        picam2.switch_mode_and_capture_file(cfg, targetPath, signal_function=self.qpicamera2.signal_done)

    def capture_done(self, job):
        result = picam2.wait(job)
        self.btnCapture.setEnabled(True)
        print("- capture_done.")
        print(result)
    
    def __init__(self, parent):
        super(QWidget, self).__init__(parent)
        
        #--- Prepare child Preview Window ----------
        self.childPreviewLayout = QVBoxLayout()
        
        # Check Auto-Focus feature
        if AF_Function:
            self.AF_Enable_CheckBox = QCheckBox("Auto-Focus (Continuous)")
            self.AF_Enable_CheckBox.setChecked(True)
            self.AF_Enable_CheckBox.setEnabled(True)
            self.AF_Enable_CheckBox.stateChanged.connect(self.AF_Enable_CheckBox_onStateChanged)
            self.childPreviewLayout.addWidget(self.AF_Enable_CheckBox)
            print("show Auto-Focus Mode Change QCheckBox")
        else:
            self.AF_Enable_CheckBox = QCheckBox("No Auto-Focus function")
            self.AF_Enable_CheckBox.setChecked(False)
            self.AF_Enable_CheckBox.setEnabled(False)
            print("No Auto-Focus Mode Change QCheckBox")
            
        # Preview qpicamera2
        self.qpicamera2 = QGlPicamera2(picam2,
                          width=preview_width, height=preview_height,
                          keep_ar=True)
        self.qpicamera2.done_signal.connect(self.capture_done)
        
        self.childPreviewLayout.addWidget(self.qpicamera2)
        
        # Capture button on Child Window
        self.btnChildCapture = QPushButton("Capture Image" + str(cam_num))
        self.btnChildCapture.setFont(QFont("Helvetica", 13, QFont.Bold))
        self.btnChildCapture.clicked.connect(self.on_Capture_Clicked)
        
        self.childPreviewLayout.addWidget(self.btnChildCapture)
        
        # pass layout to child Preview Window
        self.myPreviewWindow = self.MyPreviewWidget(self.childPreviewLayout)
        # roughly set Preview windows size according to preview_width x preview_height
        self.myPreviewWindow.setGeometry(10, 10, preview_width+10, preview_height+100)
        self.myPreviewWindow.setWindowTitle("Preview size (" + str(cam_num) + ") - " +
                                            str(preview_width) + " x " + str(preview_height))
        self.myPreviewWindow.show()
        #--- End of Prepare child Preview Window ---

        self.layout = QVBoxLayout()

        # Initialize tab screen
        self.tabs = QTabWidget()
        self.tabControl = QWidget()
        self.tabInfo = QWidget()

        # Add tabs
        self.tabs.addTab(self.tabControl,"Control")
        self.tabs.addTab(self.tabInfo,   " Info  ")
        
        #=== Tab Capture ===
        # Create first tab
        self.tabControl.layout = QVBoxLayout()
        
        self.btnCapture = QPushButton("Capture Image " + str(cam_num))
        self.btnCapture.setFont(QFont("Helvetica", 15, QFont.Bold))
        self.btnCapture.clicked.connect(self.on_Capture_Clicked)
        
        self.tabControl.layout.addWidget(self.btnCapture)
        
        # Prepre camera_controls
        cam_controls = picam2.camera_controls

        # gboxCamControls: QGroupBox to hold all controls
        self.gboxCamControls = QGroupBox()
        self.gboxCamControls.setTitle("picam2.camera_controls")
        self.vboxCamControls = QVBoxLayout()
        self.gboxCamControls.setLayout(self.vboxCamControls)
        self.tabControl.layout.addWidget(self.gboxCamControls)

        # - More Control Setting -
        
        #Brightness
        def callback_Brightness(setting_name, value):
            with picam2.controls as cam_controls:
                cam_controls.Brightness = value
                print(str(value), "=>", setting_name, "=", str(cam_controls.Brightness))
        self.sliderBrightness = self.SliderSetting("Brightness", 10, callback_Brightness)
        self.vboxCamControls.addWidget(self.sliderBrightness.labelSetting)
        self.vboxCamControls.addWidget(self.sliderBrightness.sliderSetting)
        
        #Contrast
        def callback_Contrast(setting_name, value):
            with picam2.controls as cam_controls:
                cam_controls.Contrast = value
                print(str(value), "=>", setting_name, "=", str(cam_controls.Contrast))
        self.sliderContrast = self.SliderSetting("Contrast", 1, callback_Contrast)
        self.vboxCamControls.addWidget(self.sliderContrast.labelSetting)
        self.vboxCamControls.addWidget(self.sliderContrast.sliderSetting)
        
        #ExposureValue
        def callback_ExposureValue(setting_name, value):
            with picam2.controls as cam_controls:
                cam_controls.ExposureValue = value
                print(str(value), "=>", setting_name, "=", str(cam_controls.ExposureValue))
        self.sliderExposureValue = self.SliderSetting("ExposureValue", 1, callback_ExposureValue)
        self.vboxCamControls.addWidget(self.sliderExposureValue.labelSetting)
        self.vboxCamControls.addWidget(self.sliderExposureValue.sliderSetting)

        #Saturation
        def callback_Saturation(setting_name, value):
            with picam2.controls as cam_controls:
                cam_controls.Saturation = value
                print(str(value), "=>", setting_name, "=", str(cam_controls.Saturation))
        self.sliderSaturation = self.SliderSetting("Saturation", 1, callback_Saturation)
        self.vboxCamControls.addWidget(self.sliderSaturation.labelSetting)
        self.vboxCamControls.addWidget(self.sliderSaturation.sliderSetting)
        
        #Sharpness
        def callback_Sharpness(setting_name, value):
            with picam2.controls as cam_controls:
                cam_controls.Sharpness = value
                print(str(value), "=>", setting_name, "=", str(cam_controls.Sharpness))
        self.sliderSharpness = self.SliderSetting("Sharpness", 1, callback_Sharpness)
        self.vboxCamControls.addWidget(self.sliderSharpness.labelSetting)
        self.vboxCamControls.addWidget(self.sliderSharpness.sliderSetting)
        
        # - End of Control Setting -
        
        self.labelMore = QLabel("...more controls will be placed here in coming exercises.")
        self.vboxCamControls.addWidget(self.labelMore)
        # End of Prepre camera_controls

        self.tabControl.layout.addStretch()
        
        self.tabControl.setLayout(self.tabControl.layout)

        #=== Tab Info ===
        self.tabInfo.layout = QVBoxLayout()
        
        infoGridLayout = QGridLayout()
        
        rowSpan = 1
        columnSpan0 = 1
        columnSpan1 = 5
        infoGridLayout.addWidget(QLabel('Python', self), 0, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(platform.python_version(), self), 0, 1, rowSpan, columnSpan1)
        
        infoGridLayout.addWidget(QLabel(picamera2_name, self), 1, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(version(picamera2_name), self), 1, 1, rowSpan, columnSpan1)
        
        infoGridLayout.addWidget(QLabel(' ', self), 2, 0, rowSpan, columnSpan0)        
        infoGridLayout.addWidget(QLabel('Camera Module:', self), 3, 0, rowSpan, columnSpan0)
        
        cam_properties = picam2.camera_properties
        cam_Model = cam_properties['Model']
        infoGridLayout.addWidget(QLabel('Model', self), 4, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(cam_Model, self), 4, 1, rowSpan, columnSpan1)
        cam_PixelArraySize = str(cam_properties['PixelArraySize'][0]) + " x " + str(cam_properties['PixelArraySize'][1])
        infoGridLayout.addWidget(QLabel('PixelArraySize', self), 5, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel(cam_PixelArraySize, self), 5, 1, rowSpan, columnSpan1)
        
        infoGridLayout.addWidget(QLabel(' ', self), 6, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel('Machine:', self), 7, 0, rowSpan, columnSpan0)
        infoGridLayout.addWidget(QLabel('Board', self), 8, 0, rowSpan, columnSpan0, Qt.AlignTop)
        board_def = "/proc/device-tree/model"
        board_info = self.read_f("/proc/device-tree/model") +"\n(" + board_def +")"
        infoGridLayout.addWidget(QLabel(board_info, self), 8, 1, rowSpan, columnSpan0)
        
        infoGridLayout.addWidget(QLabel('OS', self), 9, 0, rowSpan, columnSpan0, Qt.AlignTop)
        
        os_info = self.read_pretty_name() + "\n" + os.uname()[3] +"\n" + os.uname()[4] \
                  + (" (64-bit)" if sys.maxsize > 2**32 else " (32-bit)")
        infoGridLayout.addWidget(QLabel(os_info, self), 9, 1, rowSpan, columnSpan1)
        
        self.tabInfo.layout.addLayout(infoGridLayout)
        self.tabInfo.layout.addStretch()
        
        self.tabInfo.setLayout(self.tabInfo.layout)
        
        #==================================
        # Add tabs to widget
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)
        
        picam2.start()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())





next:
Python/PyQt5/Picamera2 to control Raspberry Pi Cameras with GUI, added White Balance setting.
Python 3/PyQt5 + picamera2 on Raspberry Pi, list available cameras.

Comments

Popular posts from this blog

480x320 TFT/ILI9488 SPI wih EP32C3 (arduino-esp32) using Arduino_GFX Library

my dev.tools - FNIRSI 2C23T 3-in-1 Dual Channel Oscilloscope/Multimeter/Signal Generator