Perghect commited on
Commit
21725cf
·
verified ·
1 Parent(s): 7626c11

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +118 -63
app.py CHANGED
@@ -5,7 +5,6 @@ Created on Thu Mar 27 13:56:42 2025
5
 
6
  @author: perghect
7
  """
8
-
9
  import gradio as gr
10
  import requests
11
  import io
@@ -15,6 +14,14 @@ from PIL import Image, ImageFilter
15
  from torchvision import transforms
16
  from transformers import AutoModelForImageSegmentation, AutoImageProcessor, AutoModelForDepthEstimation
17
 
 
 
 
 
 
 
 
 
18
  # Set device and precision
19
  device = 'cuda' if torch.cuda.is_available() else 'cpu'
20
  torch.set_float32_matmul_precision('high')
@@ -34,29 +41,32 @@ def load_image_from_link(url: str) -> Image.Image:
34
  # Gaussian Blur Functions
35
  def run_rmbg(image: Image.Image, threshold=0.5):
36
  """Runs the RMBG-2.0 model on the image and returns a binary mask."""
37
- image_size = (1024, 1024)
38
- transform_image = transforms.Compose([
39
- transforms.Resize(image_size),
40
- transforms.ToTensor(),
41
- transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
42
- ])
43
-
44
- input_images = transform_image(image).unsqueeze(0).to(device)
45
-
46
- with torch.no_grad():
47
- preds = rmbg_model(input_images)
48
- if isinstance(preds, list):
49
- mask_logits = preds[-1]
50
- else:
51
- raise ValueError(f"Unexpected output format: {type(preds)}")
52
-
53
- mask_prob = mask_logits.sigmoid().cpu()[0].squeeze()
54
- pred_pil = transforms.ToPILImage()(mask_prob)
55
- mask_pil = pred_pil.resize(image.size, resample=Image.BILINEAR)
56
-
57
- mask_np = np.array(mask_pil, dtype=np.uint8) / 255.0
58
- binary_mask = (mask_np > threshold).astype(np.uint8)
59
- return binary_mask
 
 
 
60
 
61
  def apply_background_blur(image: Image.Image, mask: np.ndarray, sigma: float = 15):
62
  """Applies a Gaussian blur to the background while keeping the foreground sharp."""
@@ -73,28 +83,33 @@ def apply_background_blur(image: Image.Image, mask: np.ndarray, sigma: float = 1
73
  # Lens Blur Functions
74
  def run_depth_estimation(image: Image.Image, target_size=(512, 512)):
75
  """Runs the Depth-Anything-V2-Small model and returns the depth map."""
76
- image_resized = image.resize(target_size, resample=Image.BILINEAR)
77
- inputs = depth_processor(images=image_resized, return_tensors="pt").to(device)
78
-
79
- with torch.no_grad():
80
- outputs = depth_model(**inputs)
81
- predicted_depth = outputs.predicted_depth
82
-
83
- prediction = torch.nn.functional.interpolate(
84
- predicted_depth.unsqueeze(1),
85
- size=image.size[::-1],
86
- mode="bicubic",
87
- align_corners=False,
88
- )
89
-
90
- depth_map = prediction.squeeze().cpu().numpy()
91
- depth_max = depth_map.max()
92
- depth_min = depth_map.min()
93
- depth_map = (depth_map - depth_min) / (depth_max - depth_min)
94
- depth_map = 1 - depth_map # Invert: higher values = farther
95
- return depth_map
96
-
97
- def apply_depth_based_blur(image: Image.Image, depth_map: np.ndarray, max_radius: float = 30, foreground_percentile: float = 5.0):
 
 
 
 
 
98
  """Applies a variable Gaussian blur based on the depth map."""
99
  image_np = np.array(image)
100
 
@@ -140,36 +155,76 @@ def apply_depth_based_blur(image: Image.Image, depth_map: np.ndarray, max_radius
140
  return output_image
141
 
142
  # Main Processing Function for Gradio
143
- def process_image(image, blur_type, sigma=15, max_radius=30, foreground_percentile=5.0):
144
- """Processes the image based on the selected blur type and parameters."""
145
  if image is None:
146
  return None, "Please upload an image."
147
 
148
- image = Image.fromarray(image).convert("RGB")
149
-
150
- if blur_type == "Gaussian Blur":
151
- mask = run_rmbg(image, threshold=0.5)
152
- output_image = apply_background_blur(image, mask, sigma=sigma)
153
- title = f"Gaussian Blur (sigma={sigma})"
154
- else: # Lens Blur
155
- depth_map = run_depth_estimation(image, target_size=(512, 512))
156
- output_image = apply_depth_based_blur(image, depth_map, max_radius=max_radius, foreground_percentile=foreground_percentile)
157
- title = f"Lens Blur (max_radius={max_radius}, foreground_percentile={foreground_percentile})"
 
 
 
 
 
 
 
 
 
 
 
158
 
159
  return output_image, title
160
 
161
- # Gradio Interface
162
  with gr.Blocks() as demo:
163
  gr.Markdown("# Image Blur Effects with Gaussian and Lens Blur")
164
- gr.Markdown("Upload an image and choose a blur effect. Adjust the parameters to customize the blur intensity.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  with gr.Row():
167
  image_input = gr.Image(label="Upload Image", type="numpy")
168
  with gr.Column():
169
  blur_type = gr.Radio(choices=["Gaussian Blur", "Lens Blur"], label="Blur Type", value="Gaussian Blur")
170
- sigma = gr.Slider(minimum=1, maximum=50, step=1, value=15, label="Gaussian Blur Sigma (for Gaussian Blur)")
171
- max_radius = gr.Slider(minimum=1, maximum=50, step=1, value=15, label="Max Blur Radius (for Lens Blur)")
172
- foreground_percentile = gr.Slider(minimum=1, maximum=50, step=1, value=30, label="Foreground Percentile (for Lens Blur)")
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
  process_button = gr.Button("Apply Blur")
175
  with gr.Row():
 
5
 
6
  @author: perghect
7
  """
 
