Pages

Showing posts with label PyQt6. Show all posts
Showing posts with label PyQt6. Show all posts

Saturday, December 14, 2024

Fedora 41 : OpenCV example with PyQt6.

Today I tested another source code with opencv, numpy, PyQt6 python packages.
I install opencv python package with dnf5 tool:
root@localhost:/home/mythcat# dnf5 install  python3-opencv.x86_64
The source code let you to open, change a image and save using sliders and a reset option.
This is the source code:
import sys
import cv2
import numpy as np
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QSlider, QFileDialog, QPushButton, QHBoxLayout
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtCore import Qt, pyqtSlot

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Real-Time Color Selection")
        self.setGeometry(100, 100, 1200, 800)

        # Create central widget and main layout
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # Create image label
        self.image_label = QLabel()
        main_layout.addWidget(self.image_label)

        # Initialize sliders
        self.lower_h = QSlider(Qt.Orientation.Horizontal)
        self.lower_s = QSlider(Qt.Orientation.Horizontal)
        self.lower_v = QSlider(Qt.Orientation.Horizontal)
        self.upper_h = QSlider(Qt.Orientation.Horizontal)
        self.upper_s = QSlider(Qt.Orientation.Horizontal)
        self.upper_v = QSlider(Qt.Orientation.Horizontal)

        # Set slider ranges
        for slider in [self.lower_h, self.upper_h]:
            slider.setRange(0, 179)
        for slider in [self.lower_s, self.lower_v, self.upper_s, self.upper_v]:
            slider.setRange(0, 255)

        # Set initial slider values
        self.lower_h.setValue(50)
        self.lower_s.setValue(100)
        self.lower_v.setValue(50)
        self.upper_h.setValue(130)
        self.upper_s.setValue(255)
        self.upper_v.setValue(255)

        # Connect sliders to update function
        self.lower_h.valueChanged.connect(self.update_hsv_range)
        self.lower_s.valueChanged.connect(self.update_hsv_range)
        self.lower_v.valueChanged.connect(self.update_hsv_range)
        self.upper_h.valueChanged.connect(self.update_hsv_range)
        self.upper_s.valueChanged.connect(self.update_hsv_range)
        self.upper_v.valueChanged.connect(self.update_hsv_range)

        # Create slider layouts with labels
        sliders_layout = QVBoxLayout()
        
        # Add slider pairs with labels
        slider_pairs = [
            ("Lower Hue", self.lower_h),
            ("Lower Saturation", self.lower_s),
            ("Lower Value", self.lower_v),
            ("Upper Hue", self.upper_h),
            ("Upper Saturation", self.upper_s),
            ("Upper Value", self.upper_v)
        ]

        for label_text, slider in slider_pairs:
            row_layout = QHBoxLayout()
            label = QLabel(label_text)
            label.setMinimumWidth(120)
            row_layout.addWidget(label)
            row_layout.addWidget(slider)
            sliders_layout.addLayout(row_layout)

        main_layout.addLayout(sliders_layout)

        # Add buttons
        button_layout = QHBoxLayout()
        
        self.reset_button = QPushButton("Reset Values")
        self.reset_button.clicked.connect(self.reset_values)
        button_layout.addWidget(self.reset_button)

        self.open_image_button = QPushButton("Open Image")
        self.open_image_button.clicked.connect(self.open_image)
        button_layout.addWidget(self.open_image_button)

        self.save_button = QPushButton("Save Image")
        self.save_button.clicked.connect(self.save_image)
        button_layout.addWidget(self.save_button)
        main_layout.addLayout(button_layout)

        # Process initial image
        self.process_image()

    def process_image(self):
        image_bgr = cv2.imread("image.png")
        if image_bgr is None:
            image_bgr = cv2.imread("default_image.png")
        
        self.image_bgr = image_bgr
        self.image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)

        # Create initial mask using current slider values
        lower_values = np.array([self.lower_h.value(), self.lower_s.value(), self.lower_v.value()])
        upper_values = np.array([self.upper_h.value(), self.upper_s.value(), self.upper_v.value()])
        
        mask_test = cv2.inRange(self.image_hsv, lower_values, upper_values)
        image_bgr_masked = cv2.bitwise_and(image_bgr, image_bgr, mask=mask_test)
        self.image_rgb = cv2.cvtColor(image_bgr_masked, cv2.COLOR_BGR2RGB)
        self.update_image()

    def update_image(self):
        height, width, channel = self.image_rgb.shape
        bytes_per_line = width * channel
        q_image = QImage(self.image_rgb.data, width, height, bytes_per_line, QImage.Format.Format_RGB888)
        pixmap = QPixmap.fromImage(q_image)
        self.image_label.setPixmap(pixmap.scaled(700, 500, Qt.AspectRatioMode.KeepAspectRatio))

    def update_hsv_range(self):
        lower_values = np.array([self.lower_h.value(), self.lower_s.value(), self.lower_v.value()])
        upper_values = np.array([self.upper_h.value(), self.upper_s.value(), self.upper_v.value()])
        mask_test = cv2.inRange(self.image_hsv, lower_values, upper_values)
        image_bgr_masked = cv2.bitwise_and(self.image_bgr, self.image_bgr, mask=mask_test)
        self.image_rgb = cv2.cvtColor(image_bgr_masked, cv2.COLOR_BGR2RGB)
        self.update_image()

    def reset_values(self):
        self.lower_h.setValue(50)
        self.lower_s.setValue(100)
        self.lower_v.setValue(50)
        self.upper_h.setValue(130)
        self.upper_s.setValue(255)
        self.upper_v.setValue(255)

    def open_image(self):
        filename, _ = QFileDialog.getOpenFileName(self, "Select Image File", "", "Image Files (*.png *.jpg *.jpeg)")
        if filename:
            self.image_bgr = cv2.imread(filename)
            if self.image_bgr is not None:
                self.image_hsv = cv2.cvtColor(self.image_bgr, cv2.COLOR_BGR2HSV)
                self.update_hsv_range()  # This will apply current filter and update display

    def save_image(self):
        filename, _ = QFileDialog.getSaveFileName(self, "Save Image", "", "PNG Files (*.png);;JPEG Files (*.jpg)")
        if filename:
            # Make sure filename has an extension
            if not filename.endswith(('.png', '.jpg', '.jpeg')):
                filename += '.png'
            # Convert and save
            output_image = cv2.cvtColor(self.image_rgb, cv2.COLOR_RGB2BGR)
            cv2.imwrite(filename, output_image)

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

