Spaces:
Sleeping
Sleeping
import gradio as gr | |
from PIL import Image, ImageFilter | |
import numpy as np | |
import torch | |
import cv2 | |
from transformers import AutoImageProcessor, AutoModelForDepthEstimation | |
# Load depth estimation model | |
image_processor = AutoImageProcessor.from_pretrained("depth-anything/Depth-Anything-V2-Small-hf") | |
model = AutoModelForDepthEstimation.from_pretrained("depth-anything/Depth-Anything-V2-Small-hf") | |
def apply_gaussian_blur(image, mask): | |
"""Applies Gaussian blur to the background based on a user-drawn mask.""" | |
if mask is None: | |
return image # If no mask is provided, return the original image | |
# Ensure mask is grayscale and resized to match image dimensions | |
mask_pil = Image.fromarray(mask).convert("L").resize(image.size) | |
mask_array = np.array(mask_pil) | |
# Create a blurred background | |
blurred_background = image.filter(ImageFilter.GaussianBlur(radius=15)) | |
# Convert images to NumPy arrays | |
img_array = np.array(image) | |
blurred_array = np.array(blurred_background) | |
# Create a boolean mask (foreground = True, background = False) | |
foreground_mask = mask_array > 0 | |
foreground_mask_3d = np.stack([foreground_mask] * 3, axis=-1) | |
# Blend the original image with the blurred background | |
final_image_array = np.where(foreground_mask_3d, img_array, blurred_array) | |
final_image = Image.fromarray(final_image_array.astype(np.uint8)) | |
return final_image | |
def apply_lens_blur(image): | |
"""Applies depth-based lens blur using a pre-trained model.""" | |
# Resize image to 512x512 for processing | |
resized_image = image.resize((512, 512)) | |
image_np = np.array(resized_image) | |
# Prepare image for the model | |
inputs = image_processor(images=resized_image, return_tensors="pt") | |
with torch.no_grad(): | |
outputs = model(**inputs) | |
predicted_depth = outputs.predicted_depth | |
# Interpolate depth map to match the image size | |
prediction = torch.nn.functional.interpolate( | |
predicted_depth.unsqueeze(1), | |
size=resized_image.size[::-1], | |
mode="bicubic", | |
align_corners=False, | |
).squeeze() | |
# Convert prediction to a NumPy array | |
depth_map = prediction.cpu().numpy() | |
# Normalize the depth map | |
depth_norm = (depth_map - np.min(depth_map)) / (np.max(depth_map) - np.min(depth_map)) | |
num_blur_levels = 5 | |
blurred_layers = [] | |
for i in range(num_blur_levels): | |
sigma = i * 0.5 | |
if sigma == 0: | |
blurred = image_np | |
else: | |
blurred = cv2.GaussianBlur(image_np, (15, 15), sigmaX=sigma, sigmaY=sigma, borderType=cv2.BORDER_REPLICATE) | |
blurred_layers.append(blurred) | |
depth_indices = ((1 - depth_norm) * (num_blur_levels - 1)).astype(np.uint8) | |
final_blurred_image = np.zeros_like(image_np) | |
for y in range(image_np.shape[0]): | |
for x in range(image_np.shape[1]): | |
depth_index = depth_indices[y, x] | |
final_blurred_image[y, x] = blurred_layers[depth_index][y, x] | |
# Convert the final blurred image back to a PIL Image | |
final_blurred_pil_image = Image.fromarray(final_blurred_image) | |
return final_blurred_pil_image | |
def process_image(image, mask, blur_type): | |
"""Processes the image based on the selected blur type.""" | |
if blur_type == "Gaussian Blur": | |
return apply_gaussian_blur(image, mask) | |
elif blur_type == "Lens Blur": | |
return apply_lens_blur(image) | |
else: | |
return image | |
interface = gr.Interface( | |
fn=process_image, | |
inputs=[ | |
gr.Image(type="pil", label="Upload an Image"), | |
gr.Sketchpad(height=256, width=256, label="Draw Mask (Only for Gaussian Blur)"), | |
gr.Radio(["Gaussian Blur", "Lens Blur"], label="Choose Blur Effect") | |
], | |
outputs=gr.Image(type="pil"), | |
title="Gaussian & Lens Blur Effects", | |
description="Upload an image and select either Gaussian blur (with mask) or depth-based lens blur." | |
) | |
if __name__ == "__main__": | |
interface.launch(share=True) | |