|
try: |
|
import torch |
|
import torchvision |
|
except ImportError: |
|
import subprocess |
|
import sys |
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "torch", "torchvision"]) |
|
import torch |
|
import torchvision |
|
|
|
import gradio as gr |
|
import numpy as np |
|
from PIL import Image |
|
import torchvision.transforms as transforms |
|
from transformers import pipeline |
|
from scipy.ndimage import gaussian_filter |
|
|
|
def preprocess_image(image, target_size=(512, 512)): |
|
"""Preprocess the input image""" |
|
if isinstance(image, str): |
|
image = Image.open(image) |
|
elif isinstance(image, np.ndarray): |
|
image = Image.fromarray(image) |
|
|
|
|
|
aspect_ratio = image.size[0] / image.size[1] |
|
if aspect_ratio > 1: |
|
new_width = int(target_size[0] * aspect_ratio) |
|
new_height = target_size[1] |
|
else: |
|
new_width = target_size[0] |
|
new_height = int(target_size[1] / aspect_ratio) |
|
|
|
preprocess = transforms.Compose([ |
|
transforms.Resize((new_height, new_width)), |
|
transforms.CenterCrop(target_size), |
|
]) |
|
|
|
return preprocess(image) |
|
|
|
def estimate_depth(image, pipe): |
|
"""Estimate depth using the Depth-Anything model""" |
|
depth_output = pipe(image) |
|
depth_map = depth_output["depth"] |
|
depth_map = np.array(depth_map) / 16.67 |
|
return depth_map |
|
|
|
def apply_depth_aware_blur(image, depth_map, max_sigma, min_sigma): |
|
"""Apply variable Gaussian blur based on depth values""" |
|
image_array = np.array(image) |
|
blurred = np.zeros_like(image_array, dtype=np.float32) |
|
|
|
|
|
sigmas = np.interp(depth_map, [depth_map.min(), depth_map.max()], [min_sigma, max_sigma]) |
|
unique_sigmas = np.unique(sigmas) |
|
blur_stack = {} |
|
|
|
|
|
for sigma in unique_sigmas: |
|
if sigma > 0: |
|
blurred_image = np.zeros_like(image_array, dtype=np.float32) |
|
for channel in range(3): |
|
blurred_image[:, :, channel] = gaussian_filter( |
|
image_array[:, :, channel].astype(np.float32), |
|
sigma=sigma |
|
) |
|
blur_stack[sigma] = blurred_image |
|
|
|
|
|
for sigma in unique_sigmas: |
|
if sigma > 0: |
|
mask = (sigmas == sigma) |
|
mask_3d = np.stack([mask] * 3, axis=2) |
|
blurred += mask_3d * blur_stack[sigma] |
|
else: |
|
mask = (sigmas == 0) |
|
mask_3d = np.stack([mask] * 3, axis=2) |
|
blurred += mask_3d * image_array |
|
|
|
return Image.fromarray(blurred.astype(np.uint8)) |
|
|
|
def apply_gaussian_blur(image, sigma): |
|
"""Apply uniform Gaussian blur""" |
|
image_array = np.array(image) |
|
blurred = np.zeros_like(image_array) |
|
|
|
for channel in range(3): |
|
blurred[:, :, channel] = gaussian_filter( |
|
image_array[:, :, channel], |
|
sigma=sigma |
|
) |
|
|
|
return Image.fromarray(blurred.astype(np.uint8)) |
|
|
|
|
|
def get_depth_pipeline(): |
|
return pipeline( |
|
task="depth-estimation", |
|
model="depth-anything/Depth-Anything-V2-Small-hf", |
|
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32, |
|
device=0 if torch.cuda.is_available() else -1 |
|
) |
|
|
|
def process_image(image, blur_type, gaussian_sigma, lens_min_sigma, lens_max_sigma): |
|
"""Main processing function for Gradio interface""" |
|
if image is None: |
|
return None |
|
|
|
processed_image = preprocess_image(image) |
|
|
|
if blur_type == "Gaussian Blur": |
|
result = apply_gaussian_blur(processed_image, gaussian_sigma) |
|
else: |
|
pipe = get_depth_pipeline() |
|
depth_map = estimate_depth(processed_image, pipe) |
|
result = apply_depth_aware_blur(processed_image, depth_map, lens_max_sigma, lens_min_sigma) |
|
|
|
return result |
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("# Image Blur Effects Demo") |
|
gr.Markdown("Apply Gaussian or Lens (Depth-aware) blur to your images") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
input_image = gr.Image(label="Input Image", type="numpy") |
|
blur_type = gr.Radio( |
|
choices=["Gaussian Blur", "Lens Blur"], |
|
label="Blur Effect", |
|
value="Gaussian Blur" |
|
) |
|
|
|
with gr.Column(visible=True) as gaussian_controls: |
|
gaussian_sigma = gr.Slider( |
|
minimum=0, maximum=20, value=5, |
|
label="Gaussian Blur Sigma", |
|
step=0.5 |
|
) |
|
|
|
with gr.Column() as lens_controls: |
|
lens_min_sigma = gr.Slider( |
|
minimum=0, maximum=20, value=15, |
|
label="Maximum Blur (Far)", |
|
step=0.5 |
|
) |
|
lens_max_sigma = gr.Slider( |
|
minimum=0, maximum=10, value=0, |
|
label="Minimum Blur (Near)", |
|
step=0.5 |
|
) |
|
|
|
process_btn = gr.Button("Apply Blur") |
|
|
|
with gr.Column(): |
|
output_image = gr.Image(label="Output Image") |
|
|
|
|
|
def update_controls(blur_type): |
|
return { |
|
gaussian_controls: blur_type == "Gaussian Blur", |
|
lens_controls: blur_type == "Lens Blur" |
|
} |
|
|
|
blur_type.change( |
|
fn=update_controls, |
|
inputs=[blur_type], |
|
outputs=[gaussian_controls, lens_controls] |
|
) |
|
|
|
|
|
process_btn.click( |
|
fn=process_image, |
|
inputs=[ |
|
input_image, |
|
blur_type, |
|
gaussian_sigma, |
|
lens_min_sigma, |
|
lens_max_sigma |
|
], |
|
outputs=output_image |
|
) |
|
|
|
|
|
demo.launch() |