Monday, August 22, 2022

Fedora 37 : Install PyQt5 and PyQt6 on Fedora.

In this tutorial, I will show you how to install PyQt5 and PyQt6 on Fedora 37 Distro Linux.
I used the DNF tool on the sudo user.
To install PyQt5 I used this command:
[root@fedora mythcat]# dnf install python3-qt5.x86_64
Last metadata expiration check: 2:20:40 ago on Wed 17 Aug 2022 09:42:57 PM EEST.
Dependencies resolved.
...
Installed:
  openal-soft-1.22.2-2.fc37.x86_64                                              
  python-qt5-rpm-macros-5.15.6-7.fc37.noarch                                    
  python3-pyqt5-sip-12.11.0-2.fc37.x86_64                                       
  python3-qt5-5.15.6-7.fc37.x86_64                                              
  python3-qt5-base-5.15.6-7.fc37.x86_64                                         
  qt5-qtconnectivity-5.15.5-2.fc37.x86_64                                       
  qt5-qtlocation-5.15.5-3.fc37.x86_64                                           
  qt5-qtmultimedia-5.15.5-2.fc37.x86_64                                         
  qt5-qtsensors-5.15.5-2.fc37.x86_64                                            
  qt5-qtserialport-5.15.5-2.fc37.x86_64                                         
  qt5-qtsvg-5.15.5-2.fc37.x86_64                                                
  qt5-qttools-common-5.15.5-2.fc37.noarch                                       
  qt5-qttools-libs-designer-5.15.5-2.fc37.x86_64                                
  qt5-qttools-libs-help-5.15.5-2.fc37.x86_64                                    
  qt5-qtwebchannel-5.15.5-2.fc37.x86_64                                         
  qt5-qtwebsockets-5.15.5-2.fc37.x86_64                                         
  qt5-qtxmlpatterns-5.15.5-2.fc37.x86_64                                        

Complete!
If you want to use PyQt6 then you need to use the sip solution.
Let's search and install it with the DNF tool.
[root@fedora mythcat]# dnf search qt6 | grep python
Last metadata expiration check: 1:02:01 ago on Sun 21 Aug 2022 04:43:24 PM EEST.
python3-pyqt6-sip.x86_64 : The sip module support for PyQt6
[root@fedora mythcat]# dnf install python3-pyqt6-sip.x86_64
Last metadata expiration check: 1:02:24 ago on Sun 21 Aug 2022 04:43:24 PM EEST.
Dependencies resolved.
...
Installed:
  python3-pyqt6-sip-13.3.0-3.fc37.x86_64                                        

Complete!
I used the python command and I import PyQt5 and PyQt6
[mythcat@fedora ~]$ python
Python 3.11.0rc1 (main, Aug  9 2022, 00:00:00) [GCC 12.1.1 20220810 (Red Hat 12.1.1-4)] on linux
...
The python modules are installed and working well.

Saturday, November 6, 2021

Fedora 35 : PyQt6 and Python 3.

I tested the new python version 10 and pyqt version 6 on the fedora version 35 distribution.
[mythcat@fedora ~]$ python
Python 3.10.0 (default, Oct  4 2021, 00:00:00) [GCC 11.2.1 20210728 (Red Hat 11.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
...
[mythcat@fedora ~]$ uname -a
Linux fedora 5.14.15-300.fc35.x86_64 #1 SMP Wed Oct 27 15:53:39 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
I install PyQt6 easy with pip tool:

[mythcat@fedora ~]$ pip install PyQt6 --user
Collecting PyQt6
  Downloading PyQt6-6.2.1-cp36-abi3-manylinux1_x86_64.whl (7.7 MB)
  ...
  Downloading PyQt6_Qt6-6.2.1-py3-none-manylinux_2_28_x86_64.whl (50.0 MB)
  ...
  Downloading PyQt6_sip-13.1.0-cp310-cp310-manylinux1_x86_64.whl (309 kB)
Installing collected packages: PyQt6-sip, PyQt6-Qt6, PyQt6
Successfully installed PyQt6-6.2.1 PyQt6-Qt6-6.2.1 PyQt6-sip-13.1.0
I tested with this python source code and it works fine.
import sys
from PyQt6.QtWidgets import QApplication, QWidget

def main():

    app = QApplication(sys.argv)

    w = QWidget()
    w.resize(250, 200)
    w.move(300, 300)

    w.setWindowTitle('Simple')
    w.show()

    sys.exit(app.exec())

if __name__ == '__main__':
    main()