PyQt6 GUI - 交互式亮度/对比度过滤器创建

问题描述 投票:0回答:0

使用 PyQt6,我当前的 GUI 的目标是让用户将 .bmp 图像添加到列表框(从他们计算机的某处获取)并且每次用户单击列表框中的项目时,相同的图像将出现两次QLabel(当我说两次时,我的意思是 QLabel 中有一个不应更改的“原始”顶部图像,然后在底部 QLabel 中有备用图像将由用户操作)。

我希望用户在键盘上使用按键事件(“W”或“w”)来增加底部图像的亮度,或者在键盘上使用按键事件(“S”或“s”)来降低亮度底部图像。

所以,到目前为止,我已经掌握了一切,用户可以在他们的计算机上找到一个文件夹,将 .bmp 图像添加到列表框,并让这些图像填充顶部/底部图像 QLabels。这一切都完成了,我唯一想不通的是如何根据用户点击键盘上的 W 或 S 键来使亮度过滤器交互。

对此有什么建议吗?

This is how the GUI looks

到目前为止的完整代码:

import os
import sys

import pyautogui
import cv2 as cv
import numpy as np
import qimage2ndarray

from PyQt6.QtGui import QPalette, QColor, QPixmap, QFont, QTransform, QImage
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QListWidget, \
QPushButton, QFileDialog, QLabel, QSizePolicy, QScrollArea, QSlider

