parent
							
								
									49fb1b027c
								
							
						
					
					
						commit
						c1441c6fe9
					
				| @ -0,0 +1,342 @@ | ||||
| import tkinter as tk | ||||
| from tkinter import filedialog, messagebox | ||||
| from tkinter import Toplevel | ||||
| from PIL import Image, ImageTk | ||||
| import numpy as np | ||||
| import cv2 | ||||
| import os | ||||
| 
 | ||||
| img_path = ""  # 全局变量,用于存储图像路径 | ||||
| src = None  # 全局变量,用于存储已选择的图像 | ||||
| img_label = None  # 全局变量,用于存储显示选择的图片的标签 | ||||
| edge = None | ||||
| 
 | ||||
| FreqsmoWin = None | ||||
| AirsmoWin  = None | ||||
| 
 | ||||
| def select_image(root): | ||||
|     global img_path, src, img_label, edge | ||||
| 
 | ||||
|     img_path = filedialog.askopenfilename(filetypes=[("Image files", "*.jpg;*.png;*.jpeg;*.bmp")]) | ||||
|     if img_path: | ||||
|         # 确保路径中的反斜杠正确处理,并使用 UTF-8 编码处理中文路径 | ||||
|         img_path_fixed = os.path.normpath(img_path) | ||||
| 
 | ||||
|         # 图像输入 | ||||
|         src_temp = cv2.imdecode(np.fromfile(img_path_fixed, dtype=np.uint8), cv2.IMREAD_UNCHANGED) | ||||
|         if src_temp is None: | ||||
|             messagebox.showerror("错误", "无法读取图片,请选择有效的图片路径") | ||||
|             return | ||||
|         src = cv2.cvtColor(src_temp, cv2.COLOR_BGR2RGB) | ||||
| 
 | ||||
|         # 检查 img_label 是否存在且有效 | ||||
|         if img_label is None or not img_label.winfo_exists(): | ||||
|             img_label = tk.Label(root) | ||||
|             img_label.pack(side=tk.TOP, pady=10) | ||||
| 
 | ||||
|         img = Image.open(img_path) | ||||
|         img.thumbnail((160, 160)) | ||||
|         img_tk = ImageTk.PhotoImage(img) | ||||
|         img_label.configure(image=img_tk) | ||||
|         img_label.image = img_tk | ||||
| 
 | ||||
|         # 定义 edge 变量为 PIL.Image 对象,以便稍后保存 | ||||
|         edge = Image.fromarray(src) | ||||
|     else: | ||||
|         messagebox.showerror("错误", "没有选择图片路径") | ||||
| 
 | ||||
| def show_selected_image(root): | ||||
|     global img_label | ||||
|     img_label = tk.Label(root) | ||||
|     img_label.pack(side=tk.TOP, pady=10) | ||||
|     img = Image.open(img_path) | ||||
|     img.thumbnail((160, 160)) | ||||
|     img_tk = ImageTk.PhotoImage(img) | ||||
|     img_label.configure(image=img_tk) | ||||
|     img_label.image = img_tk | ||||
| 
 | ||||
| def changeSize(event, img, LabelPic): | ||||
|     img_aspect = img.shape[1] / img.shape[0] | ||||
|     new_aspect = event.width / event.height | ||||
| 
 | ||||
|     if new_aspect > img_aspect: | ||||
|         new_width = int(event.height * img_aspect) | ||||
|         new_height = event.height | ||||
|     else: | ||||
|         new_width = event.width | ||||
|         new_height = int(event.width / img_aspect) | ||||
| 
 | ||||
|     resized_image = cv2.resize(img, (new_width, new_height)) | ||||
|     image1 = ImageTk.PhotoImage(Image.fromarray(resized_image)) | ||||
|     LabelPic.image = image1 | ||||
|     LabelPic['image'] = image1 | ||||
| 
 | ||||
| def savefile(): | ||||
|     global edge | ||||
| 
 | ||||
|     filename = filedialog.asksaveasfilename(defaultextension=".jpg", filetypes=[("JPEG files", "*.jpg"), ("PNG files", "*.png"), ("BMP files", "*.bmp")]) | ||||
|     if not filename: | ||||
|         return | ||||
|     # 确保 edge 变量已定义 | ||||
|     if edge is not None: | ||||
|         try: | ||||
|             edge.save(filename) | ||||
|             messagebox.showinfo("保存成功", "图片保存成功!") | ||||
|         except Exception as e: | ||||
|             messagebox.showerror("保存失败", f"无法保存图片: {e}") | ||||
|     else: | ||||
|         messagebox.showerror("保存失败", "没有图像可保存") | ||||
| 
 | ||||
