You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

957 lines
44 KiB

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 mainwindow_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.tobytes(), width, height, bytesPerLine, QImage.Format_Grayscale8)
else:
height, width, channel = image.shape
bytesPerLine = 3 * width
qImg = QImage(image.data.tobytes(), 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_())