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_())