| #频域平滑 | ||||
| def freq_smo(root): | ||||
|     global src, FreqsmoWin, edge | ||||
| 
 | ||||
|     # 判断是否已经选取图片 | ||||
|     if src is None: | ||||
|         messagebox.showerror("错误", "没有选择图片!") | ||||
|         return | ||||
| 
 | ||||
|     def Ideal_LowPassFilter(rows, cols, crow, ccol, D0=20): | ||||
|         # 创建一个与输入图像大小相同的空白图像 | ||||
|         Ideal_LowPass = np.zeros((rows, cols), dtype=np.uint8) | ||||
| 
 | ||||
|         # 创建理想低通滤波器 | ||||
|         for i in range(rows): | ||||
|             for j in range(cols): | ||||
|                 x = i - crow | ||||
|                 y = j - ccol | ||||
|                 D = np.sqrt(x**2 + y**2) | ||||
|                 if D <= D0: | ||||
|                     Ideal_LowPass[i, j] = 255 | ||||
| 
 | ||||
|         # 应用滤波器到频域表示 | ||||
|         mask = Ideal_LowPass[:, :, np.newaxis] | ||||
|         fshift = dft_shift * mask | ||||
| 
 | ||||
|         # 逆傅里叶变换以获得平滑后的图像 | ||||
|         f_ishift = np.fft.ifftshift(fshift) | ||||
|         img_back = cv2.idft(f_ishift) | ||||
|         img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1]) | ||||
| 
 | ||||
|         # 归一化图像到0-255 | ||||
|         cv2.normalize(img_back, img_back, 0, 255, cv2.NORM_MINMAX) | ||||
|         img_back = np.uint8(img_back) | ||||
| 
 | ||||
|         return img_back | ||||
| 
 | ||||
|     def ButterWorth_LowPassFilter(rows, cols, crow, ccol, D0=20, n=2): | ||||
|         # 创建一个与输入图像大小相同的空白图像 | ||||
|         ButterWorth_LowPass = np.zeros((rows, cols), dtype=np.uint8) | ||||
| 
 | ||||
|         # 创建巴特沃斯低通滤波器 | ||||
|         for i in range(rows): | ||||
|             for j in range(cols): | ||||
|                 x = i - crow | ||||
|                 y = j - ccol | ||||
|                 D = np.sqrt(x ** 2 + y ** 2) | ||||
|                 ButterWorth_LowPass[i, j] = 255 / (1 + (D / D0) ** (2 * n)) | ||||
| 
 | ||||
|         # 应用滤波器到频域表示 | ||||
|         mask = ButterWorth_LowPass[:, :, np.newaxis] | ||||
|         fshift = dft_shift * mask | ||||
| 
 | ||||
|         # 逆傅里叶变换以获得平滑后的图像 | ||||
|         f_ishift = np.fft.ifftshift(fshift) | ||||
|         img_back = cv2.idft(f_ishift) | ||||
|         img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1]) | ||||
| 
 | ||||
|         # 归一化图像到0-255 | ||||
|         cv2.normalize(img_back, img_back, 0, 255, cv2.NORM_MINMAX) | ||||
|         img_back = np.uint8(img_back) | ||||
| 
 | ||||
|         return img_back | ||||
| 
 | ||||
|     def Gauss_LowPassFilter(rows, cols, crow, ccol, D0=20): | ||||
|         # 创建一个与输入图像大小相同的空白图像 | ||||
|         Gauss_LowPass = np.zeros((rows, cols), dtype=np.uint8) | ||||
| 
 | ||||
|         # 创建高斯低通滤波器 | ||||
|         for i in range(rows): | ||||
|             for j in range(cols): | ||||
|                 x = i - crow | ||||
|                 y = j - ccol | ||||
|                 D = np.sqrt(x ** 2 + y ** 2) | ||||
|                 Gauss_LowPass[i, j] = 255 * np.exp(-0.5 * (D ** 2) / (D0 ** 2)) | ||||
| 
 | ||||
|         # 应用滤波器到频域表示 | ||||
|         mask = Gauss_LowPass[:, :, np.newaxis] | ||||
|         fshift = dft_shift * mask | ||||
| 
 | ||||
|         # 逆傅里叶变换以获得平滑后的图像 | ||||
|         f_ishift = np.fft.ifftshift(fshift) | ||||
|         img_back = cv2.idft(f_ishift) | ||||
|         img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1]) | ||||
| 
 | ||||
|         # 归一化图像到0-255 | ||||
|         cv2.normalize(img_back, img_back, 0, 255, cv2.NORM_MINMAX) | ||||
|         img_back = np.uint8(img_back) | ||||
| 
 | ||||
