SOSSY commited on
Commit
52f5763
·
verified ·
1 Parent(s): 2c712f7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +228 -81
app.py CHANGED
@@ -1,88 +1,235 @@
1
  import gradio as gr
2
  from transformers import pipeline
3
- from PIL import Image
4
  import numpy as np
5
- from scipy.ndimage import gaussian_filter
6
- import matplotlib.pyplot as plt
7
-
8
- # Load the depth estimation model
9
- depth_estimator = pipeline("depth-estimation", model="Intel/zoedepth-nyu-kitti")
10
-
11
- def process_image(input_image):
12
- # Convert Gradio input (numpy array) to PIL Image
13
- input_image = Image.fromarray(input_image.astype('uint8'), 'RGB')
14
-
15
- # Perform depth estimation
16
- depth_results = depth_estimator(input_image)
17
- depth_map = depth_results["depth"]
18
-
19
- # Convert depth map to numpy array and normalize to [0, 1]
20
- depth_array = np.array(depth_map)
21
- normalized_depth = (depth_array - np.min(depth_array)) / (np.max(depth_array) - np.min(depth_array))
22
-
23
- # Convert input image to numpy array
24
- img_array = np.array(input_image)
25
-
26
- # Create variable blur effect
27
- max_blur = 5.0 # Maximum blur radius
28
- min_blur = 0.5 # Minimum blur radius to avoid completely sharp areas
29
- n_steps = 10 # Number of blur levels
30
-
31
- # Create output array
32
- blurred_array = np.zeros_like(img_array, dtype=np.float32)
33
-
34
- # Apply variable blur by processing the image with multiple blur levels
35
- for i in range(n_steps):
36
- sigma = min_blur + (max_blur - min_blur) * i / (n_steps - 1)
37
- # Apply Gaussian blur with current sigma to the whole image
38
- blurred_r = gaussian_filter(img_array[:,:,0], sigma=sigma)
39
- blurred_g = gaussian_filter(img_array[:,:,1], sigma=sigma)
40
- blurred_b = gaussian_filter(img_array[:,:,2], sigma=sigma)
41
- blurred_temp = np.stack([blurred_r, blurred_g, blurred_b], axis=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
- # Create a mask for this blur level
44
- lower_bound = i / n_steps
45
- upper_bound = (i + 1) / n_steps
46
- mask = (normalized_depth >= lower_bound) & (normalized_depth < upper_bound)
47
- mask = mask[..., np.newaxis] # Add channel dimension
48
 
49
- # Apply this blur level to the appropriate regions
50
- blurred_array = np.where(mask, blurred_temp, blurred_array)
51
-
52
- # Convert back to uint8
53
- blurred_image = Image.fromarray(blurred_array.astype('uint8'))
54
-
55
- # Create side-by-side visualization
56
- fig, axes = plt.subplots(1, 3, figsize=(15, 5))
57
- axes[0].imshow(input_image)
58
- axes[0].set_title("Input Image")
59
- axes[0].axis("off")
60
-
61
- axes[1].imshow(depth_map, cmap="gray")
62
- axes[1].set_title("Depth Map")
63
- axes[1].axis("off")
64
-
65
- axes[2].imshow(blurred_image)
66
- axes[2].set_title("Variable Blur Output")
67
- axes[2].axis("off")
68
-
69
- plt.tight_layout()
70
-
71
- # Save the figure to a temporary file or buffer to display in Gradio
72
- output_path = "output.png"
73
- plt.savefig(output_path, bbox_inches='tight')
74
- plt.close()
75
-
76
- return output_path
77
-
78
- # Define Gradio interface
79
- interface = gr.Interface(
80
- fn=process_image,
81
- inputs=gr.Image(label="Upload an Image"),
82
- outputs=gr.Image(label="Processed Output"),
83
- title="Depth-Based Variable Blur App",
84
- description="Upload an image to apply a variable blur effect based on depth estimation."
85
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  # Launch the app
88
- interface.launch()
 
1
  import gradio as gr
2
  from transformers import pipeline
3
+ from PIL import Image, ImageFilter, ImageOps
4
  import numpy as np
5
+ import requests
6
+ import cv2
7
+
8
+ # Dictionary of available segmentation models
9
+ SEGMENTATION_MODELS = {
10
+ "NVIDIA SegFormer (Cityscapes)": "nvidia/segformer-b1-finetuned-cityscapes-1024-1024",
11
+ "NVIDIA SegFormer (ADE20K)": "nvidia/segformer-b0-finetuned-ade-512-512",
12
+ "Facebook MaskFormer (COCO)": "facebook/maskformer-swin-base-ade",
13
+ "OneFormer (COCO)": "shi-labs/oneformer_coco_swin_large",
14
+ "NVIDIA SegFormer (B5)": "nvidia/segformer-b5-finetuned-cityscapes-1024-1024"
15
+ }
16
+
17
+ # Dictionary of available depth estimation models
18
+ DEPTH_MODELS = {
19
+ "Intel ZoeDepth (NYU-KITTI)": "Intel/zoedepth-nyu-kitti",
20
+ "DPT (Large)": "Intel/dpt-large",
21
+ "DPT (Hybrid)": "Intel/dpt-hybrid-midas",
22
+ "GLPDepth": "vinvino02/glpn-nyu"
23
+ }
24
+
25
+ # Initialize model placeholders
26
+ segmentation_model = None
27
+ depth_estimator = None
28
+
29
+ def load_segmentation_model(model_name):
30
+ """Load the selected segmentation model"""
31
+ global segmentation_model
32
+ model_path = SEGMENTATION_MODELS[model_name]
33
+ print(f"Loading segmentation model: {model_path}...")
34
+ segmentation_model = pipeline("image-segmentation", model=model_path)
35
+ return f"Loaded segmentation model: {model_name}"
36
+
37
+ def load_depth_model(model_name):
38
+ """Load the selected depth estimation model"""
39
+ global depth_estimator
40
+ model_path = DEPTH_MODELS[model_name]
41
+ print(f"Loading depth estimation model: {model_path}...")
42
+ depth_estimator = pipeline("depth-estimation", model=model_path)
43
+ return f"Loaded depth model: {model_name}"
44
+
45
+ def lens_blur(image, radius):
46
+ """
47
+ Apply a more realistic lens blur (bokeh effect) using OpenCV.
48
+ """
49
+ if radius < 1:
50
+ return image
51
+
52
+ # Convert PIL image to OpenCV format
53
+ img_np = np.array(image)
54
+
55
+ # Create a circular kernel for the bokeh effect
56
+ kernel_size = 2 * radius + 1
57
+ kernel = np.zeros((kernel_size, kernel_size), dtype=np.float32)
58
+ center = radius
59
+ for i in range(kernel_size):
60
+ for j in range(kernel_size):
61
+ # Create circular kernel
62
+ if np.sqrt((i - center) ** 2 + (j - center) ** 2) <= radius:
63
+ kernel[i, j] = 1.0
64
+
65
+ # Normalize the kernel
66
+ if kernel.sum() != 0:
67
+ kernel = kernel / kernel.sum()
68
+
69
+ # Apply the filter to each channel separately
70
+ channels = cv2.split(img_np)
71
+ blurred_channels = []
72
+
73
+ for channel in channels:
74
+ blurred_channel = cv2.filter2D(channel, -1, kernel)
75
+ blurred_channels.append(blurred_channel)
76
+
77
+ # Merge the channels back
78
+ blurred_img = cv2.merge(blurred_channels)
79
+
80
+ # Convert back to PIL image
81
+ return Image.fromarray(blurred_img)
82
+
83
+ def process_image(input_image, method, blur_intensity, blur_type):
84
+ """
85
+ Process the input image using one of two methods:
86
+
87
+ 1. Segmented Background Blur:
88
+ - Uses segmentation to extract a foreground mask.
89
+ - Applies the selected blur (Gaussian or Lens) to the background.
90
+ - Composites the final image.
91
+
92
+ 2. Depth-based Variable Blur:
93
+ - Uses depth estimation to generate a depth map.
94
+ - Normalizes the depth map to be used as a blending mask.
95
+ - Blends a fully blurred version (using the selected blur) with the original image.
96
+
97
+ Returns:
98
+ - output_image: final composited image.
99
+ - mask_image: the mask used (binary for segmentation, normalized depth for depth-based).
100
+ """
101
+ # Check if models are loaded
102
+ if segmentation_model is None or depth_estimator is None:
103
+ return input_image, input_image.convert("L")
104
+
105
+ # Ensure image is in RGB mode
106
+ input_image = input_image.convert("RGB")
107
+
108
+ # Select blur function based on blur_type
109
+ if blur_type == "Gaussian Blur":
110
+ blur_fn = lambda img, rad: img.filter(ImageFilter.GaussianBlur(radius=rad))
111
+ elif blur_type == "Lens Blur":
112
+ blur_fn = lens_blur
113
+ else:
114
+ blur_fn = lambda img, rad: img.filter(ImageFilter.GaussianBlur(radius=rad))
115
+
116
+ if method == "Segmented Background Blur":
117
+ # Use segmentation to obtain a foreground mask.
118
+ results = segmentation_model(input_image)
119
+ # Assume the last result is the main foreground object.
120
+ foreground_mask = results[-1]["mask"]
121
+ # Ensure the mask is grayscale.
122
+ foreground_mask = foreground_mask.convert("L")
123
+ # Threshold to create a binary mask.
124
+ binary_mask = foreground_mask.point(lambda p: 255 if p > 128 else 0)
125
 
126
+ # Blur the background using the selected blur function.
127
+ blurred_background = blur_fn(input_image, blur_intensity)
 
 
 
128
 
129
+ # Composite the final image: keep foreground and use blurred background elsewhere.
130
+ output_image = Image.composite(input_image, blurred_background, binary_mask)
131
+ mask_image = binary_mask
132
+
133
+ elif method == "Depth-based Variable Blur":
134
+ # Generate depth map.
135
+ depth_results = depth_estimator(input_image)
136
+ depth_map = depth_results["depth"]
137
+
138
+ # Convert depth map to numpy array and normalize to [0, 255]
139
+ depth_array = np.array(depth_map).astype(np.float32)
140
+ norm = (depth_array - depth_array.min()) / (depth_array.max() - depth_array.min() + 1e-8)
141
+ normalized_depth = (norm * 255).astype(np.uint8)
142
+ mask_image = Image.fromarray(normalized_depth)
143
+
144
+ # Create fully blurred version using the selected blur function.
145
+ blurred_image = blur_fn(input_image, blur_intensity)
146
+
147
+ # Convert images to arrays for blending.
148
+ orig_np = np.array(input_image).astype(np.float32)
149
+ blur_np = np.array(blurred_image).astype(np.float32)
150
+ # Reshape mask for broadcasting.
151
+ alpha = normalized_depth[..., np.newaxis] / 255.0
152
+
153
+ # Blend pixels: 0 = original; 1 = fully blurred.
154
+ blended_np = (1 - alpha) * orig_np + alpha * blur_np
155
+ blended_np = np.clip(blended_np, 0, 255).astype(np.uint8)
156
+ output_image = Image.fromarray(blended_np)
157
+
158
+ else:
159
+ output_image = input_image
160
+ mask_image = input_image.convert("L")
161
+
162
+ return output_image, mask_image
163
+
164
+ # Build a Gradio interface
165
+ with gr.Blocks() as demo:
166
+ gr.Markdown("## Image Processing App: Segmentation & Depth-based Blur")
167
+
168
+ with gr.Tab("Model Selection"):
169
+ with gr.Row():
170
+ with gr.Column():
171
+ seg_model_dropdown = gr.Dropdown(
172
+ label="Segmentation Model",
173
+ choices=list(SEGMENTATION_MODELS.keys()),
174
+ value=list(SEGMENTATION_MODELS.keys())[0]
175
+ )
176
+ seg_model_load_btn = gr.Button("Load Segmentation Model")
177
+ seg_model_status = gr.Textbox(label="Status", value="No model loaded")
178
+
179
+ with gr.Column():
180
+ depth_model_dropdown = gr.Dropdown(
181
+ label="Depth Estimation Model",
182
+ choices=list(DEPTH_MODELS.keys()),
183
+ value=list(DEPTH_MODELS.keys())[0]
184
+ )
185
+ depth_model_load_btn = gr.Button("Load Depth Model")
186
+ depth_model_status = gr.Textbox(label="Status", value="No model loaded")
187
+
188
+ with gr.Tab("Image Processing"):
189
+ with gr.Row():
190
+ with gr.Column():
191
+ input_image = gr.Image(label="Input Image", type="pil")
192
+ method = gr.Radio(label="Processing Method",
193
+ choices=["Segmented Background Blur", "Depth-based Variable Blur"],
194
+ value="Segmented Background Blur")
195
+ blur_intensity = gr.Slider(label="Blur Intensity (Maximum Blur Radius)",
196
+ minimum=1, maximum=30, step=1, value=15)
197
+ blur_type = gr.Dropdown(label="Blur Type",
198
+ choices=["Gaussian Blur", "Lens Blur"],
199
+ value="Gaussian Blur")
200
+ run_button = gr.Button("Process Image")
201
+ with gr.Column():
202
+ output_image = gr.Image(label="Output Image")
203
+ mask_output = gr.Image(label="Mask")
204
+
205
+ # Set up event handlers
206
+ seg_model_load_btn.click(
207
+ fn=load_segmentation_model,
208
+ inputs=[seg_model_dropdown],
209
+ outputs=[seg_model_status]
210
+ )
211
+
212
+ depth_model_load_btn.click(
213
+ fn=load_depth_model,
214
+ inputs=[depth_model_dropdown],
215
+ outputs=[depth_model_status]
216
+ )
217
+
218
+ run_button.click(
219
+ fn=process_image,
220
+ inputs=[input_image, method, blur_intensity, blur_type],
221
+ outputs=[output_image, mask_output]
222
+ )
223
+
224
+ # Load default models on startup
225
+ demo.load(
226
+ fn=lambda: (
227
+ load_segmentation_model(list(SEGMENTATION_MODELS.keys())[0]),
228
+ load_depth_model(list(DEPTH_MODELS.keys())[0])
229
+ ),
230
+ inputs=None,
231
+ outputs=[seg_model_status, depth_model_status]
232
+ )
233
 
234
  # Launch the app
235
+ demo.launch()