Исходный код blinddeconv.processing.core

"""
Основной модуль фреймворка обработки изображений.

Содержит класс Processing для управления конвейером обработки изображений:
загрузка, фильтрация, восстановление, анализ метрик.

Авторы: Юров П.И., Беззаборов А.А., Куропатов К.Л.
"""

import numpy as np
import os
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import pandas as pd
from pathlib import Path
from typing import Optional, Any

from .utils import Image
from ..filters import base as filters
from ..algorithms.base import DeconvolutionAlgorithm

from .extensions.hyperparameter_optimization import HyperparameterOptimizer
from .extensions.pareto_analysis import ParetoFrontAnalyzer
from .reader import ModuleReader
from .display import ModuleDisplay
from .preprocessing import ModulePreprocessing
from .tables import ModuleData
from .clear import ModuleClear
from .applyfilter import ModuleFilter
from .restore import ModuleProcess
from .restorepipeline import ModuleProcessPipeline


[документация] class Processing: """ Фреймворк для обработки изображений. Предоставляет полный конвейер для работы с изображениями: загрузка, применение фильтров, восстановление, анализ метрик. Атрибуты -------- color : bool Тип загрузки изображений (цветное/черно-белое). folder_path : Path Директория с исходными изображениями. folder_path_blurred : Path Директория со смазанными изображениями. folder_path_restored : Path Директория с восстановленными изображениями. data_path : Path Директория для сохранения анализа данных. images : np.ndarray Массив связей изображений. kernel_dir : Path Директория для ядер. dataset_path : Path Директория для метаданных датасетов. preprocess_dir: str Директория для обработанных смазанных изображений. """
[документация] def __init__(self, images_folder: str = 'images', blurred_folder: str = 'blurred', restored_folder: str = 'restored', data_path: str = 'data', color: bool = False, kernel_dir: str = 'kernels', preprocess_dir: str = 'preprocess', dataset_path: str = 'dataset') -> None: """ Инициализация фреймворка. Параметры --------- images_folder : str Директория с исходными изображениями. blurred_folder : str Директория со смазанными изображениями. restored_folder : str Директория с восстановленными изображениями. data_path : str Директория для сохранения анализа данных. color : bool Тип загрузки изображений (True - цветное, False - ч/б). kernel_dir : str Директория для ядер. dataset_path : str Директория для метаданных датасетов. preprocess_dir: str Директория для обработанных смазанных изображений. """ self.color = color self.folder_path = Path(images_folder) self.folder_path_blurred = Path(blurred_folder) self.folder_path_restored = Path(restored_folder) self.data_path = Path(data_path) self.images = np.array([]) self.amount_of_blurred = 1 self.optimizer = HyperparameterOptimizer(self) self.analyzer = ParetoFrontAnalyzer(self) self.reader = ModuleReader(self) self.display = ModuleDisplay(self) self.histogram = ModulePreprocessing(self) self.tables = ModuleData(self) self.clear = ModuleClear(self) self.apply_filter = ModuleFilter(self) self.module_process = ModuleProcess(self) self.process_pipeline = ModuleProcessPipeline(self) #разные, если дочерний будет переопределять методы из родительского. self.kernel_dir = Path(kernel_dir) self.dataset_path = Path(dataset_path) self.preprocess_dir = Path(preprocess_dir) for folder in [self.folder_path, self.folder_path_blurred, self.folder_path_restored, self.data_path, self.kernel_dir, self.dataset_path, self.preprocess_dir]: folder.mkdir(parents=True, exist_ok=True)
[документация] def changescale(self, color: bool) -> None: """ Изменение способа загрузки изображений. Параметры --------- color : bool True - цветное, False - черно-белое. """ self.color = color
[документация] def read_all(self) -> None: """Загрузка всех изображений из директории.""" self.reader.read_all()
[документация] def read_one(self, path: Path) -> None: """Загрузка одного изображения.""" self.reader.read_one(path)
[документация] def show(self, size: float = 1.0, kernel_intencity_scale: float = 1.0, kernel_size: float = 1.0) -> None: """Вывод всех изображений: оригинал, размытые, восстановленные + метрики.""" self.display.show(size, kernel_intencity_scale, kernel_size)
[документация] def histogram_equalization(self, view_histogram: bool = False) -> None: """Выполняет выравнивание гистограмм.""" self.histogram.histogram_equalization(view_histogram)
[документация] def histogram_equalization_CLAHE(self, view_histogram: bool = False, clip_limit: float = 0.01) -> None: """Выполняет адаптивное выравнивание гистограмм с ограничением контрастности.""" self.histogram.histogram_equalization_CLAHE(view_histogram, clip_limit)
[документация] def inverse_histogram_equalization(self, view_histogram: bool = False) -> None: """Обращает выравнивание гистограмм.""" self.histogram.inverse_histogram_equalization(view_histogram)
[документация] def get_table(self, table_path: Path, display_table: bool = False) -> None: """Получение метрик в структурированном виде.""" self.tables.get_table(table_path, display_table)
[документация] def clear_input(self) -> None: """Убирает привязку ко всем загруженным изображениям.""" self.clear.clear_input()
[документация] def reset(self) -> None: """Сброс состояний всех изображений до исходного.""" self.clear.reset()
[документация] def clear_output(self) -> None: """Удаление всех сгенерированных файлов.""" self.clear.clear_output()
[документация] def clear_output_directory(self, warning: str = 'IT WILL DELETE EVERYTHING!') -> None: """Полная очистка выходных директорий.""" self.clear.clear_output_directory(warning)
[документация] def clear_restored(self) -> None: """Удаляет восстановленные изображения из каждой связи.""" self.clear.clear_restored()
[документация] def unbind_restored(self) -> None: """Разрывает связь, убирая все восстановленные.""" self.clear.unbind_restored()
[документация] def clear_all(self) -> None: """Полная очистка: файлы + состояния + загруженные изображения.""" self.clear.clear_all()
[документация] def bind(self, original_image_path: Path, blurred_image_path: Path, original_kernel_path: Optional[Path] = None, filter_description: str = "unknown", color: bool = True) -> Image: """ Связывает оригинальное изображение с искаженной версией. Параметры --------- original_image_path : Path Путь к оригинальному изображению. blurred_image_path : Path Путь к смазанному изображению. original_kernel_path : Optional[Path] Путь к ядру размытия. filter_description : str Описание примененного фильтра. color : bool Способ загрузки (True - цветное, False - ч/б). Возвращает ---------- Image Объект связи изображений. """ return self.reader.bind(original_image_path, blurred_image_path, original_kernel_path, filter_description, color)
[документация] def save_bind_state(self, file_path: Optional[Path] = None) -> None: """Сохраняет состояние связей в JSON файл.""" self.reader.save_bind_state(file_path)
[документация] def load_bind_state(self, bind_path: Path) -> None: """Загружает состояние связей из JSON файла.""" self.reader.load_bind_state(bind_path)
[документация] def custom_filter(self, kernel_image_path: Path, kernel_npy_path: Path) -> None: """Применение созданного фильтра ко всем оригинальным изображениям.""" self.apply_filter.custom_filter(kernel_image_path, kernel_npy_path)
[документация] def show_line(self, window_scale: float = 1.0, fontsize: int = 8) -> None: """ Вывод изображений в строчку. Параметры --------- window_scale : float Регулирует размер окна. fontsize : int Размер шрифта. """ self.display.show_line(window_scale, fontsize)
[документация] def filter(self, filter_processor: filters.FilterBase) -> None: """Применение фильтра ко всем изображениям.""" self.apply_filter.filter(filter_processor)
[документация] def save_filter(self) -> None: """Сохранение текущего состояния фильтров в список.""" for img_obj in self.images: img_obj.save_filter() self.amount_of_blurred += 1
[документация] def load_filter(self, index: int) -> None: """ Загрузка состояния фильтров из списка. Параметры --------- index : int Индекс доставаемого изображения. """ for img_obj in self.images: img_obj.load(index) self.amount_of_blurred -= 1
[документация] def len_blur(self) -> int: """Количество вариантов размытия.""" return self.amount_of_blurred
[документация] def process(self, algorithm_processor: DeconvolutionAlgorithm, metadata: bool = False, unique_path: bool = True) -> None: """ Восстановление всех изображений. Параметры --------- algorithm_processor : DeconvolutionAlgorithm Метод восстановления изображения. metadata : bool Сохранять метаданные или нет. unique_path : bool Генерировать уникальные пути. """ self.module_process.process(algorithm_processor, metadata, unique_path)
[документация] def full_process(self, filters: list, methods: list, size: float = 0.75, kernel_intencity_scale: float = 10.0) -> None: """ Пайплайн применения фильтров с последующим восстановлением. Параметры --------- filters : list Массив массивов объектов FilterBase [[],[]]. methods : list Массив объектов DeconvolutionAlgorithm. size : float Размер таблицы. kernel_intencity_scale : float Цвет пикселей PSF при выводе. """ self.process_pipeline.full_process(filters, methods, size, kernel_intencity_scale)
[документация] def process_hyperparameter_optimization(self, *args, **kwargs) -> Any: """Запуск оптимизации гиперпараметров.""" return self.optimizer.execute(*args, **kwargs)
[документация] def pareto(self) -> Any: """Построение фронта Парето.""" return self.analyzer.execute()
[документация] def merge(frame1: Processing, frame2: Processing)->Processing: """ Объединяет массивы обработанных изображений. Параметры --------- frame1 : Processing Первый фреймворк. frame2 : Processing Второй фреймворк. Возвращает ---------- Processing Объединённый фреймворк. """ frame_res = Processing(images_folder=frame1.folder_path, blurred_folder=frame1.folder_path_blurred, restored_folder=frame1.folder_path_restored, data_path=frame1.data_path, color=frame1.color, kernel_dir=frame1.kernel_dir, dataset_path = frame1.dataset_path) frame_res.images = np.append(frame1.images.copy(),frame2.images.copy()) return frame_res
[документация] def show_from_table(table_path: Path, alg_name: str, window_scale: float = 1.0) -> None: """ Выводит сетку из смазанных и восстановленных изображений. Параметры --------- table_path : str Путь к .csv файлу. alg_name : str Имя алгоритма для визуализации. window_scale : float Регулирует размер окна. """ df = pd.read_csv(table_path) h, w = df.shape fig, axes = plt.subplots(4, h, figsize=(5 * h * max(window_scale,0.1), 18*max(window_scale,0.1))) axes = np.atleast_2d(axes) for idx, line in enumerate(df.iloc): paths = { "Original": line['blurred'], "Restored": line[alg_name], "Estimated Kernel": line[f'kernel_{alg_name}'], "Ground Truth Kernel": line['kernel blur'] } images = {} for title, path in paths.items(): if os.path.exists(path): images[title] = mpimg.imread(path) else: print(f" Файл не найден: {path}") images[title] = np.zeros((100, 100), dtype=np.uint8) # Черный квадрат-заглушка axes[0, idx].imshow(images["Original"], cmap='gray') axes[1, idx].imshow(images["Restored"], cmap='gray') axes[2, idx].imshow(images["Estimated Kernel"], cmap='gray') axes[3, idx].imshow(images["Ground Truth Kernel"], cmap='gray') for row in range(4): axes[row, idx].axis('off') fig.suptitle(f"Сравнение результатов восстановления изображений ({alg_name})", fontsize=20, y=0.97) plt.tight_layout(rect=[0, 0, 1, 0.95]) plt.show()