|         return img_back | ||||
| 
 | ||||
|     # 读取灰度图像 | ||||
|     im = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) | ||||
| 
 | ||||
|     # 获取图像的频域表示 | ||||
|     dft = cv2.dft(np.float32(im), flags=cv2.DFT_COMPLEX_OUTPUT) | ||||
|     dft_shift = np.fft.fftshift(dft) | ||||
| 
 | ||||
|     # 获取图像的尺寸 | ||||
|     rows, cols = im.shape | ||||
|     crow, ccol = rows // 2, cols // 2 | ||||
| 
 | ||||
|     # 理想低通滤波器 | ||||
|     Ideal_LowPass = Ideal_LowPassFilter(rows, cols, crow, ccol) | ||||
|     # 巴特沃斯低通滤波器 | ||||
|     ButterWorth_LowPass = ButterWorth_LowPassFilter(rows, cols, crow, ccol) | ||||
|     # 高斯低通滤波器 | ||||
|     Gauss_LowPass = Gauss_LowPassFilter(rows, cols, crow, ccol) | ||||
| 
 | ||||
|     combined = np.hstack((Ideal_LowPass, ButterWorth_LowPass, Gauss_LowPass)) | ||||
|     # 更新 edge 变量 | ||||
|     edge = Image.fromarray(combined) | ||||
| 
 | ||||
|     # 创建Toplevel窗口 | ||||
|     try: | ||||
|         FreqsmoWin.destroy() | ||||
|     except Exception as e: | ||||
|         print("NVM") | ||||
|     finally: | ||||
|         FreqsmoWin = Toplevel() | ||||
|         FreqsmoWin.attributes('-topmost', True) | ||||
|     FreqsmoWin.geometry("720x300") | ||||
|     FreqsmoWin.resizable(True, True)  # 可缩放 | ||||
|     FreqsmoWin.title("频域平滑结果") | ||||
| 
 | ||||
|     # 显示图像 | ||||
|     LabelPic = tk.Label(FreqsmoWin, text="IMG", width=720, height=240) | ||||
|     image = ImageTk.PhotoImage(Image.fromarray(combined)) | ||||
|     LabelPic.image = image | ||||
|     LabelPic['image'] = image | ||||
| 
 | ||||
|     LabelPic.bind('<Configure>', lambda event: changeSize(event, combined, LabelPic)) | ||||
|     LabelPic.pack(fill=tk.BOTH, expand=tk.YES) | ||||
| 
 | ||||
|     # 添加保存按钮 | ||||
|     btn_save = tk.Button(FreqsmoWin, text="保存", bg='#add8e6', fg='black', font=('Helvetica', 14), width=20, | ||||
|                          command=savefile) | ||||
|     btn_save.pack(pady=10) | ||||
| 
 | ||||
|     return | ||||
| 
 | ||||
| #空域平滑 | ||||
| def air_smo(root): | ||||
|     global src, AirsmoWin, edge | ||||
| 
 | ||||
|     # 判断是否已经选取图片 | ||||
|     if src is None: | ||||
|         messagebox.showerror("错误", "没有选择图片!") | ||||
|         return | ||||
| 
 | ||||
|     def mean_filter(image, height, width): | ||||
|         # 创建空白图像以存储滤波结果 | ||||
|         filtered_image = np.zeros((height - 2, width - 2), dtype=np.uint8) | ||||
| 
 | ||||
|         # 执行3x3均值滤波 | ||||
|         for i in range(1, height - 1): | ||||
|             for j in range(1, width - 1): | ||||
|                 tmp = (int(image[i - 1, j - 1]) + int(image[i - 1, j]) + int(image[i - 1, j + 1]) + | ||||
|                        int(image[i, j - 1]) + int(image[i, j]) + int(image[i, j + 1]) + | ||||
|                        int(image[i + 1, j - 1]) + int(image[i + 1, j]) + int(image[i + 1, j + 1])) // 9 | ||||
|                 filtered_image[i - 1, j - 1] = tmp | ||||
| 
 | ||||
|         return filtered_image | ||||
| 
 | ||||
|     def median_filter(image, height, width): | ||||
|         # 创建空白图像以存储滤波结果 | ||||
|         filtered_image = np.zeros((height - 2, width - 2), dtype=np.uint8) | ||||
| 
 | ||||
