spacelord16 commited on
Commit
90e02bf
·
verified ·
1 Parent(s): 20d7337

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +216 -0
app.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import numpy as np
4
+ from PIL import Image
5
+ import cv2
6
+ from transformers import pipeline
7
+ import os
8
+
9
+ # Load models
10
+ def load_models():
11
+ # Load segmentation model
12
+ segmenter = pipeline("image-segmentation", model="facebook/maskformer-swin-base-ade")
13
+
14
+ # Load depth estimation model
15
+ depth_estimator = pipeline("depth-estimation", model="intel/dpt-large")
16
+
17
+ return segmenter, depth_estimator
18
+
19
+ # Create binary mask
20
+ def create_binary_mask(segmentation_results, image_np, target_class="person"):
21
+ # Initialize empty mask with black background
22
+ mask = np.zeros((image_np.shape[0], image_np.shape[1]), dtype=np.uint8)
23
+
24
+ # Look for segments with target class
25
+ found = False
26
+ for segment in segmentation_results:
27
+ if target_class.lower() in segment['label'].lower():
28
+ # Convert segment mask to numpy array
29
+ segment_mask = np.array(segment['mask'])
30
+ # Convert grayscale to binary (255 for white)
31
+ binary_mask = np.where(segment_mask > 0.5, 255, 0).astype(np.uint8)
32
+ # Add to overall mask
33
+ mask = cv2.bitwise_or(mask, binary_mask)
34
+ found = True
35
+
36
+ # If target class not found, use the largest segment
37
+ if not found:
38
+ largest_area = 0
39
+ largest_mask = None
40
+
41
+ for segment in segmentation_results:
42
+ segment_mask = np.array(segment['mask'])
43
+ binary_mask = np.where(segment_mask > 0.5, 255, 0).astype(np.uint8)
44
+ area = np.sum(binary_mask > 0)
45
+
46
+ if area > largest_area:
47
+ largest_area = area
48
+ largest_mask = binary_mask
49
+
50
+ if largest_mask is not None:
51
+ mask = largest_mask
52
+
53
+ return mask
54
+
55
+ # Apply Gaussian blur to background
56
+ def apply_gaussian_blur_to_background(image_np, mask, sigma=15):
57
+ # Create a blurred version of the entire image
58
+ blurred_image = cv2.GaussianBlur(image_np, (0, 0), sigma)
59
+
60
+ # Ensure mask is in correct format
61
+ if len(mask.shape) == 3 and mask.shape[2] == 3:
62
+ mask_gray = cv2.cvtColor(mask, cv2.COLOR_RGB2GRAY)
63
+ else:
64
+ mask_gray = mask.copy()
65
+
66
+ # Normalize mask to range 0-1
67
+ if mask_gray.max() > 1:
68
+ mask_gray = mask_gray / 255.0
69
+
70
+ # Expand mask dimensions for elementwise multiplication
71
+ mask_3channel = np.stack([mask_gray] * 3, axis=2)
72
+
73
+ # Combine original foreground with blurred background
74
+ result = image_np * mask_3channel + blurred_image * (1 - mask_3channel)
75
+ result = result.astype(np.uint8)
76
+
77
+ return result
78
+
79
+ # Normalize depth map
80
+ def normalize_depth_map(depth_map):
81
+ depth_min = depth_map.min()
82
+ depth_max = depth_map.max()
83
+ normalized_depth = (depth_map - depth_min) / (depth_max - depth_min)
84
+ return normalized_depth
85
+
86
+ # Apply depth-based blur
87
+ def apply_depth_based_blur(image, depth_map, max_blur=25):
88
+ # Create output image
89
+ result = np.zeros_like(image)
90
+
91
+ # Apply blur with intensity proportional to depth
92
+ for blur_size in range(1, max_blur + 1, 2): # Odd numbers for kernel size
93
+ # Create a mask for pixels that should receive this blur level
94
+ if blur_size == 1:
95
+ mask = (depth_map <= blur_size / max_blur).astype(np.float32)
96
+ else:
97
+ lower_bound = (blur_size - 2) / max_blur
98
+ upper_bound = blur_size / max_blur
99
+ mask = ((depth_map > lower_bound) & (depth_map <= upper_bound)).astype(np.float32)
100
+
101
+ # Skip if no pixels in this range
102
+ if not np.any(mask):
103
+ continue
104
+
105
+ # Apply Gaussian blur with current kernel size
106
+ if blur_size > 1:
107
+ blurred = cv2.GaussianBlur(image, (blur_size, blur_size), 0)
108
+ mask_3d = np.stack([mask] * 3, axis=2)
109
+ result += (blurred * mask_3d).astype(np.uint8)
110
+ else:
111
+ mask_3d = np.stack([mask] * 3, axis=2)
112
+ result += (image * mask_3d).astype(np.uint8)
113
+
114
+ return result
115
+
116
+ # Process function for Gradio
117
+ def process_image(input_image, blur_effect_type, blur_strength, target_class):
118
+ # Load models if not already loaded
119
+ if not hasattr(process_image, "models_loaded"):
120
+ process_image.segmenter, process_image.depth_estimator = load_models()
121
+ process_image.models_loaded = True
122
+
123
+ # Convert to numpy array
124
+ image_np = np.array(input_image)
125
+
126
+ # Process based on selected effect
127
+ if blur_effect_type == "Gaussian Background Blur":
128
+ # Segment the image
129
+ segmentation_results = process_image.segmenter(input_image)
130
+
131
+ # Create binary mask
132
+ binary_mask = create_binary_mask(segmentation_results, image_np, target_class)
133
+
134
+ # Apply Gaussian blur to background
135
+ result = apply_gaussian_blur_to_background(image_np, binary_mask, sigma=blur_strength)
136
+
137
+ return result
138
+
139
+ elif blur_effect_type == "Depth-Based Lens Blur":
140
+ # Resize for depth estimation
141
+ depth_input = cv2.resize(image_np, (512, 512))
142
+
143
+ # Get depth map
144
+ depth_result = process_image.depth_estimator(depth_input)
145
+ depth_map = np.array(depth_result["depth"])
146
+
147
+ # Normalize depth map
148
+ normalized_depth = normalize_depth_map(depth_map)
149
+
150
+ # Apply depth-based blur
151
+ result = apply_depth_based_blur(depth_input, normalized_depth, max_blur=blur_strength)
152
+
153
+ # Resize back to original dimensions if needed
154
+ if image_np.shape[:2] != (512, 512):
155
+ result = cv2.resize(result, (image_np.shape[1], image_np.shape[0]))
156
+
157
+ return result
158
+
159
+ else:
160
+ return image_np # Return original if no effect selected
161
+
162
+ # Create Gradio interface
163
+ demo = gr.Blocks(title="Image Blur Effects")
164
+
165
+ with demo:
166
+ gr.Markdown("# Image Blur Effects using Segmentation and Depth Estimation")
167
+ gr.Markdown("Upload an image to apply different blur effects. For best results, use an image with a clear foreground subject.")
168
+
169
+ with gr.Row():
170
+ input_image = gr.Image(label="Input Image", type="pil")
171
+ output_image = gr.Image(label="Output Image")
172
+
173
+ with gr.Row():
174
+ blur_effect_type = gr.Radio(
175
+ ["Gaussian Background Blur", "Depth-Based Lens Blur"],
176
+ label="Blur Effect Type",
177
+ value="Gaussian Background Blur"
178
+ )
179
+
180
+ blur_strength = gr.Slider(
181
+ minimum=5,
182
+ maximum=45,
183
+ step=2,
184
+ value=15,
185
+ label="Blur Strength"
186
+ )
187
+
188
+ target_class = gr.Textbox(
189
+ label="Target Class (for segmentation)",
190
+ value="person",
191
+ placeholder="e.g., person, cat, dog"
192
+ )
193
+
194
+ process_btn = gr.Button("Apply Effect")
195
+ process_btn.click(
196
+ fn=process_image,
197
+ inputs=[input_image, blur_effect_type, blur_strength, target_class],
198
+ outputs=output_image
199
+ )
200
+
201
+ gr.Markdown("""
202
+ ## How to use:
203
+ 1. Upload an image with a clear foreground subject
204
+ 2. Choose a blur effect type:
205
+ - **Gaussian Background Blur**: Blurs the background while keeping the foreground sharp
206
+ - **Depth-Based Lens Blur**: Creates a realistic lens blur effect based on depth estimation
207
+ 3. Adjust the blur strength
208
+ 4. For Gaussian Background Blur, specify the target class to identify the foreground (e.g., person, cat, dog)
209
+ 5. Click "Apply Effect"
210
+ """)
211
+
212
+ # Initialize models
213
+ segmenter, depth_estimator = load_models()
214
+
215
+ # Launch the app
216
+ demo.launch()