File size: 8,526 Bytes
de61f4a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
import gradio as gr
import numpy as np
import cv2 # Используем OpenCV для продвинутых опций
import math
# Словарь для сопоставления имен методов интерполяции с флагами OpenCV
interpolation_map = {
'Nearest': cv2.INTER_NEAREST, # Ближайший сосед
'Linear': cv2.INTER_LINEAR, # Билинейная
'Cubic': cv2.INTER_CUBIC, # Бикубическая
'Area': cv2.INTER_AREA, # Хорошо для уменьшения (усреднение по площади)
'Lanczos4': cv2.INTER_LANCZOS4 # Ланцош (часто дает резкие результаты)
}
def resize_image_gaussian_smooth(image, target_width, target_height, interpolation_str, blur_sigma):
"""
Изменяет размер изображения и применяет Гауссово размытие.
Args:
image (np.ndarray): Входное изображение в формате NumPy RGB.
target_width (int): Целевая ширина.
target_height (int): Целевая высота.
interpolation_str (str): Название метода интерполяции ('Nearest', 'Linear', etc.).
blur_sigma (float): Стандартное отклонение для Гауссова фильтра (0 = без размытия).
Returns:
np.ndarray: Обработанное изображение в формате NumPy RGB, или None при ошибке.
"""
if image is None:
gr.Warning("Сначала загрузите изображение!")
return None
if not (isinstance(target_width, (int, float)) and target_width > 0 and
isinstance(target_height, (int, float)) and target_height > 0):
gr.Warning("Ширина и высота должны быть положительными числами.")
return None # Возвращаем None, чтобы поле вывода очистилось или показало ошибку
target_width = int(target_width)
target_height = int(target_height)
blur_sigma = float(blur_sigma)
# --- Безопасность: Ограничим максимальный размер во избежание проблем с памятью ---
MAX_DIM = 8192
if target_width > MAX_DIM or target_height > MAX_DIM:
gr.Warning(f"Слишком большой размер. Максимальная сторона: {MAX_DIM}px.")
return None
h_orig, w_orig, _ = image.shape
print(f"Original size: {w_orig}x{h_orig}")
print(f"Target size: {target_width}x{target_height}")
print(f"Interpolation: {interpolation_str}")
print(f"Gaussian Sigma: {blur_sigma}")
# 1. Выбираем флаг интерполяции OpenCV
interpolation_flag = interpolation_map.get(interpolation_str, cv2.INTER_LANCZOS4)
# 2. Изменяем размер изображения
# Gradio передает изображение как NumPy array в формате RGB. OpenCV работает с BGR.
img_bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
try:
resized_bgr = cv2.resize(img_bgr, (target_width, target_height), interpolation=interpolation_flag)
except Exception as e:
gr.Error(f"Ошибка при изменении размера: {e}")
return None
# 3. Применяем Гауссово размытие (если sigma > 0)
# Это имитирует сглаживающий фильтр DSR, применяемый *после* масштабирования
# Размер ядра (ksize) должен быть нечетным. Если ksize=(0, 0), OpenCV вычисляет его из sigma.
# Чем больше sigma, тем сильнее размытие.
result_bgr = resized_bgr
if blur_sigma > 0.0:
# Рассчитаем подходящий размер ядра (должен быть нечетным)
# Эмпирическое правило: размер ядра примерно 6*sigma. Округляем до ближайшего нечетного.
ksize = int(math.ceil(blur_sigma * 3)) * 2 + 1
print(f"Calculated Gaussian kernel size: ({ksize}, {ksize}) for sigma={blur_sigma}")
try:
# Используем явно заданный ksize для большего контроля, как в 13-tap
# ksize=(13, 13) было бы прямым аналогом 13-tap, но sigma дает больше гибкости
# result_bgr = cv2.GaussianBlur(resized_bgr, ksize=(ksize, ksize), sigmaX=blur_sigma, sigmaY=blur_sigma)
# ИЛИ: Позволим OpenCV самому выбрать ksize из sigma (более стандартный подход)
result_bgr = cv2.GaussianBlur(resized_bgr, ksize=(0, 0), sigmaX=blur_sigma, sigmaY=blur_sigma)
except Exception as e:
gr.Error(f"Ошибка при применении размытия: {e}")
return None
# 4. Конвертируем результат обратно в RGB для отображения в Gradio
result_rgb = cv2.cvtColor(result_bgr, cv2.COLOR_BGR2RGB)
return result_rgb
# --- Создание интерфейса Gradio ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown(
"""
# Масштабирование изображений с Гауссовым сглаживанием
Загрузите изображение, выберите целевое разрешение, метод интерполяции и степень Гауссова размытия (для сглаживания).
Это может имитировать эффект сглаживания от технологий типа NVIDIA DSR при даунскейлинге,
или просто смягчить артефакты апскейлинга.
"""
)
with gr.Row():
with gr.Column(scale=1):
input_image = gr.Image(label="Входное изображение", type="numpy", height=300)
interp_choice = gr.Dropdown(
choices=list(interpolation_map.keys()),
label="Метод интерполяции для масштабирования",
value='Lanczos4' # Ланцош часто хорош для качества
)
target_w = gr.Number(label="Целевая ширина (px)", value=512, minimum=1, step=1, precision=0)
target_h = gr.Number(label="Целевая высота (px)", value=512, minimum=1, step=1, precision=0)
smoothness_sigma = gr.Slider(
minimum=0.0, maximum=5.0, step=0.1,
label="Сигма Гауссова размытия (0 = нет)",
info="Применяется ПОСЛЕ масштабирования. Небольшие значения (0.3-0.8) могут сгладить пикселизацию апскейла или имитировать DSR-сглаживание даунскейла.",
value=0.0
)
submit_btn = gr.Button("Обработать изображение", variant="primary")
with gr.Column(scale=1):
output_image = gr.Image(label="Результат", type="numpy", height=400)
gr.Markdown(
"**Примечание о 13-tap Gaussian filter:** DSR использует специфический фильтр. "
"Здесь применяется стандартный Гауссов фильтр *после* изменения размера. "
"Параметр `Сигма` контролирует степень размытия."
"Вы можете экспериментировать с `Сигмой` около 0.5-1.0 для имитации мягкого сглаживания."
)
# Связываем кнопку с функцией
submit_btn.click(
fn=resize_image_gaussian_smooth,
inputs=[input_image, target_w, target_h, interp_choice, smoothness_sigma],
outputs=output_image
)
# Запуск интерфейса
if __name__ == "__main__":
# Установка зависимостей: pip install gradio opencv-python numpy
demo.launch() |