kvinod15 commited on
Commit
4b0b756
·
verified ·
1 Parent(s): aa66451

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -46
app.py CHANGED
@@ -1,57 +1,138 @@
1
- import cv2
2
  import numpy as np
 
 
 
3
  import gradio as gr
4
- from PIL import Image
5
-
6
- # Dummy segmentation function: replace with your actual segmentation model inference if available.
7
- def segment_foreground(img):
8
- np_img = np.array(img.convert("RGB"))
9
- h, w, _ = np_img.shape
10
- mask = np.zeros((h, w), dtype=np.uint8)
11
- center = (w // 2, h // 2)
12
- radius = min(center) - 10
13
- cv2.circle(mask, center, radius, (255), thickness=-1)
14
- return mask
15
-
16
- # Function to apply Gaussian blur to the background using the segmentation mask.
17
- def gaussian_blur_background(img, sigma=15):
18
- mask = segment_foreground(img)
19
- np_img = np.array(img.convert("RGB"))
20
- blurred = cv2.GaussianBlur(np_img, (0, 0), sigma)
21
- mask_3d = np.stack([mask] * 3, axis=-1) / 255.0
22
- combined = np_img * mask_3d + blurred * (1 - mask_3d)
23
- return Image.fromarray(combined.astype(np.uint8))
24
-
25
- # Dummy depth estimation function: replace with your actual depth estimation inference.
26
- def estimate_depth(img):
27
- np_img = np.array(img.convert("RGB"))
28
- h, w, _ = np_img.shape
29
- depth = np.tile(np.linspace(0, 1, h)[:, None], (1, w))
30
- return depth
31
-
32
- # Function to apply depth-based lens blur.
33
- def depth_based_blur(img, max_sigma=20):
34
- depth = estimate_depth(img)
35
- np_img = np.array(img.convert("RGB"))
36
- output = np.zeros_like(np_img)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- depth_norm = (depth - depth.min()) / (depth.max() - depth.min() + 1e-8)
 
 
 
 
 
 
39
 
40
- for i in range(np_img.shape[0]):
41
- sigma = max_sigma * depth_norm[i, 0]
42
- row = cv2.GaussianBlur(np_img[i:i+1, :, :], (0, 0), sigma)
43
- output[i, :, :] = row
44
- return Image.fromarray(output.astype(np.uint8))
45
 
46
- def process_image(img, effect):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  if effect == "Gaussian Blur Background":
48
- return gaussian_blur_background(img)
49
  elif effect == "Depth-based Lens Blur":
50
- return depth_based_blur(img)
51
  else:
52
- return img
 
 
 
 
 
53
 
54
- # Updated Gradio interface using the new API components.
55
  iface = gr.Interface(
56
  fn=process_image,
57
  inputs=[
@@ -60,7 +141,10 @@ iface = gr.Interface(
60
  ],
61
  outputs=gr.Image(type="pil", label="Output Image"),
62
  title="Blur Effects Demo",
63
- description="Upload an image and choose an effect to apply either a Gaussian Blur to the background or a Depth-based Lens Blur."
 
 
 
64
  )
65
 
66
  if __name__ == "__main__":
 
1
+ import io
2
  import numpy as np
3
+ import torch
4
+ from PIL import Image, ImageFilter
5
+ from torchvision import transforms
6
  import gradio as gr
7
+ from transformers import AutoModelForImageSegmentation, pipeline
8
+
9
+ # ----------------------------
10
+ # Global Setup and Model Loading
11
+ # ----------------------------
12
+
13
+ # Set device (GPU if available, else CPU)
14
+ device = "cuda" if torch.cuda.is_available() else "cpu"
15
+
16
+ # Load the segmentation model (RMBG-2.0)
17
+ segmentation_model = AutoModelForImageSegmentation.from_pretrained(
18
+ 'briaai/RMBG-2.0',
19
+ trust_remote_code=True
20
+ )
21
+ segmentation_model.to(device)
22
+ segmentation_model.eval()
23
+
24
+ # Define the image transformation for segmentation (resize to 512x512)
25
+ image_size = (512, 512)
26
+ segmentation_transform = transforms.Compose([
27
+ transforms.Resize(image_size),
28
+ transforms.ToTensor(),
29
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
30
+ ])
31
+
32
+ # Load the depth estimation pipeline (Depth-Anything)
33
+ depth_pipeline = pipeline("depth-estimation", model="depth-anything/Depth-Anything-V2-Small-hf")
34
+
35
+
36
+ # ----------------------------
37
+ # Processing Functions
38
+ # ----------------------------
39
+
40
+ def segment_and_blur_background(input_image: Image.Image, blur_radius: int = 15, threshold: float = 0.5) -> Image.Image:
41
+ """
42
+ Applies segmentation using the RMBG-2.0 model and then uses the segmentation mask
43
+ to composite a Gaussian-blurred background with a sharp foreground.
44
+ """
45
+ # Ensure the image is in RGB and get its original dimensions
46
+ image = input_image.convert("RGB")
47
+ orig_width, orig_height = image.size
48
+
49
+ # Preprocess image for segmentation
50
+ input_tensor = segmentation_transform(image).unsqueeze(0).to(device)
51
+
52
+ # Run inference on the segmentation model
53
+ with torch.no_grad():
54
+ preds = segmentation_model(input_tensor)[-1].sigmoid().cpu()
55
+ pred = preds[0].squeeze()
56
 
57
+ # Create a binary mask using the threshold
58
+ binary_mask = (pred > threshold).float()
59
+ mask_pil = transforms.ToPILImage()(binary_mask).convert("L")
60
+ # Convert grayscale mask to pure binary (0 or 255)
61
+ mask_pil = mask_pil.point(lambda p: 255 if p > 128 else 0)
62
+ # Resize mask back to the original image dimensions
63
+ mask_pil = mask_pil.resize((orig_width, orig_height), resample=Image.BILINEAR)
64
 
65
+ # Apply Gaussian blur to the entire image for background
66
+ blurred_image = image.filter(ImageFilter.GaussianBlur(blur_radius))
67
+ # Composite the original image (foreground) with the blurred image (background) using the mask
68
+ final_image = Image.composite(image, blurred_image, mask_pil)
69
+ return final_image
70
 
71
+
72
+ def depth_based_lens_blur(input_image: Image.Image, max_blur: float = 2, num_bands: int = 40, invert_depth: bool = False) -> Image.Image:
73
+ """
74
+ Applies a depth-based blur effect using a depth map produced by Depth-Anything.
75
+ The effect simulates a lens blur by applying different blur strengths in depth bands.
76
+ """
77
+ # Resize the input image to 512x512 for the depth estimation model
78
+ image_resized = input_image.resize((512, 512))
79
+
80
+ # Run depth estimation to obtain the depth map (as a PIL image)
81
+ results = depth_pipeline(image_resized)
82
+ depth_map_image = results['depth']
83
+
84
+ # Convert the depth map to a NumPy array and normalize to [0, 1]
85
+ depth_array = np.array(depth_map_image, dtype=np.float32)
86
+ d_min, d_max = depth_array.min(), depth_array.max()
87
+ depth_norm = (depth_array - d_min) / (d_max - d_min + 1e-8)
88
+ if invert_depth:
89
+ depth_norm = 1.0 - depth_norm
90
+
91
+ # Convert the resized image to RGBA for compositing
92
+ orig_rgba = image_resized.convert("RGBA")
93
+ final_image = orig_rgba.copy()
94
+
95
+ # Divide the normalized depth range into bands
96
+ band_edges = np.linspace(0, 1, num_bands + 1)
97
+ for i in range(num_bands):
98
+ band_min = band_edges[i]
99
+ band_max = band_edges[i + 1]
100
+ # Use the midpoint of the band to determine the blur strength.
101
+ mid = (band_min + band_max) / 2.0
102
+ blur_radius_band = (1 - mid) * max_blur
103
+
104
+ # Create a blurred version of the image for this band.
105
+ blurred_version = orig_rgba.filter(ImageFilter.GaussianBlur(blur_radius_band))
106
+
107
+ # Create a mask for pixels whose normalized depth falls within this band.
108
+ band_mask = ((depth_norm >= band_min) & (depth_norm < band_max)).astype(np.uint8) * 255
109
+ band_mask_pil = Image.fromarray(band_mask, mode="L")
110
+
111
+ # Composite the blurred version with the current final image using the band mask.
112
+ final_image = Image.composite(blurred_version, final_image, band_mask_pil)
113
+
114
+ # Return the final composited image as RGB.
115
+ return final_image.convert("RGB")
116
+
117
+
118
+ def process_image(input_image: Image.Image, effect: str) -> Image.Image:
119
+ """
120
+ Dispatch function to apply the selected effect:
121
+ - "Gaussian Blur Background": uses segmentation and Gaussian blur.
122
+ - "Depth-based Lens Blur": applies depth-based blur using the estimated depth map.
123
+ """
124
  if effect == "Gaussian Blur Background":
125
+ return segment_and_blur_background(input_image)
126
  elif effect == "Depth-based Lens Blur":
127
+ return depth_based_lens_blur(input_image)
128
  else:
129
+ return input_image
130
+
131
+
132
+ # ----------------------------
133
+ # Gradio Interface
134
+ # ----------------------------
135
 
 
136
  iface = gr.Interface(
137
  fn=process_image,
138
  inputs=[
 
141
  ],
142
  outputs=gr.Image(type="pil", label="Output Image"),
143
  title="Blur Effects Demo",
144
+ description=(
145
+ "Upload an image and choose an effect: "
146
+ "apply segmentation + Gaussian blurred background, or a depth-based lens blur effect."
147
+ )
148
  )
149
 
150
  if __name__ == "__main__":