diff --git a/mainwindow.py b/mainwindow.py deleted file mode 100644 index 1a2af23..0000000 --- a/mainwindow.py +++ /dev/null @@ -1,956 +0,0 @@ -import sys -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtWidgets import QFileDialog, QGraphicsScene, QGraphicsPixmapItem -import cv2 -import numpy as np -from PyQt5.QtGui import QImage, QPixmap -from mainwindow9_ui import Ui_Image_processing -import vessel_detection -import os -import io -from PIL import Image -from PIL import ImageFile - -class MainWindow(QtWidgets.QMainWindow, Ui_Image_processing): - def __init__(self, parent=None): - super(MainWindow, self).__init__(parent) - self.setupUi(self) - self.original_image = None - self.modified_image = None - self.image_history = [] - - # Connect buttons to functions - #图片存取 - self.pushButton_open_image.clicked.connect(self.open_image) - self.pushButton_undo_image.clicked.connect(self.undo_last_action) - self.pushButton_close_image.clicked.connect(self.close_image) - self.pushButton_save_image.clicked.connect(self.save_image) - self.pushButton_reset_image.clicked.connect(self.reset_image) - # 基础功能 - self.pushButton_symmetry.clicked.connect(self.symmetry) - self.pushButton_rotate.clicked.connect(self.rotate) - self.pushButton_to_grayscale.clicked.connect(self.to_grayscale) - self.pushButton_invert_colors.clicked.connect(self.invert_colors) - self.size_controller.valueChanged.connect(self.change_size) - #算术运算 - self.pushButton_add.clicked.connect(self.image_add) - self.pushButton_minus.clicked.connect(self.image_subtract) - self.pushButton_multi.clicked.connect(self.image_multiply) - self.pushButton_complex_change.clicked.connect(self.complex_change) - #二值化 - self.pushButton_to_binary.clicked.connect(self.to_binary) - #hough线条预测 - self.pushButton_hough.clicked.connect(self.hough) - self.pushButton_hist_equ.clicked.connect(self.equalize_histogram) - self.pushButton_brightness_change.clicked.connect(self.brightness_change) - self.pushButton_hist_equ_2.clicked.connect(self.histogram_normalization) - #空间滤波器 - self.pushButton_mean_filter.clicked.connect(self.mean_filter) - self.pushButton_gaussian_filter.clicked.connect(self.gaussian_filter) - self.pushButton_median_filter.clicked.connect(self.median_filter) - #频域滤波 - self.pushButton_band_stop_filter.clicked.connect(self.band_stop_filter) - self.pushButton_band_pass_filter.clicked.connect(self.band_pass_filter) - self.pushButton_ideal_high_pass_filter.clicked.connect(self.ideal_high_pass_filter) - self.pushButton_ideal_low_pass_filter.clicked.connect(self.ideal_low_pass_filter) - self.pushButton_butterworth_high_pass_filter.clicked.connect(self.butterworth_high_pass_filter) - self.pushButton_butterworth_low_pass_filter.clicked.connect(self.butterworth_low_pass_filter) - self.pushButton_gaussian_high_pass_filter.clicked.connect(self.gaussian_high_pass_filter) - self.pushButton_gaussian_low_pass_filter.clicked.connect(self.gaussian_low_pass_filter) - #添加噪声 - self.pushButton_add_gaussian_noise.clicked.connect(self.add_gaussian_noise) - self.pushButton_add_poisson_noise.clicked.connect(self.add_poisson_noise) - self.pushButton_add_salt_and_pepper_noise.clicked.connect(self.add_salt_and_pepper_noise) - #形态学操作 - self.pushButton_apply_erosion.clicked.connect(self.apply_erosion) - self.pushButton_apply_dilation.clicked.connect(self.apply_dilation) - #边缘检测 - self.pushButton_log_edge_detection.clicked.connect(self.log_edge_detection) - self.pushButton_roberts_edge_detection.clicked.connect(self.roberts_edge_detection) - self.pushButton_sobel_edge_detection.clicked.connect(self.sobel_edge_detection) - self.pushButton_laplacian_edge_detection.clicked.connect(self.laplacian_edge_detection) - self.pushButton_canny_edge_detection.clicked.connect(self.canny_edge_detection) - #锐化 - self.pushButton_apply_roberts.clicked.connect(self.apply_roberts) - self.pushButton_apply_sobel.clicked.connect(self.apply_sobel) - self.pushButton_apply_prewitt.clicked.connect(self.apply_prewitt) - self.pushButton_sobel_edge_detection_5.clicked.connect(self.apply_laplacian) - #实际应用 - self.pushButton_vessel_division.clicked.connect(self.vessel_division) - self.pushButton_repair_image.clicked.connect(self.repair_image) - self.pushButton_compress_image.clicked.connect(self.compress_image) - #测试专用 - self.pushButton_test.clicked.connect(self.repair_image) - - def open_image(self): - options = QFileDialog.Options() - fileName, _ = QFileDialog.getOpenFileName(self, "打开图片", "", "All Files (*);;Image Files (*.jpg *.png)", options=options) - if fileName: - self.original_image = cv2.imread(fileName) - self.modified_image = self.original_image.copy() - self.image_history.clear() # Clear history when a new image is opened - self.display_image(self.original_image, self.graphicsView) - self.display_image(self.modified_image, self.graphicsView_2) - - def close_image(self): - self.original_image = None - self.modified_image = None - self.image_history.clear() # Clear history when image is closed - self.graphicsView.scene().clear() - self.graphicsView_2.scene().clear() - - def save_image(self): - if self.modified_image is not None: - options = QFileDialog.Options() - fileName, _ = QFileDialog.getSaveFileName(self, "保存图片", "", "Image Files (*.jpg *.png)", options=options) - if fileName: - cv2.imwrite(fileName, self.modified_image) - - def reset_image(self): - if self.original_image is not None: - self.modified_image = self.original_image.copy() - self.image_history.clear() # Clear history when image is reset - self.display_image(self.modified_image, self.graphicsView_2) - - def add_to_history(self): - if self.modified_image is not None: - self.image_history.append(self.modified_image.copy()) - - def undo_last_action(self): - if self.image_history: - self.modified_image = self.image_history.pop() - self.display_image(self.modified_image, self.graphicsView_2) - - def symmetry(self): - if self.modified_image is not None: - self.add_to_history() - self.modified_image = cv2.flip(self.modified_image, 1) # Horizontal flip - self.display_image(self.modified_image, self.graphicsView_2) - - def rotate(self): - if self.modified_image is not None: - self.add_to_history() - self.modified_image = cv2.rotate(self.modified_image, cv2.ROTATE_90_CLOCKWISE) # Rotate 90 degrees clockwise - self.display_image(self.modified_image, self.graphicsView_2) - - def to_grayscale(self): - if self.modified_image is not None: - self.add_to_history() - if len(self.modified_image.shape) == 3: # Image has 3 channels (BGR) - self.modified_image = cv2.cvtColor(self.modified_image, cv2.COLOR_BGR2GRAY) - self.display_image(self.modified_image, self.graphicsView_2) - - def to_binary(self): - if self.modified_image is not None: - self.add_to_history() - if len(self.original_image.shape) == 3: # Image has 3 channels (BGR) - gray_image = cv2.cvtColor(self.modified_image, cv2.COLOR_BGR2GRAY) - else: - gray_image = self.modified_image - - unique_values = set(gray_image.flatten()) - if unique_values.issubset({0, 255}): # Image is already binary - self.modified_image = gray_image - else: - _, self.modified_image = cv2.threshold(gray_image, self.spinBox_threshold_for_to_binary.value(), 255, cv2.THRESH_BINARY) - - self.display_image(self.modified_image, self.graphicsView_2) - - def image_add(self): - if self.modified_image is not None: - self.add_to_history() - options = QFileDialog.Options() - fileName, _ = QFileDialog.getOpenFileName(self, "打开图片", "", "All Files (*);;Image Files (*.jpg *.png)", options=options) - if fileName: - obj_image = cv2.imread(fileName) - - # 获取原始图像的尺寸 - original_shape = self.original_image.shape - original_height, original_width = original_shape[:2] - - # 调整新图像的尺寸与原始图像相同 - resized_obj_image = cv2.resize(obj_image, (original_width, original_height)) - - # 确保通道数匹配,如果不匹配,进行相应调整 - if len(original_shape) == 2 and len(resized_obj_image.shape) == 3: - resized_obj_image = cv2.cvtColor(resized_obj_image, cv2.COLOR_BGR2GRAY) - elif len(original_shape) == 3 and len(resized_obj_image.shape) == 2: - resized_obj_image = cv2.cvtColor(resized_obj_image, cv2.COLOR_GRAY2BGR) - - # 执行图像加法操作 - self.modified_image = cv2.add(self.original_image, resized_obj_image) - - # 显示结果图像 - self.display_image(self.modified_image, self.graphicsView_2) - - def image_subtract(self): - if self.modified_image is not None: - self.add_to_history() - options = QFileDialog.Options() - fileName, _ = QFileDialog.getOpenFileName(self, "打开图片", "", "All Files (*);;Image Files (*.jpg *.png)", options=options) - if fileName: - obj_image = cv2.imread(fileName) - - # 获取原始图像的尺寸 - original_shape = self.original_image.shape - original_height, original_width = original_shape[:2] - - # 调整新图像的尺寸与原始图像相同 - resized_obj_image = cv2.resize(obj_image, (original_width, original_height)) - - # 确保通道数匹配,如果不匹配,进行相应调整 - if len(original_shape) == 2 and len(resized_obj_image.shape) == 3: - resized_obj_image = cv2.cvtColor(resized_obj_image, cv2.COLOR_BGR2GRAY) - elif len(original_shape) == 3 and len(resized_obj_image.shape) == 2: - resized_obj_image = cv2.cvtColor(resized_obj_image, cv2.COLOR_GRAY2BGR) - - # 执行图像加法操作 - self.modified_image = cv2.subtract(self.original_image, resized_obj_image) - - # 显示结果图像 - self.display_image(self.modified_image, self.graphicsView_2) - - def image_multiply(self): - if self.modified_image is not None: - self.add_to_history() - options = QFileDialog.Options() - fileName, _ = QFileDialog.getOpenFileName(self, "打开图片", "", "All Files (*);;Image Files (*.jpg *.png)", options=options) - if fileName: - obj_image = cv2.imread(fileName) - - # 获取原始图像的尺寸 - original_shape = self.original_image.shape - original_height, original_width = original_shape[:2] - - # 调整新图像的尺寸与原始图像相同 - resized_obj_image = cv2.resize(obj_image, (original_width, original_height)) - - # 确保通道数匹配,如果不匹配,进行相应调整 - if len(original_shape) == 2 and len(resized_obj_image.shape) == 3: - resized_obj_image = cv2.cvtColor(resized_obj_image, cv2.COLOR_BGR2GRAY) - elif len(original_shape) == 3 and len(resized_obj_image.shape) == 2: - resized_obj_image = cv2.cvtColor(resized_obj_image, cv2.COLOR_GRAY2BGR) - - # 执行图像加法操作 - self.modified_image = cv2.multiply(self.original_image, resized_obj_image) - - # 显示结果图像 - self.display_image(self.modified_image, self.graphicsView_2) - - def complex_change(self): - if self.modified_image is not None: - self.add_to_history() - - # 图像放缩 - self.modified_image = cv2.resize(self.original_image, (256, 256)) - # 获取图像shape - rows, cols = self.modified_image.shape[: 2] - - ########Begin######## - # 设置图像仿射变化矩阵 - - post1 = np.float32([[50, 50], [200, 50], [50, 200]]) - post2 = np.float32([[10, 100], [200, 50], [100,250]]) - M = cv2.getAffineTransform(post1, post2) - - # 图像仿射变换,及保存 - self.modified_image = cv2.warpAffine(self.modified_image, M, (rows, cols)) - self.display_image(self.modified_image, self.graphicsView_2) - - - def change_size(self): - def resize_image(image, scale): - original_height, original_width = image.shape[:2] - - if scale > 1: - # 截取中心区域 - new_width = int(original_width / scale) - new_height = int(original_height / scale) - start_x = (original_width - new_width) // 2 - start_y = (original_height - new_height) // 2 - cropped_image = image[start_y:start_y + new_height, start_x:start_x + new_width] - resized_image = cv2.resize(cropped_image, (original_width, original_height), interpolation=cv2.INTER_LINEAR) - elif scale < 1: - # 填充白边 - new_width = int(original_width * scale) - new_height = int(original_height * scale) - resized_image = cv2.resize(image, (new_width, new_height), interpolation=cv2.INTER_LINEAR) - - # 创建带有白边的新图像 - padded_image = np.ones((original_height, original_width, 3), dtype=np.uint8) * 255 - start_x = (original_width - new_width) // 2 - start_y = (original_height - new_height) // 2 - padded_image[start_y:start_y + new_height, start_x:start_x + new_width] = resized_image - resized_image = padded_image - else: - resized_image = image.copy() - - return resized_image - - if self.modified_image is not None: - self.add_to_history() - - # Get the factor from the slider value - factor = self.size_controller.value() / 10.0 - - if self.radioButton_bigger.isChecked(): - changed=resize_image(self.modified_image,factor) - else: - changed=resize_image(self.modified_image,1/factor) - - self.display_image(changed, self.graphicsView_2) - - def hough(self): - if self.modified_image is not None: - self.add_to_history() - - self.modified_image = cv2.GaussianBlur(self.modified_image, (3, 3), 0) - edges = cv2.Canny(self.modified_image, 50, 150, apertureSize=3) - - minLineLength = 200 - maxLineGap = 15 - - linesP = cv2.HoughLinesP(edges, 1, np.pi/180, 80, minLineLength, maxLineGap) - self.modified_image = self.modified_image.copy() - for i_P in linesP: - for x1, y1, x2, y2 in i_P: - cv2.line(self.modified_image, (x1, y1), (x2, y2), (0, 255, 0), 3) - self.display_image(self.modified_image, self.graphicsView_2) - - def equalize_histogram(self): - if self.modified_image is not None: - self.add_to_history() - #判断是不是灰度图 - if len(self.modified_image.shape) == 3: - ycrcb_img = cv2.cvtColor(self.modified_image, cv2.COLOR_BGR2YCrCb) - - # 对Y通道进行直方图均衡化 - ycrcb_img[:, :, 0] = cv2.equalizeHist(ycrcb_img[:, :, 0]) - - # 将图像转换回BGR颜色空间 - self.modified_image = cv2.cvtColor(ycrcb_img, cv2.COLOR_YCrCb2BGR) - else: # 是灰度图 - self.modified_image = cv2.equalizeHist(self.modified_image) - self.display_image(self.modified_image, self.graphicsView_2) - - def brightness_change(self): - if self.modified_image is not None: - self.add_to_history() - self.modified_image=cv2.convertScaleAbs(self.modified_image, alpha=1, beta=self.spinBox_threshold_for_brightness_change.value()) - self.display_image(self.modified_image, self.graphicsView_2) - - def histogram_normalization(self): - if self.modified_image is not None: - self.add_to_history() - - options = QFileDialog.Options() - fileName, _ = QFileDialog.getOpenFileName(self, "打开图片", "", "All Files (*);;Image Files (*.jpg *.png)", options=options) - if fileName: - self.modified_image=cv2.imread(fileName) - img=self.original_image.copy() - scr=self.modified_image.copy() - mHist1=[] - mNum1=[] - inhist1=[] - mHist2=[] - mNum2=[] - inhist2=[] - ########Begin######## - # 对原图像进行均衡化 - for i in range(256): - mHist1.append(0) - # 获取原图像像素点的宽度和高度 - row, col = img.shape - for i in range(row): - for j in range(col): - mHist1[img[i, j]] = mHist1[img[i, j]] + 1 # 统计灰度值的个数 - mNum1.append(mHist1[0] / img.size) - for i in range(0, 255): - mNum1.append(mNum1[i] + mHist1[i + 1] / img.size) - for i in range(256): - inhist1.append(round(255 * mNum1[i])) - # 对目标图像进行均衡化 - for i in range(256): - mHist2.append(0) - rows, cols = scr.shape # 获取目标图像像素点的宽度和高度 - for i in range(rows): - for j in range(cols): - mHist2[scr[i, j]] = mHist2[scr[i, j]] + 1 # 统计灰度值的个数 - mNum2.append(mHist2[0] / scr.size) - for i in range(0, 255): - mNum2.append(mNum2[i] + mHist2[i + 1] / scr.size) - for i in range(256): - inhist2.append(round(255 * mNum2[i])) - # 进行规定化 - # 用于放入规定化后的图片像素 - g = [] - for i in range(256): - a = inhist1[i] - flag = True - for j in range(256): - if inhist2[j] == a: - g.append(j) - flag = False - break - if flag == True: - minp = 255 - for j in range(256): - b = abs(inhist2[j] - a) - if b < minp: - minp = b - jmin = j - g.append(jmin) - for i in range(row): - for j in range(col): - img[i, j] = g[img[i, j]] - self.modified_image=img - self.display_image(self.modified_image, self.graphicsView_2) - - - - def invert_colors(self): - if self.modified_image is not None: - self.add_to_history() - self.modified_image = cv2.bitwise_not(self.modified_image) - self.display_image(self.modified_image, self.graphicsView_2) - - def display_image(self, image, graphicsView): - if len(image.shape) == 2: - height, width = image.shape - bytesPerLine = width - qImg = QImage(image.data, width, height, bytesPerLine, QImage.Format_Grayscale8) - else: - height, width, channel = image.shape - bytesPerLine = 3 * width - qImg = QImage(image.data, width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped() - pixmap = QPixmap.fromImage(qImg) - scene = QGraphicsScene() - scene.addItem(QGraphicsPixmapItem(pixmap)) - graphicsView.setScene(scene) - graphicsView.fitInView(scene.itemsBoundingRect(), QtCore.Qt.KeepAspectRatio) - - def mean_filter(self): - if self.modified_image is not None: - self.add_to_history() - kernel=self.spinBox_kernel_for_mean_filter.value() - self.modified_image = cv2.blur(self.modified_image, (kernel, kernel)) - self.display_image(self.modified_image, self.graphicsView_2) - - def gaussian_filter(self): - if self.modified_image is not None: - self.add_to_history() - kernel=self.spinBox_kernel_for_gaussian_filter.value() - self.modified_image = cv2.GaussianBlur(self.modified_image, (kernel,kernel), 0) - self.display_image(self.modified_image, self.graphicsView_2) - - def median_filter(self): - if self.modified_image is not None: - self.add_to_history() - kernel=self.spinBox_kernel_for_median_filter.value() - self.modified_image = cv2.medianBlur(self.modified_image, kernel) - self.display_image(self.modified_image, self.graphicsView_2) - - def low_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - kernel = np.array([[-1, -1, -1], - [-1, 8, -1], - [-1, -1, -1]]) - - # 使用 cv2.filter2D() 进行高通滤波 - self.modified_image = cv2.filter2D(self.modified_image, -1, kernel) - self.display_image(self.modified_image, self.graphicsView_2) - - def high_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - self.modified_image= cv2.blur(self.modified_image, (5, 5)) - self.display_image(self.modified_image, self.graphicsView_2) - - def band_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - # 将图像转换为灰度图像 - gray_image = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) if len(self.original_image.shape) == 3 else self.original_image - rows, cols = gray_image.shape - crow, ccol = rows // 2, cols // 2 - - dft = cv2.dft(np.float32(gray_image), flags=cv2.DFT_COMPLEX_OUTPUT) - dft_shift = np.fft.fftshift(dft) - - low_thresh=self.spinBox_min_for_band_pass_filter.value() - high_thresh=self.spinBox_max_for_band_pass_filter.value() - - mask = np.zeros((rows, cols, 2), np.float32) - for u in range(rows): - for v in range(cols): - d = np.sqrt((u - crow)**2 + (v - ccol)**2) - if low_thresh < d < high_thresh: - mask[u, v] = 1 - - fshift = dft_shift * mask - f_ishift = np.fft.ifftshift(fshift) - img_back = cv2.idft(f_ishift) - self.modified_image = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1]) - - self.display_image(self.modified_image, self.graphicsView_2) - - def band_stop_filter(self): - if self.modified_image is not None: - self.add_to_history() - # 将图像转换为灰度图像 - gray_image = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) if len(self.original_image.shape) == 3 else self.original_image - rows, cols = gray_image.shape - crow, ccol = rows // 2, cols // 2 - - dft = cv2.dft(np.float32(gray_image), flags=cv2.DFT_COMPLEX_OUTPUT) - dft_shift = np.fft.fftshift(dft) - - low_thresh=self.spinBox_min_for_band_stop_filter.value() - high_thresh=self.spinBox_max_for_band_stop_filter.value() - - mask = np.ones((rows, cols, 2), np.float32) - for u in range(rows): - for v in range(cols): - d = np.sqrt((u - crow)**2 + (v - ccol)**2) - if low_thresh < d < high_thresh: - mask[u, v] = 0 - - fshift = dft_shift * mask - f_ishift = np.fft.ifftshift(fshift) - img_back = cv2.idft(f_ishift) - self.modified_image = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1]) - - self.display_image(self.modified_image, self.graphicsView_2) - - def add_gaussian_noise(self): - if self.modified_image is not None: - self.add_to_history() - row, col, ch = self.modified_image.shape - mean = self.doubleSpinBox_mean_for_add_gaussian_noise.value() - sigma = self.doubleSpinBox_sigma_for_add_gaussian_noise.value() - gauss = np.random.normal(mean, sigma, (row, col, ch)) - gauss = gauss.reshape(row, col, ch) - noisy = self.modified_image + gauss * 255 - self.modified_image = np.clip(noisy, 0, 255).astype(np.uint8) - self.display_image(self.modified_image, self.graphicsView_2) - - def add_poisson_noise(self): - if self.modified_image is not None: - self.add_to_history() - vals = len(np.unique(self.modified_image)) - vals = 2 ** np.ceil(np.log2(vals)) - noisy = np.random.poisson(self.modified_image * vals) / float(vals) - self.modified_image = np.clip(noisy, 0, 255).astype(np.uint8) - self.display_image(self.modified_image, self.graphicsView_2) - - def add_salt_and_pepper_noise(self): - if self.modified_image is not None: - self.add_to_history() - noisy_img = self.modified_image.copy() - total_pixels = self.modified_image.size // self.modified_image.shape[2] # 计算总像素数 - num_noise_pixels = int(total_pixels * self.doubleSpinBox_occupation_for_add_salt_and_pepper_noise.value()) # 计算噪声像素数 - - if self.radioButton_salt_and_pepper_for_add_salt_and_pepper_noise.isChecked(): - # 随机分布椒盐噪声 - for _ in range(num_noise_pixels): - x = np.random.randint(0, self.modified_image.shape[0]) - y = np.random.randint(0, self.modified_image.shape[1]) - if np.random.randint(2) == 0: - noisy_img[x, y] = [0, 0, 0] # 椒噪声 - else: - noisy_img[x, y] = [255, 255, 255] # 盐噪声 - elif self.radioButton_salt_for_add_salt_and_pepper_noise.isChecked(): - # 全盐噪声 - for _ in range(num_noise_pixels): - x = np.random.randint(0, self.modified_image.shape[0]) - y = np.random.randint(0, self.modified_image.shape[1]) - noisy_img[x, y] = [255, 255, 255] # 盐噪声 - elif self.radioButton_pepper_for_add_salt_and_pepper_noise.isChecked(): - # 全椒噪声 - for _ in range(num_noise_pixels): - x = np.random.randint(0, self.modified_image.shape[0]) - y = np.random.randint(0, self.modified_image.shape[1]) - noisy_img[x, y] = [0, 0, 0] # 椒噪声 - self.modified_image=noisy_img - self.display_image(self.modified_image, self.graphicsView_2) - - - def apply_erosion(self): - if self.modified_image is not None: - self.add_to_history() - kernel = np.ones((5,5), np.uint8) - self.modified_image = cv2.erode(self.modified_image, kernel, iterations = 1) - self.display_image(self.modified_image, self.graphicsView_2) - - def apply_dilation(self): - if self.modified_image is not None: - self.add_to_history() - kernel = np.ones((5,5), np.uint8) - self.modified_image = cv2.dilate(self.modified_image, kernel, iterations = 1) - self.display_image(self.modified_image, self.graphicsView_2) - - def log_edge_detection(self): - if self.modified_image is not None: - self.add_to_history() - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - blurred = cv2.GaussianBlur(gray, (3, 3), 0) - log = cv2.Laplacian(blurred, cv2.CV_64F) - self.modified_image = cv2.convertScaleAbs(log) - self.display_image(self.modified_image, self.graphicsView_2) - - def roberts_edge_detection(self): - if self.modified_image is not None: - self.add_to_history() - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - kernelx = np.array([[1, 0], [0, -1]], dtype=int) - kernely = np.array([[0, 1], [-1, 0]], dtype=int) - x = cv2.filter2D(gray, cv2.CV_16S, kernelx) - y = cv2.filter2D(gray, cv2.CV_16S, kernely) - absX = cv2.convertScaleAbs(x) - absY = cv2.convertScaleAbs(y) - self.modified_image = cv2.addWeighted(absX, 0.5, absY, 0.5, 0) - self.display_image(self.modified_image, self.graphicsView_2) - - def sobel_edge_detection(self): - if self.modified_image is not None: - self.add_to_history() - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - grad_x = cv2.Sobel(gray, cv2.CV_16S, 1, 0) - grad_y = cv2.Sobel(gray, cv2.CV_16S, 0, 1) - abs_grad_x = cv2.convertScaleAbs(grad_x) - abs_grad_y = cv2.convertScaleAbs(grad_y) - self.modified_image = cv2.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0) - self.display_image(self.modified_image, self.graphicsView_2) - - def laplacian_edge_detection(self): - if self.modified_image is not None: - self.add_to_history() - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - laplacian = cv2.Laplacian(gray, cv2.CV_16S) - self.modified_image = cv2.convertScaleAbs(laplacian) - self.display_image(self.modified_image, self.graphicsView_2) - - def canny_edge_detection(self): - if self.modified_image is not None: - self.add_to_history() - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - self.modified_image = cv2.Canny(gray, 100, 200) - self.display_image(self.modified_image, self.graphicsView_2) - - def ideal_high_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - rows, cols = gray.shape - crow, ccol = rows // 2, cols // 2 - - threshold=self.spinBox_threshold_for_ideal_high_pass_filter.value() - - if self.radioButton_circle_for_ideal_high_pass_filter.isChecked(): - shape = "圆形" - elif self.radioButton_rectangle_for_ideal_high_pass_filter.isChecked(): - shape = "矩形" - else: - shape = "圆形" - - mask = np.ones((rows, cols), np.uint8) - if shape == "圆形": - for i in range(rows): - for j in range(cols): - dist = np.sqrt((i - crow) ** 2 + (j - ccol) ** 2) - if dist <= threshold: - mask[i, j] = 0 - elif shape == "矩形": - mask[int(crow - threshold):int(crow + threshold), int(ccol - threshold):int(ccol + threshold)] = 0 - - fshift = np.fft.fftshift(np.fft.fft2(gray)) - fshift = fshift * mask - - img_back = np.fft.ifft2(np.fft.ifftshift(fshift)) - img_back = np.abs(img_back) - - self.modified_image = np.uint8(img_back) - self.display_image(self.modified_image, self.graphicsView_2) - - def butterworth_high_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - rows, cols = gray.shape - crow, ccol = rows // 2, cols // 2 - - # 设置阈值和阶数 - threshold=self.spinBox_threshold_for_butterworth_high_pass_filter.value() - - order=self.spinBox_order_for_butterworth_high_pass_filter.value() - - mask = np.zeros((rows, cols), np.float32) - for i in range(rows): - for j in range(cols): - dist = np.sqrt((i - crow) ** 2 + (j - ccol) ** 2) - mask[i, j] = 1 / (1 + (threshold / dist) ** (2 * order)) - - fshift = np.fft.fftshift(np.fft.fft2(gray)) - fshift = fshift * mask - - img_back = np.fft.ifft2(np.fft.ifftshift(fshift)) - img_back = np.abs(img_back) - - self.modified_image = np.uint8(img_back) - self.display_image(self.modified_image, self.graphicsView_2) - - def gaussian_high_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - rows, cols = gray.shape - crow, ccol = rows // 2, cols // 2 - - # 设置标准差 - threshold=self.spinBox_sigma_for_gaussian_high_pass_filter.value() - - mask = np.zeros((rows, cols), np.float32) - for i in range(rows): - for j in range(cols): - dist = np.sqrt((i - crow) ** 2 + (j - ccol) ** 2) - mask[i, j] = 1 - np.exp(-dist ** 2 / (2 * (threshold ** 2))) - - fshift = np.fft.fftshift(np.fft.fft2(gray)) - fshift = fshift * mask - - img_back = np.fft.ifft2(np.fft.ifftshift(fshift)) - img_back = np.abs(img_back) - - self.modified_image = np.uint8(img_back) - self.display_image(self.modified_image, self.graphicsView_2) - - def ideal_low_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - rows, cols = gray.shape - crow, ccol = rows // 2, cols // 2 - - threshold=self.spinBox_threshold_for_ideal_low_pass_filter.value() - - if self.radioButton_circle_for_ideal_low_pass_filter.isChecked(): - shape = "圆形" - - elif self.radioButton_rectangle_for_ideal_low_pass_filter.isChecked(): - shape = "矩形" - else: - shape = "圆形" - - mask = np.zeros((rows, cols), np.uint8) - if shape == "圆形": - for i in range(rows): - for j in range(cols): - dist = np.sqrt((i - crow) ** 2 + (j - ccol) ** 2) - if dist <= threshold: - mask[i, j] = 1 - elif shape == "矩形": - mask[int(crow - threshold):int(crow + threshold), int(ccol - threshold):int(ccol + threshold)] = 1 - - fshift = np.fft.fftshift(np.fft.fft2(gray)) - fshift = fshift * mask - - img_back = np.fft.ifft2(np.fft.ifftshift(fshift)) - img_back = np.abs(img_back) - - self.modified_image = np.uint8(img_back) - self.display_image(self.modified_image, self.graphicsView_2) - - def butterworth_low_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - rows, cols = gray.shape - crow, ccol = rows // 2, cols // 2 - - threshold=self.spinBox_threshold_for_butterworth_low_pass_filter.value() - - order=self.spinBox_order_for_butterworth_low_pass_filter.value() - - mask = np.zeros((rows, cols)) - for i in range(rows): - for j in range(cols): - distance = np.sqrt((i - crow) ** 2 + (j - ccol) ** 2) - mask[i, j] = 1 / (1 + (distance / threshold) ** (2 * order)) - - fshift = np.fft.fftshift(np.fft.fft2(gray)) - fshift = fshift * mask - - img_back = np.fft.ifft2(np.fft.ifftshift(fshift)) - img_back = np.abs(img_back) - - self.modified_image = np.uint8(img_back) - self.display_image(self.modified_image, self.graphicsView_2) - - def gaussian_low_pass_filter(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.original_image, cv2.COLOR_BGR2GRAY) - rows, cols = gray.shape - crow, ccol = rows // 2, cols // 2 - - sigma=self.spinBox_sigma_for_gaussian_low_pass_filter.value() - - mask = np.zeros((rows, cols)) - for i in range(rows): - for j in range(cols): - distance = np.sqrt((i - crow) ** 2 + (j - ccol) ** 2) - mask[i, j] = np.exp(-(distance ** 2) / (2 * (sigma ** 2))) - - fshift = np.fft.fftshift(np.fft.fft2(gray)) - fshift = fshift * mask - - img_back = np.fft.ifft2(np.fft.ifftshift(fshift)) - img_back = np.abs(img_back) - - self.modified_image = np.uint8(img_back) - self.display_image(self.modified_image, self.graphicsView_2) - - - - - def apply_roberts(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.modified_image, cv2.COLOR_BGR2GRAY) - kernelx = np.array([[1, 0], [0, -1]], dtype=int) - kernely = np.array([[0, 1], [-1, 0]], dtype=int) - x = cv2.filter2D(gray, cv2.CV_16S, kernelx) - y = cv2.filter2D(gray, cv2.CV_16S, kernely) - absX = cv2.convertScaleAbs(x) - absY = cv2.convertScaleAbs(y) - roberts = cv2.addWeighted(absX, 0.5, absY, 0.5, 0) - self.modified_image = cv2.cvtColor(roberts, cv2.COLOR_GRAY2BGR) - self.display_image(self.modified_image, self.graphicsView_2) - - def apply_sobel(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.modified_image, cv2.COLOR_BGR2GRAY) - x = cv2.Sobel(gray, cv2.CV_16S, 1, 0) - y = cv2.Sobel(gray, cv2.CV_16S, 0, 1) - absX = cv2.convertScaleAbs(x) - absY = cv2.convertScaleAbs(y) - sobel = cv2.addWeighted(absX, 0.5, absY, 0.5, 0) - self.modified_image = cv2.cvtColor(sobel, cv2.COLOR_GRAY2BGR) - self.display_image(self.modified_image, self.graphicsView_2) - - def apply_prewitt(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.modified_image, cv2.COLOR_BGR2GRAY) - kernelx = np.array([[1, 0, -1], [1, 0, -1], [1, 0, -1]], dtype=int) - kernely = np.array([[1, 1, 1], [0, 0, 0], [-1, -1, -1]], dtype=int) - x = cv2.filter2D(gray, cv2.CV_16S, kernelx) - y = cv2.filter2D(gray, cv2.CV_16S, kernely) - absX = cv2.convertScaleAbs(x) - absY = cv2.convertScaleAbs(y) - prewitt = cv2.addWeighted(absX, 0.5, absY, 0.5, 0) - self.modified_image = cv2.cvtColor(prewitt, cv2.COLOR_GRAY2BGR) - self.display_image(self.modified_image, self.graphicsView_2) - - def apply_laplacian(self): - if self.modified_image is not None: - self.add_to_history() - - gray = cv2.cvtColor(self.modified_image, cv2.COLOR_BGR2GRAY) - laplacian = cv2.Laplacian(gray, cv2.CV_16S) - laplacian = cv2.convertScaleAbs(laplacian) - self.modified_image = cv2.cvtColor(laplacian, cv2.COLOR_GRAY2BGR) - self.display_image(self.modified_image, self.graphicsView_2) - - def vessel_division(self): - if self.modified_image is not None: - self.add_to_history() - - self.modified_image=vessel_detection.vessel_division(self.original_image) - self.display_image(self.modified_image, self.graphicsView_2) - - def repair_image(self): - if self.modified_image is not None: - self.add_to_history() - - # 读取图片 - img = self.original_image - # 对图片进行噪声去除 - blurred = cv2.medianBlur(img, 5) - noise = cv2.fastNlMeansDenoisingColored(blurred, None, 10, 10, 7, 21) - # 对图片进行细节修复 - detail_enhancer = cv2.detailEnhance(noise) - detail_enhancer = detail_enhancer.astype(np.uint8) - self.modified_image=detail_enhancer - self.display_image(self.modified_image, self.graphicsView_2) - - def compress_image(self): # 通常你只需要修改mb大小 - if self.modified_image is not None: - self.add_to_history() - - # 如果输入图像是 numpy 数组,将其转换为 PIL 图像 - if isinstance(self.original_image, np.ndarray): - self.modified_image = Image.fromarray(self.original_image) - # 创建一个BytesIO对象,用于存储压缩后的图像数据 - img_bytes = io.BytesIO() - - # 初始压缩质量 - quality = 95 - target_size_kb=self.spinBox_size_to_transform.value() - quality_step=5 - # 获取当前文件大小 - def get_size_kb(byte_data): - return len(byte_data) / 1024 - - while quality > 0: - # 清空BytesIO对象 - img_bytes.seek(0) - img_bytes.truncate() - - # 压缩图像 - self.modified_image.save(img_bytes, format='JPEG', quality=quality) - - # 获取压缩后图像的大小 - current_size_kb = get_size_kb(img_bytes.getvalue()) - - # 如果压缩后的图像大小在目标范围内,则返回图像对象 - if current_size_kb <= target_size_kb: - img_bytes.seek(0) - self.modified_image = Image.open(img_bytes) - self.modified_image =np.array(self.modified_image) - self.display_image(self.modified_image, self.graphicsView_2) - return - - # 否则,降低质量并继续压缩 - quality -= quality_step - - # 如果无法压缩到目标大小,返回None并提示 - print("无法压缩到目标大小,请检查目标大小是否合理。") - return None - -if __name__ == '__main__': - def scale_ui(widget, scale_factor): - widget.resize(widget.size() * scale_factor) - for child in widget.findChildren(QtWidgets.QWidget): - child.resize(child.size() * scale_factor) - child.move(child.pos() * scale_factor) - - app = QtWidgets.QApplication(sys.argv) - window=MainWindow() - - scale_factor = 1.8 - scale_ui(window, scale_factor) - - window.show() - sys.exit(app.exec_()) \ No newline at end of file