8
  import gradio as gr
9
  import requests
10
  import io
 
14
  from torchvision import transforms
15
  from transformers import AutoModelForImageSegmentation, AutoImageProcessor, AutoModelForDepthEstimation
16
 
17
+ # Verify kornia and timm are available
18
+ try:
19
+ import kornia
20
+ import timm
21
+ print("kornia and timm are successfully installed!")
22
+ except ImportError as e:
23
+ print(f"Error: {e}")
24
+
25
  # Set device and precision
26
  device = 'cuda' if torch.cuda.is_available() else 'cpu'
27
  torch.set_float32_matmul_precision('high')
 
41
  # Gaussian Blur Functions
42
  def run_rmbg(image: Image.Image, threshold=0.5):
43
  """Runs the RMBG-2.0 model on the image and returns a binary mask."""
44
+ try:
45
+ image_size = (1024, 1024)
46
+ transform_image = transforms.Compose([
47
+ transforms.Resize(image_size),
48
+ transforms.ToTensor(),
49
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
50
+ ])
51
+
52
+ input_images = transform_image(image).unsqueeze(0).to(device)
53
+
54
+ with torch.no_grad():
55
+ preds = rmbg_model(input_images)
56
+ if isinstance(preds, list):
57
+ mask_logits = preds[-1]
58
+ else:
59
+ raise ValueError(f"Unexpected output format: {type(preds)}")
60
+
61
+ mask_prob = mask_logits.sigmoid().cpu()[0].squeeze()
62
+ pred_pil = transforms.ToPILImage()(mask_prob)
63
+ mask_pil = pred_pil.resize(image.size, resample=Image.BILINEAR)
64
+
65
+ mask_np = np.array(mask_pil, dtype=np.uint8) / 255.0
66
+ binary_mask = (mask_np > threshold).astype(np.uint8)
67
+ return binary_mask
68
+ except Exception as e:
69
+ raise Exception(f"Error in background removal: {str(e)}")
70
 
71
  def apply_background_blur(image: Image.Image, mask: np.ndarray, sigma: float = 15):
72
  """Applies a Gaussian blur to the background while keeping the foreground sharp."""
 
83
  # Lens Blur Functions
84
  def run_depth_estimation(image: Image.Image, target_size=(512, 512)):
85
  """Runs the Depth-Anything-V2-Small model and returns the depth map."""
86
+ try:
87
+ image_resized = image.resize(target_size, resample=Image.BILINEAR)
88
+ inputs = depth_processor(images=image_resized, return_tensors="pt").to(device)
89
+
90
+ with torch.no_grad():
91
+ outputs = depth_model(**inputs)
92
+ predicted_depth = outputs.predicted_depth
93
+
94
+ prediction = torch.nn.functional.interpolate(
95
+ predicted_depth.unsqueeze(1),
96
+ size=image.size[::-1],
97
+ mode="bicubic",
98
+ align_corners=False,
99
+ )
100
+
101
+ depth_map = prediction.squeeze().cpu().numpy()
102
+ depth_max = depth_map.max()
103
+ depth_min = depth_map.min()
104
+ if depth_max == depth_min:
105
+ depth_max = depth_min + 1e-6 # Avoid division by zero
106
+ depth_map = (depth_map - depth_min) / (depth_max - depth_min)
107
+ depth_map = 1 - depth_map # Invert: higher values = farther
108
+ return depth_map
109
+ except Exception as e:
110
+ raise Exception(f"Error in depth estimation: {str(e)}")
111
+
112
+ def apply_depth_based_blur(image: Image.Image, depth_map: np.ndarray, max_radius: float = 15, foreground_percentile: float = 30):
113
  """Applies a variable Gaussian blur based on the depth map."""
