Spaces:
Running
Running
File size: 5,504 Bytes
0730fce b84432d 0730fce b84432d 0730fce b84432d 0730fce b84432d 0730fce b84432d 0730fce b84432d 0730fce b84432d 0730fce b84432d af321f2 5add41c b84432d 0532cb6 5add41c b84432d 5ca4219 b84432d 5ca4219 0730fce b84432d d609bee 0730fce b84432d 0730fce b84432d 0730fce b84432d |
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 |
import numpy as np
import torch
from torchvision.transforms.functional import normalize
import torch.nn.functional as F
from skimage import io
from PIL import Image, ImageFilter
from transformers import AutoModelForImageSegmentation, AutoImageProcessor, AutoModelForDepthEstimation
import streamlit as st
# Load models
segmentation_model = AutoModelForImageSegmentation.from_pretrained("briaai/RMBG-1.4", trust_remote_code=True)
depth_model = AutoModelForDepthEstimation.from_pretrained("depth-anything/Depth-Anything-V2-Small-hf")
depth_processor = AutoImageProcessor.from_pretrained("depth-anything/Depth-Anything-V2-Small-hf")
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
segmentation_model.to(device)
depth_model.to(device)
# Preprocessing function for segmentation
def preprocess_image(im: np.ndarray, model_input_size: list) -> torch.Tensor:
if len(im.shape) < 3:
im = im[:, :, np.newaxis]
im_tensor = torch.tensor(im, dtype=torch.float32).permute(2, 0, 1)
im_tensor = F.interpolate(torch.unsqueeze(im_tensor, 0), size=model_input_size, mode='bilinear')
image = torch.divide(im_tensor, 255.0)
image = normalize(image, [0.5, 0.5, 0.5], [1.0, 1.0, 1.0])
return image
# Postprocessing function for segmentation mask
def postprocess_image(result: torch.Tensor, im_size: list) -> np.ndarray:
result = torch.squeeze(F.interpolate(result, size=im_size, mode='bilinear'), 0)
ma = torch.max(result)
mi = torch.min(result)
result = (result - mi) / (ma - mi)
im_array = (result * 255).permute(1, 2, 0).cpu().data.numpy().astype(np.uint8)
im_array = np.squeeze(im_array)
return im_array
# Streamlit UI
st.title("Blur Effects App")
st.markdown("Choose between Gaussian blur (segmentation-based) or depth-based lens blur.")
# File uploader
uploaded_file = st.file_uploader("Upload an image", type=["jpg", "png", "jpeg"])
if uploaded_file:
# Load the uploaded image
orig_image = Image.open(uploaded_file).convert("RGB")
orig_im_size = orig_image.size
orig_im_np = np.array(orig_image)
# Display original image
st.image(orig_image, caption="Uploaded Image", use_column_width=True)
# Effect selection
effect_option = st.radio("Choose an effect", ("Gaussian Blur (Segmentation)", "Lens Blur (Depth Map)"))
if effect_option == "Gaussian Blur (Segmentation)":
# Gaussian Blur (Segmentation-Based)
st.subheader("Gaussian Blur (Segmentation)")
# Preprocess image for segmentation
model_input_size = [256, 256] # Resize for model compatibility
image = preprocess_image(orig_im_np, model_input_size).to(device)
# Inference using the segmentation model
with torch.no_grad():
result = segmentation_model(image)
# Postprocess result to generate mask
result_image = postprocess_image(result[0][0], orig_im_size)
pil_mask_im = Image.fromarray(result_image)
# Create binary mask for background and foreground separation
binary_mask = pil_mask_im.point(lambda p: 255 if p > 170 else 0, '1')
# Gaussian blur for background
blur_intensity = st.slider("Blur Intensity (σ)", min_value=1, max_value=30, value=15)
blurred_background = orig_image.filter(ImageFilter.GaussianBlur(blur_intensity))
# Combine blurred background and sharp foreground
binary_mask_rgba = binary_mask.convert("L").resize(orig_image.size)
foreground = Image.composite(orig_image, blurred_background, binary_mask_rgba)
# Display results side by side
st.image([orig_image, foreground], caption=["Original Image", "Blurred Background"], use_column_width=True)
elif effect_option == "Lens Blur (Depth Map)":
# Lens Blur (Depth-Based)
st.subheader("Lens Blur (Depth Map)")
# Resize image for depth model processing
inputs = depth_processor(images=orig_image, return_tensors="pt")
# Generate depth map
with torch.no_grad():
outputs = depth_model(**inputs)
depth = outputs.predicted_depth.squeeze().cpu().numpy()
depth = np.array(Image.fromarray(depth).resize(orig_image.size, resample=Image.BICUBIC))
# Resize depth map back to the original image size
depth_min, depth_max = np.min(depth), np.max(depth)
manual_depth_min = depth_min/10
manual_depth_max = depth_max
normalized_depth = (depth - depth_min) / (depth_max - depth_min)
adjusted_depth = np.clip((normalized_depth * (manual_depth_max - manual_depth_min)) + manual_depth_min, 0, 1)
# Create depth-based blur effect
max_blur = st.slider("Max Blur Intensity", min_value=1, max_value=10, value=3)
depth_array = ((1 - adjusted_depth) * max_blur).astype(np.uint8)
# Create blurred images for depth-based blurring
blurred_images = [orig_image.filter(ImageFilter.GaussianBlur(i)) for i in range(max_blur + 1)]
final_image = Image.new("RGB", orig_image.size)
# Apply depth-based blur pixel by pixel
for y in range(orig_image.height):
for x in range(orig_image.width):
blur_level = min(max_blur, max(0, depth_array[y, x]))
final_image.putpixel((x, y), blurred_images[blur_level].getpixel((x, y)))
# Display results side by side
st.image([orig_image, final_image], caption=["Original Image", "Lens Blur Image"], use_column_width=True)
|