/
karik
/
seventh
Обзор
Документация
Войти
/
karik
/
seventh
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
7.py
454 строки
19 KB
karik
upload files
30 ноя 2025, 17:43
30 ноя 2025, 17:43
5799ffb
Код
Авторство
О чём код?
import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTk import numpy as np import cv2 import os # ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ def resize_for_display(img, max_size=400): """Масштабирование изображения для отображения в Tkinter""" h, w = img.shape[:2] scale = min(max_size / h, max_size / w) new_w = int(w * scale) new_h = int(h * scale) return cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_AREA) def calculate_difference(img1, img2): """Вычисление разности между двумя изображениями""" if img1.shape != img2.shape: img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0])) # Конвертируем в grayscale для вычисления разности if len(img1.shape) == 3: img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) else: img1_gray = img1 if len(img2.shape) == 3: img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) else: img2_gray = img2 diff = cv2.absdiff(img1_gray, img2_gray) return diff def normalize_to_heatmap(diff): """Нормализация разности для визуализации как тепловой карты""" normalized = cv2.normalize(diff, None, 0, 255, cv2.NORM_MINMAX) heatmap = cv2.applyColorMap(normalized.astype(np.uint8), cv2.COLORMAP_JET) return heatmap def apply_roberts_to_half(image, half='left'): """Применение оператора Робертса к половине изображения""" if len(image.shape) == 3: img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) else: img_gray = image h, w = img_gray.shape mid = w // 2 # Оператор Робертса kernel_roberts_x = np.array([[1, 0], [0, -1]], dtype=np.float32) kernel_roberts_y = np.array([[0, 1], [-1, 0]], dtype=np.float32) img_f = img_gray.astype(np.float32) rob_x = cv2.filter2D(img_f, cv2.CV_32F, kernel_roberts_x) rob_y = cv2.filter2D(img_f, cv2.CV_32F, kernel_roberts_y) roberts_full = cv2.sqrt(rob_x * rob_x + rob_y * rob_y) roberts_full = np.clip(roberts_full, 0, 255).astype(np.uint8) # Создаем результат с оригиналом и обработанной половиной if len(image.shape) == 3: result = image.copy() roberts_bgr = cv2.cvtColor(roberts_full, cv2.COLOR_GRAY2BGR) else: result = np.stack([img_gray] * 3, axis=-1) if len(img_gray.shape) == 2 else img_gray.copy() roberts_bgr = np.stack([roberts_full] * 3, axis=-1) if half == 'left': result[:, :mid] = roberts_bgr[:, :mid] else: result[:, mid:] = roberts_bgr[:, mid:] return result def apply_sobel_to_half(image, half='right'): """Применение оператора Собеля к половине изображения""" if len(image.shape) == 3: img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) else: img_gray = image h, w = img_gray.shape mid = w // 2 # Оператор Собеля sobel_x = cv2.Sobel(img_gray, cv2.CV_64F, 1, 0, ksize=3) sobel_y = cv2.Sobel(img_gray, cv2.CV_64F, 0, 1, ksize=3) sobel_full = cv2.magnitude(sobel_x, sobel_y) sobel_full = np.clip(sobel_full, 0, 255).astype(np.uint8) # Создаем результат с оригиналом и обработанной половиной if len(image.shape) == 3: result = image.copy() sobel_bgr = cv2.cvtColor(sobel_full, cv2.COLOR_GRAY2BGR) else: result = np.stack([img_gray] * 3, axis=-1) if len(img_gray.shape) == 2 else img_gray.copy() sobel_bgr = np.stack([sobel_full] * 3, axis=-1) if half == 'left': result[:, :mid] = sobel_bgr[:, :mid] else: result[:, mid:] = sobel_bgr[:, mid:] return result def apply_combined_highpass(image): """Применение Робертса к левой половине и Собеля к правой""" if len(image.shape) == 3: img_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) else: img_gray = image h, w = img_gray.shape mid = w // 2 # Левая половина - Робертс left_half = apply_roberts_to_half(image, 'left') # Правая половина - Собель right_half = apply_sobel_to_half(image, 'right') # Объединяем результаты result = left_half.copy() result[:, mid:] = right_half[:, mid:] return result def save_image(image, default_name): """Сохранение изображения с выбором файла""" filename = filedialog.asksaveasfilename( defaultextension=".png", filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg"), ("All files", "*.*")], initialfile=default_name ) if filename: # Конвертируем BGR в RGB для сохранения if len(image.shape) == 3: image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) else: image_rgb = image cv2.imwrite(filename, image_rgb) messagebox.showinfo("Успех", f"Изображение сохранено как:\n{filename}") # ОСНОВНОЙ КЛАСС GUI class ImageProcessorApp: def __init__(self, root): self.root = root self.root.title("Обработка изображений — НЧ и ВЧ фильтры с сравнением") self.root.geometry("1400x900") self.original = None self.original_filename = None self.proc_low = {} # Словарь для НЧ фильтров self.proc_high = {} # Словарь для ВЧ фильтров self.differences = {} # Словарь для разностей # --- Основные кнопки --- btn_frame = tk.Frame(root) btn_frame.pack(pady=10) btn_open = tk.Button(btn_frame, text="Загрузить изображение", command=self.load_image, width=20, height=2) btn_open.grid(row=0, column=0, padx=5) # --- Кнопки НЧ фильтров --- low_frame = tk.LabelFrame(btn_frame, text="НЧ фильтры (Гаусс)") low_frame.grid(row=0, column=1, padx=10) btn_low1 = tk.Button(low_frame, text="Гаусс 5x5", command=lambda: self.apply_lowpass(5), width=12) btn_low1.grid(row=0, column=0, padx=2) btn_low2 = tk.Button(low_frame, text="Гаусс 15x15", command=lambda: self.apply_lowpass(15), width=12) btn_low2.grid(row=0, column=1, padx=2) btn_low3 = tk.Button(low_frame, text="Гаусс 25x25", command=lambda: self.apply_lowpass(25), width=12) btn_low3.grid(row=0, column=2, padx=2) # --- Кнопки ВЧ фильтров --- high_frame = tk.LabelFrame(btn_frame, text="ВЧ фильтры") high_frame.grid(row=0, column=2, padx=10) btn_high_combined = tk.Button(high_frame, text="Робертс(лев) + Собель(прав)", command=self.apply_combined_highpass, width=25) btn_high_combined.grid(row=0, column=0, padx=2) # --- Кнопки сравнения --- compare_frame = tk.LabelFrame(btn_frame, text="Сравнение") compare_frame.grid(row=0, column=3, padx=10) btn_compare = tk.Button(compare_frame, text="Сравнить результаты", command=self.show_comparison, width=18, height=2) btn_compare.grid(row=0, column=0, padx=5) # --- Область для изображений --- main_frame = tk.Frame(root) main_frame.pack(pady=20, fill=tk.BOTH, expand=True) # Оригинальное изображение orig_frame = tk.LabelFrame(main_frame, text="Оригинал") orig_frame.grid(row=0, column=0, padx=10, pady=5, sticky='nsew') self.label_original = tk.Label(orig_frame) self.label_original.pack() # Кнопка сохранения оригинала self.btn_save_original = tk.Button(orig_frame, text="Сохранить оригинал", command=self.save_original, width=15, state=tk.DISABLED) self.btn_save_original.pack(pady=5) # НЧ фильтры low_display_frame = tk.LabelFrame(main_frame, text="НЧ фильтры (Гаусс)") low_display_frame.grid(row=0, column=1, padx=10, pady=5, sticky='nsew') self.low_labels = {} self.low_buttons = {} sizes = [5, 15, 25] for i, size in enumerate(sizes): frame = tk.Frame(low_display_frame) frame.pack(pady=5) tk.Label(frame, text=f"Гаусс {size}x{size}").pack() label = tk.Label(frame) label.pack() self.low_labels[size] = label # Кнопка сохранения для каждого НЧ фильтра btn_save = tk.Button(frame, text="Сохранить", command=lambda s=size: self.save_lowpass(s), width=10, state=tk.DISABLED) btn_save.pack(pady=2) self.low_buttons[size] = btn_save # ВЧ фильтры high_display_frame = tk.LabelFrame(main_frame, text="ВЧ фильтры") high_display_frame.grid(row=0, column=2, padx=10, pady=5, sticky='nsew') self.high_labels = {} self.high_buttons = {} filters = ['combined'] names = ['Робертс(лев) + Собель(прав)'] for i, (filter_type, name) in enumerate(zip(filters, names)): frame = tk.Frame(high_display_frame) frame.pack(pady=5) tk.Label(frame, text=name).pack() label = tk.Label(frame) label.pack() self.high_labels[filter_type] = label # Кнопка сохранения для ВЧ фильтра btn_save = tk.Button(frame, text="Сохранить", command=lambda f=filter_type: self.save_highpass(f), width=10, state=tk.DISABLED) btn_save.pack(pady=2) self.high_buttons[filter_type] = btn_save # Настройка весов колонок main_frame.columnconfigure(0, weight=1) main_frame.columnconfigure(1, weight=1) main_frame.columnconfigure(2, weight=1) # ЗАГРУЗКА def load_image(self): filename = filedialog.askopenfilename( filetypes=[("Изображения", "*.png *.jpg *.jpeg *.bmp")] ) if not filename: return # Чтение через PIL (работает с кириллицей) pil_img = Image.open(filename) self.original = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) self.original_filename = os.path.basename(filename) self.proc_low = {} self.proc_high = {} self.differences = {} # Активируем кнопку сохранения оригинала self.btn_save_original.config(state=tk.NORMAL) # Деактивируем кнопки сохранения фильтров for btn in self.low_buttons.values(): btn.config(state=tk.DISABLED) for btn in self.high_buttons.values(): btn.config(state=tk.DISABLED) self.update_display() # НИЗКИЕ ЧАСТОТЫ (Гаусс) def apply_lowpass(self, kernel_size): if self.original is None: messagebox.showwarning("Предупреждение", "Сначала загрузите изображение") return # НЧ фильтр — гауссово размытие с разными размерами ядра low = cv2.GaussianBlur(self.original, (kernel_size, kernel_size), 0) self.proc_low[kernel_size] = low # Активируем кнопку сохранения для этого фильтра self.low_buttons[kernel_size].config(state=tk.NORMAL) self.update_display() # ВЫСОКИЕ ЧАСТОТЫ (комбинированный) def apply_combined_highpass(self): if self.original is None: messagebox.showwarning("Предупреждение", "Сначала загрузите изображение") return # Применяем Робертса к левой половине и Собеля к правой combined = apply_combined_highpass(self.original) self.proc_high['combined'] = combined # Активируем кнопку сохранения для ВЧ фильтра self.high_buttons['combined'].config(state=tk.NORMAL) self.update_display() # СОХРАНЕНИЕ ИЗОБРАЖЕНИЙ def save_original(self): if self.original is not None: base_name = os.path.splitext(self.original_filename)[0] default_name = f"{base_name}_original.png" save_image(self.original, default_name) def save_lowpass(self, kernel_size): if kernel_size in self.proc_low: base_name = os.path.splitext(self.original_filename)[0] default_name = f"{base_name}_gaussian_{kernel_size}x{kernel_size}.png" save_image(self.proc_low[kernel_size], default_name) def save_highpass(self, filter_type): if filter_type in self.proc_high: base_name = os.path.splitext(self.original_filename)[0] if filter_type == 'combined': default_name = f"{base_name}_roberts_left_sobel_right.png" save_image(self.proc_high[filter_type], default_name) # СРАВНЕНИЕ РЕЗУЛЬТАТОВ def show_comparison(self): if len(self.proc_low) < 2: messagebox.showwarning("Предупреждение", "Примените хотя бы два НЧ фильтра для сравнения") return # Создаем окно для сравнения compare_window = tk.Toplevel(self.root) compare_window.title("Сравнение результатов фильтрации") compare_window.geometry("1000x600") # Вычисляем разности self.calculate_all_differences() # Основной фрейм для сравнения main_compare_frame = tk.Frame(compare_window) main_compare_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # Фрейм для разностей НЧ фильтров low_diff_frame = tk.LabelFrame(main_compare_frame, text="Разности НЧ фильтров (Гаусс)") low_diff_frame.pack(fill=tk.BOTH, expand=True, pady=5) # Отображаем разности НЧ фильтров low_inner_frame = tk.Frame(low_diff_frame) low_inner_frame.pack() col = 0 if 'low_5_15' in self.differences: self.create_diff_display(low_inner_frame, self.differences['low_5_15'], "Гаусс 5x5 vs 15x15", col) col += 1 if 'low_15_25' in self.differences: self.create_diff_display(low_inner_frame, self.differences['low_15_25'], "Гаусс 15x15 vs 25x25", col) col += 1 if 'low_5_25' in self.differences: self.create_diff_display(low_inner_frame, self.differences['low_5_25'], "Гаусс 5x5 vs 25x25", col) def create_diff_display(self, parent_frame, diff, title, column): """Создание отображения разности с тепловой картой""" frame = tk.Frame(parent_frame) frame.grid(row=0, column=column, padx=10, pady=5) # Заголовок tk.Label(frame, text=title, font=('Arial', 10, 'bold')).pack() # Тепловая карта разности heatmap = normalize_to_heatmap(diff) img_display = resize_for_display(heatmap, 300) imgtk = ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(img_display, cv2.COLOR_BGR2RGB))) label = tk.Label(frame, image=imgtk) label.image = imgtk label.pack() def calculate_all_differences(self): """Вычисление всех возможных разностей между фильтрами""" # Разности между НЧ фильтрами if 5 in self.proc_low and 15 in self.proc_low: self.differences['low_5_15'] = calculate_difference(self.proc_low[5], self.proc_low[15]) if 15 in self.proc_low and 25 in self.proc_low: self.differences['low_15_25'] = calculate_difference(self.proc_low[15], self.proc_low[25]) if 5 in self.proc_low and 25 in self.proc_low: self.differences['low_5_25'] = calculate_difference(self.proc_low[5], self.proc_low[25]) # ОБНОВЛЕНИЕ GUI def update_display(self): # Оригинальное изображение if self.original is not None: img = resize_for_display(self.original) imgtk = ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))) self.label_original.configure(image=imgtk) self.label_original.image = imgtk else: self.label_original.configure(image=None) # НЧ фильтры for size, label in self.low_labels.items(): if size in self.proc_low: img = resize_for_display(self.proc_low[size]) imgtk = ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))) label.configure(image=imgtk) label.image = imgtk else: label.configure(image=None) # ВЧ фильтры for filter_type, label in self.high_labels.items(): if filter_type in self.proc_high: img = resize_for_display(self.proc_high[filter_type]) imgtk = ImageTk.PhotoImage(image=Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))) label.configure(image=imgtk) label.image = imgtk else: label.configure(image=None) # ЗАПУСК ПРОГРАММЫ if __name__ == "__main__": root = tk.Tk() app = ImageProcessorApp(root) root.mainloop()