114
  image_np = np.array(image)
115
 
 
155
  return output_image
156
 
157
  # Main Processing Function for Gradio
158
+ def process_image(image, blur_type, sigma=15, max_radius=15, foreground_percentile=30):
159
+ """Processes the image based on the selected blur type."""
160
  if image is None:
161
  return None, "Please upload an image."
162
 
163
+ try:
164
+ image = Image.fromarray(image).convert("RGB")
165
+ except Exception as e:
166
+ return None, f"Error processing image: {str(e)}"
167
+
168
+ # Resize image if too large
169
+ max_size = (1024, 1024)
170
+ if image.size[0] > max_size[0] or image.size[1] > max_size[1]:
171
+ image.thumbnail(max_size, Image.Resampling.LANCZOS)
172
+
173
+ try:
174
+ if blur_type == "Gaussian Blur":
175
+ mask = run_rmbg(image, threshold=0.5)
176
+ output_image = apply_background_blur(image, mask, sigma=sigma)
177
+ title = f"Gaussian Blur (sigma={sigma})"
178
+ else: # Lens Blur
179
+ depth_map = run_depth_estimation(image, target_size=(512, 512))
180
+ output_image = apply_depth_based_blur(image, depth_map, max_radius=max_radius, foreground_percentile=foreground_percentile)
181
+ title = f"Lens Blur (max_radius={max_radius}, foreground_percentile={foreground_percentile})"
182
+ except Exception as e:
183
+ return None, f"Error applying blur: {str(e)}"
184
 
185
  return output_image, title
186
 
187
+ # Gradio Interface with Conditional Parameter Display
188
  with gr.Blocks() as demo:
189
  gr.Markdown("# Image Blur Effects with Gaussian and Lens Blur")
190
+ gr.Markdown("""
191
+ This app applies blur effects to your images. Follow these steps to use it:
192
+
193
+ **Note**: This app is hosted on Hugging Face Spaces’ free tier and may go to "Sleeping" mode after 48 hours of inactivity. If it doesn’t load immediately, please wait a few seconds while it wakes up.
194
+
195
+ 1. **Upload an Image**: Click the "Upload Image" box to upload an image from your device.
196
+ 2. **Choose a Blur Type**:
197
+ - **Gaussian Blur**: Applies a uniform blur to the background, keeping the foreground sharp. Adjust the sigma parameter to control blur intensity.
198
+ - **Lens Blur**: Applies a depth-based blur, simulating a depth-of-field effect (closer objects are sharp, farther objects are blurred). Adjust the max radius and foreground percentile to fine-tune the effect.
199
+ 3. **Adjust Parameters**:
200
+ - For Gaussian Blur, use the "Gaussian Blur Sigma" slider to control blur intensity (higher values = more blur).
201
+ - For Lens Blur, use the "Max Blur Radius" slider to control the maximum blur intensity and the "Foreground Percentile" slider to adjust the depth threshold for the foreground.
202
+ 4. **Apply the Blur**: Click the "Apply Blur" button to process the image.
203
+ 5. **View the Result**: The processed image will appear in the "Output Image" box, along with a description of the effect applied.
204
+
205
+ **Example**: Try uploading an image with a clear foreground and background (e.g., a person in front of a landscape) to see the effects in action.
206
+ """)
207
 
208
  with gr.Row():
209
  image_input = gr.Image(label="Upload Image", type="numpy")
210
  with gr.Column():
211
  blur_type = gr.Radio(choices=["Gaussian Blur", "Lens Blur"], label="Blur Type", value="Gaussian Blur")
212
+ sigma = gr.Slider(minimum=1, maximum=50, step=1, value=15, label="Gaussian Blur Sigma", visible=True)
213
+ max_radius = gr.Slider(minimum=1, maximum=50, step=1, value=15, label="Max Blur Radius (for Lens Blur)", visible=False)
214
+ foreground_percentile = gr.Slider(minimum=1, maximum=50, step=1, value=30, label="Foreground Percentile (for Lens Blur)", visible=False)
215
+
216
+ # Update visibility of parameters based on blur type
217
+ def update_visibility(blur_type):
218
+ if blur_type == "Gaussian Blur":
219
+ return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)
220
+ else: # Lens Blur
221
+ return gr.update(visible=False), gr.update(visible=True), gr.update(visible=True)
222
+
223
+ blur_type.change(
224
+ fn=update_visibility,
225
+ inputs=blur_type,
226
+ outputs=[sigma, max_radius, foreground_percentile]
227
+ )
228
 
229
  process_button = gr.Button("Apply Blur")
230
  with gr.Row():