|         # 执行3x3中值滤波 | ||||
|         for i in range(1, height - 1): | ||||
|             for j in range(1, width - 1): | ||||
|                 # 取3x3邻域 | ||||
|                 region = [ | ||||
|                     image[i - 1, j - 1], image[i - 1, j], image[i - 1, j + 1], | ||||
|                     image[i, j - 1], image[i, j], image[i, j + 1], | ||||
|                     image[i + 1, j - 1], image[i + 1, j], image[i + 1, j + 1] | ||||
|                 ] | ||||
|                 # 计算中值 | ||||
|                 filtered_image[i - 1, j - 1] = np.median(region) | ||||
| 
 | ||||
|         return filtered_image | ||||
| 
 | ||||
|     def med_filter_5x5(image, height, width): | ||||
|         # 创建空白图像以存储滤波结果 | ||||
|         filtered_image = np.zeros((height - 4, width - 4), dtype=np.uint8) | ||||
| 
 | ||||
|         # 执行5x5中值滤波 | ||||
|         for i in range(2, height - 2): | ||||
|             for j in range(2, width - 2): | ||||
|                 # 取5x5邻域的所有值 | ||||
|                 neighbors = [ | ||||
|                     image[i - 2, j - 2], image[i - 2, j - 1], image[i - 2, j], image[i - 2, j + 1], image[i - 2, j + 2], | ||||
|                     image[i - 1, j - 2], image[i - 1, j - 1], image[i - 1, j], image[i - 1, j + 1], image[i - 1, j + 2], | ||||
|                     image[i, j - 2], image[i, j - 1], image[i, j], image[i, j + 1], image[i, j + 2], | ||||
|                     image[i + 1, j - 2], image[i + 1, j - 1], image[i + 1, j], image[i + 1, j + 1], image[i + 1, j + 2], | ||||
|                     image[i + 2, j - 2], image[i + 2, j - 1], image[i + 2, j], image[i + 2, j + 1], image[i + 2, j + 2] | ||||
|                 ] | ||||
|                 # 计算中值 | ||||
|                 filtered_image[i - 2, j - 2] = np.median(neighbors) | ||||
| 
 | ||||
|         return filtered_image | ||||
| 
 | ||||
|     # 读取灰度图像 | ||||
|     im = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) | ||||
| 
 | ||||
|     # 获取图像尺寸 | ||||
|     height, width = im.shape | ||||
| 
 | ||||
|     # 邻域平均 | ||||
|     mean = mean_filter(im, height, width) | ||||
|     # 中值滤波3x3 | ||||
|     median = median_filter(im, height, width) | ||||
|     # 中值滤波5x5 | ||||
|     med = med_filter_5x5(im, height, width) | ||||
| 
 | ||||
|     min_height = min(mean.shape[0], median.shape[0], med.shape[0]) | ||||
|     min_width = min(mean.shape[1], median.shape[1], med.shape[1]) | ||||
| 
 | ||||
|     mean_cropped = mean[:min_height, :min_width] | ||||
|     median_cropped = median[:min_height, :min_width] | ||||
|     med_cropped = med[:min_height, :min_width] | ||||
| 
 | ||||
|     combined = np.hstack((mean_cropped, median_cropped, med_cropped)) | ||||
|     # 更新 edge 变量 | ||||
|     edge = Image.fromarray(combined) | ||||
| 
 | ||||
|     # 创建Toplevel窗口 | ||||
|     try: | ||||
|         AirsmoWin.destroy() | ||||
|     except Exception as e: | ||||
|         print("NVM") | ||||
|     finally: | ||||
|         AirsmoWin = Toplevel() | ||||
|         AirsmoWin.attributes('-topmost', True) | ||||
|     AirsmoWin.geometry("720x300") | ||||
|     AirsmoWin.resizable(True, True)  # 可缩放 | ||||
|     AirsmoWin.title("空域平滑结果") | ||||
| 
 | ||||
|     # 显示图像 | ||||
|     LabelPic = tk.Label(AirsmoWin, text="IMG", width=720, height=240) | ||||
|     image = ImageTk.PhotoImage(Image.fromarray(combined)) | ||||
|     LabelPic.image = image | ||||
|     LabelPic['image'] = image | ||||
| 
 | ||||
|     LabelPic.bind('<Configure>', lambda event: changeSize(event, combined, LabelPic)) | ||||
|     LabelPic.pack(fill=tk.BOTH, expand=tk.YES) | ||||
| 
 | ||||
|     # 添加保存按钮 | ||||
|     btn_save = tk.Button(AirsmoWin, text="保存", bg='#add8e6', fg='black', font=('Helvetica', 14), width=20, | ||||
|                          command=savefile) | ||||
|     btn_save.pack(pady=10) | ||||
| 
 | ||||
|     return | ||||
					Loading…
					
					
				
		Reference in new issue