import sys from PyQt6.QtCore import Qt from PyQt6.QtWidgets import * import PyQt6.QtGui as QtGui from PyQt6.QtGui import QColor, QAction, QPixmap, QPalette from pathlib import Path import cv2 import numpy as np from Photo import Photo from functools import partial class Judge: def __init__(self, newWindow: QDialog, confirm, cancel): button1 = QPushButton('Confirm', newWindow) button1.clicked.connect(confirm) button2 = QPushButton('Cancel', newWindow) button2.clicked.connect(cancel) hbox = QHBoxLayout() hbox.addWidget(button1) hbox.addWidget(button2) self.hbox = hbox class Menu: def __init__(self, menu: QMenu): self.menu = menu def addFun(self, name, p, lam): action = QAction(name, p) action.triggered.connect(lam) self.menu.addAction(action) def changeValue(sld, label): text = f'ratio: {sld.value()}' label.setText(text) class PhotoProcessor(QMainWindow): def __init__(self): super().__init__() self.labelImage = None self.initUI() def initUI(self): self.labelImage = QLabel(self) self.initMenu() self.showMaximized() def initMenu(self): self.statusBar() menuBar = self.menuBar() fileMenu = menuBar.addMenu('File') editMenu = menuBar.addMenu('Edit') self.fileMenu = Menu(fileMenu) self.editMenu = Menu(editMenu) self.initFileMenu() self.initEditMenu() def initEditMenu(self): self.editMenu.addFun('Rotate', self, lambda: self.noAsk(Photo.rotate)) self.editMenu.addFun('Vertical Mirror', self, lambda: self.noAsk(Photo.vertical_mirror)) self.editMenu.addFun('Horizontal Mirror', self, lambda: self.noAsk(Photo.horizontal_mirror)) self.editMenu.addFun('Resize', self, lambda: self.ask('ratio', 1, 500, 100, Photo.resize)) # wait for brightness self.editMenu.addFun('Lightning', self, lambda: self.ask('value', -100, 100, 0, Photo.lighting)) # crash self.editMenu.addFun('Contrast', self, lambda: self.ask('value', -100, 100, 0, Photo.contrast)) self.editMenu.addFun('Hue', self, lambda: self.ask('value', 0, 180, 0, Photo.hue)) blurMenu = self.editMenu.menu.addMenu('Blur') self.blurMenu = Menu(blurMenu) self.blurMenu.addFun('Blur', self, lambda: self.ask('value', 0, 20, 0, Photo.blur)) self.blurMenu.addFun('Median_Blur', self, lambda: self.ask('value', 0, 20, 0, Photo.median_blur)) self.blurMenu.addFun('gaussian_blur', self, lambda: self.ask('value', 0, 20, 0, Photo.gaussian_blur)) self.editMenu.addFun('Gray', self, lambda: self.noAsk(Photo.to_gray)) self.editMenu.addFun('Invert', self, lambda: self.noAsk(Photo.invert)) binaryMenu = self.editMenu.menu.addMenu('Binary') self.binaryMenu = Menu(binaryMenu) self.binaryMenu.addFun('Binary', self, lambda: self.ask('threshold', 0, 255, 127, Photo.to_binary)) self.binaryMenu.addFun('Binary_ostu', self, lambda: self.noAsk(Photo.to_binary_ostu)) self.binaryMenu.addFun('Binary_adaptive', self, lambda: self.noAsk(Photo.to_binary_adaptive)) self.editMenu.addFun('Sharpen', self, lambda: self.ask('value', 0, 20, 0, Photo.sharpen)) self.editMenu.addFun('Open', self, lambda: self.noAsk(Photo.open)) self.editMenu.addFun('Close', self, lambda: self.noAsk(Photo.close)) self.editMenu.addFun('Scale', self, lambda: self.noAsk(Photo.scale)) self.editMenu.addFun('Equalize', self, lambda: self.noAsk(Photo.equalizeHist)) self.editMenu.addFun('DetectAntigen', self, lambda: self.noAsk(Photo.detectQRcode)) def noAsk(self, func): func(self.Image) self.display_image() def initFileMenu(self): self.fileMenu.addFun('Open Image', self, self.openImage) self.fileMenu.addFun('Save Image', self, self.saveImage) self.fileMenu.addFun('Original Image', self, lambda: self.noAsk(Photo.origin)) def saveImage(self): home_dir = str(Path.home()) filepath = QFileDialog.getSaveFileName(self, 'Save File', home_dir, 'Image files(*.jpg)') if filepath[0]: cv2.imwrite(filepath[0], self.Image.img) def openImage(self): home_dir = str(Path.home()) filepath = QFileDialog.getOpenFileName(self, 'Open Image', home_dir, "Image files(*.jpg *.png)") if filepath[0]: self.Image = Photo(filepath[0]) self.display_image() def display_image(self): shrink = cv2.cvtColor(self.Image.img, cv2.COLOR_BGR2RGB) qt_img = QtGui.QImage(shrink.data, shrink.shape[1], shrink.shape[0], shrink.shape[1] * 3, QtGui.QImage.Format.Format_RGB888) w, h = qt_img.width(), qt_img.height() f1 = 1.0 * self.width() / w f2 = 1.0 * self.height() / h factor = min([f1, f2]) width = int(w * factor) height = int(h * factor) self.labelImage.setPixmap(QPixmap.fromImage(qt_img).scaled(width, height)) self.labelImage.resize(width, height) # self.image_resize() def image_resize(self): w, h = self.labelImage.width(), self.labelImage.height() f1 = 1.0 * self.width() / w f2 = 1.0 * self.height() / h factor = min([f1, f2]) width = int(w * factor) height = int(h * factor) self.labelImage.resize(width, height) def cancel(self): self.sender().parent().close() def ask(self, text_, min_value, max_value, init, func): newWindow = QDialog() text = text_ + f': {init}' vbox = QVBoxLayout() label = QLabel(text, newWindow) sld = QSlider(Qt.Orientation.Horizontal, newWindow) sld.setMaximum(max_value) sld.setMinimum(min_value) sld.setTickPosition(QSlider.TickPosition.TicksAbove) sld.setSliderPosition(init) sld.setFocusPolicy(Qt.FocusPolicy.NoFocus) sld.setGeometry(30, 40, 200, 30) sld.valueChanged[int].connect(lambda: changeValue(sld, label)) judge = Judge(newWindow, lambda: self.setValue(sld, func), self.cancel) vbox.addWidget(label) vbox.addWidget(sld) vbox.addLayout(judge.hbox) newWindow.setLayout(vbox) newWindow.show() newWindow.exec() def setValue(self, sld, fun): a = self.sender() b = a.parent() b.close() fun(self.Image, sld.value()) self.display_image() def run(): app = QApplication(sys.argv) pp = PhotoProcessor() sys.exit(app.exec()) run()