class MainWindow(QMainWindow, QScrollArea):
    def __init__(self):
        super().__init__()
        self.screen_width, self.screen_height = pyautogui.size()

        self.setWindowTitle("GUI")
    
        main_frame_widget = QWidget()
        main_frame = QGridLayout()
        self.list_box = QListWidget()
        list_box_widget = QWidget(main_frame_widget)
    
        self.top_image = QLabel()
        top_image_text = QLabel(self.top_image)
    
        self.bottom_image = QLabel()
        bottom_image_text = QLabel(self.bottom_image)
    
        top_image_text.setText("Original Image")
        top_image_text.setFont(QFont("Arial", 26))
        top_image_text.setStyleSheet("border: none;")
    
        self.top_image.setStyleSheet("border: 2px solid black;")
        self.top_image.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
    
        bottom_image_text.setText("Alternate Image")
        bottom_image_text.setFont(QFont("Arial", 26))
        bottom_image_text.setStyleSheet("border: none;")
    
        self.bottom_image.setStyleSheet("border: 2px solid black;")
        self.bottom_image.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
    
        main_frame.setColumnStretch(0, 1)
        main_frame.setColumnStretch(1, 1)
        main_frame.setRowStretch(0, 1)
        main_frame.setRowStretch(1, 1)
    
        # Create a button to add items to the QListWidget
        list_box_add_items_button = QPushButton("Add Images")
        list_box_add_items_button.clicked.connect(self.add_folder)
    
        list_box_clear_all_button = QPushButton("Clear All Items")
        list_box_clear_all_button.clicked.connect(self.clear_list_box)
    
        list_box_clear_item_button = QPushButton("Clear An Item")
        list_box_clear_item_button.clicked.connect(self.delete_item_in_list_box)
    
        self.list_box.currentRowChanged.connect(self.on_item_clicked)
    
        # Create a vertical layout to add the QListWidget and button
        list_box_layout = QVBoxLayout()
        list_box_layout.addWidget(list_box_add_items_button)
        list_box_layout.addWidget(list_box_clear_all_button)
        list_box_layout.addWidget(list_box_clear_item_button)
        list_box_layout.addWidget(self.list_box)
    
        list_box_widget.setLayout(list_box_layout)
    
        main_frame.addWidget(self.top_image, 0, 0)
        main_frame.addWidget(self.bottom_image, 1, 0)
        main_frame.addWidget(list_box_widget, 1, 1)
    
        main_frame_widget.setLayout(main_frame)
    
        self.setCentralWidget(main_frame_widget)
    
    def on_item_clicked(self):
        if self.list_box.currentItem() is None:
            return
    
        image_path = self.list_box.currentItem().data(Qt.ItemDataRole.DisplayRole)
        pixmap = QPixmap(image_path)
    
        scaled_pixmap_top = pixmap.scaled(self.top_image.contentsRect().width(), self.top_image.contentsRect().height(), Qt.AspectRatioMode.KeepAspectRatio)
        self.scaled_pixmap_bottom = pixmap.scaled(self.bottom_image.contentsRect().width(), self.bottom_image.contentsRect().height(), Qt.AspectRatioMode.KeepAspectRatio)
    
        #Work in progress for contrast
        scaled_pixmap_bottom_to_q_image = self.scaled_pixmap_bottom.toImage()
    
        scaled_pixmap_bottom_image_to_ndarray = scaled_pixmap_bottom_to_q_image.bits().asstring(
            scaled_pixmap_bottom_to_q_image.width() * scaled_pixmap_bottom_to_q_image.height() * 4)
    
        self.final_ndarray = np.frombuffer(scaled_pixmap_bottom_image_to_ndarray, dtype=np.uint8).reshape(
            (scaled_pixmap_bottom_to_q_image.height(), scaled_pixmap_bottom_to_q_image.width(), 4))
    
        self.top_image.setPixmap(scaled_pixmap_top)
        self.bottom_image.setPixmap(self.scaled_pixmap_bottom)
    
    
    def clear_list_box(self):
        self.list_box.clear()
        self.top_image.clear()
        self.bottom_image.clear()
    
    
    def delete_item_in_list_box(self):
        current_item = self.list_box.currentItem()
        if current_item is not None:
            self.list_box.takeItem(self.list_box.row(current_item))
            if self.list_box.count() == 0:
                self.top_image.clear()
                self.bottom_image.clear()
    
    
    def add_folder(self):
        # Prompt the user to select a folder and add it to the list box
        folder_path = QFileDialog.getExistingDirectory(self, "Select Folder To Add To The ListBox")  # folder_path type is str
        if folder_path:
            bmp_files = []
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    if file.endswith('.bmp'):
                        file_path = os.path.join(root, file)
                        if os.path.basename(file_path) not in [os.path.basename(self.list_box.item(i).text()) for i in
                                                               range(self.list_box.count())]:
                            bmp_files.append(os.path.normpath(os.path.join(root, file)))
    
                # Add the .bmp files to the list box
            for bmp_file in bmp_files:
                self.list_box.addItem(bmp_file)
    
    
    def keyPressEvent(self, event):
        if event.key() == Qt.Key.Key_Shift:
            contrast_factor = 15
            converted = cv.convertScaleAbs(self.final_ndarray, alpha=contrast_factor, beta=0)
            qimage = qimage2ndarray.array2qimage(converted)
            pixmap = QPixmap(qimage)
            self.bottom_image.setPixmap(pixmap)
    
        elif event.key() == Qt.Key.Key_S:
            pass
            # self.scaled_pixmap_bottom -= self.change_contrast(self.scaled_pixmap_bottom)
    
            # self.bottom_image.setPixmap(self.scaled_pixmap_bottom)
    
        elif event.key() == Qt.Key.Key_Escape:
            print("You have exited the code")
            sys.exit(1)
    
        else:
            print("Wrong button, please press 'W' to increase contrast or 'S' to decrease contrast")

app = QApplication([])  # pass in sys.argv if you want to use CLI arguments
window = MainWindow()
window.showMaximized()
window.show()
app.exec()

我在想什么:

因此,在我的 on_item_clicked 函数中,我获取文件名字符串 (image_path) 并将其转换为 QPixmap,以便我最终可以将其放入我的 QLabel (self.bottom_image) 中。然后我对其进行了一些缩放,以使其与我的 QLabel 框大小相匹配。

现在,我的问题是我不知道如何调整 QPixmap 对象的亮度,或者如果可能的话,或者我是否必须将 QPixmap 转换为 ndarray 或整数?我尝试将 QPixmap 转换为 ndarray,你会在 (self.final_ndarray) 中看到它,所以现在我试图在我的 keyPressEvent 函数中使用那个 self.final_ndarray 变量。

我之前提到过最终我想使用“W”或“w”键来增加亮度,但现在,我只是尝试使用“shift”键进行测试。每次我点击“shift”键时,我的整个代码都会崩溃,而且它不会给出我看到的任何类型的错误。

有什么建议吗?

谢谢!

python-3.x user-interface filter interactive pyqt6
© www.soinside.com 2019 - 2024. All rights reserved.