odeodhar commited on
Commit
b47a3a8
·
verified ·
1 Parent(s): 299f78e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +212 -0
app.py ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from unicodedata import normalize
2
+
3
+ import gradio as gr
4
+ import numpy as np
5
+ import matplotlib.pyplot as plt
6
+ from PIL import Image, ImageFilter
7
+ from transformers import SegformerImageProcessor, SegformerForSemanticSegmentation
8
+ from scipy.ndimage import gaussian_filter
9
+ import torch
10
+ import requests
11
+ from io import BytesIO
12
+ import cv2
13
+ import warnings
14
+ warnings.filterwarnings('ignore')
15
+ from transformers import DPTImageProcessor, DPTForDepthEstimation, AutoImageProcessor
16
+
17
+ model_cache = {
18
+ "seg_name": None, "seg_proc": None, "seg_model": None,
19
+ "depth_name": None, "depth_proc": None, "depth_model": None
20
+ }
21
+
22
+ MODEL_CONFIG = {
23
+ "segmentation": {
24
+ "Segformer (B0)": "nvidia/segformer-b0-finetuned-ade-512-512",
25
+ "Segformer (B5)": "nvidia/segformer-b5-finetuned-ade-640-640",
26
+ },
27
+ "depth": {
28
+ "DPT-Large": "Intel/dpt-large",
29
+ "Facebook-DPT-Dinov2": "facebook/dpt-dinov2-small-nyu",
30
+ }
31
+ }
32
+
33
+ def get_seg_model(model_name):
34
+ global model_cache
35
+ repo_id = MODEL_CONFIG["segmentation"][model_name]
36
+ if model_cache["seg_name"] != model_name:
37
+ print(f"Switching segmentation model to {model_name}...")
38
+ model_cache["seg_proc"] = SegformerImageProcessor.from_pretrained(repo_id)
39
+ model_cache["seg_model"] = SegformerForSemanticSegmentation.from_pretrained(repo_id)
40
+ model_cache["seg_name"] = model_name
41
+ return model_cache["seg_proc"], model_cache["seg_model"]
42
+
43
+ def get_depth_model(model_name):
44
+ global model_cache
45
+ repo_id = MODEL_CONFIG["depth"][model_name]
46
+ if model_cache["depth_name"] != model_name:
47
+ print(f"Switching depth model to {model_name}...")
48
+ model_cache["depth_proc"] = DPTImageProcessor.from_pretrained(repo_id)
49
+ model_cache["depth_model"] = DPTForDepthEstimation.from_pretrained(repo_id)
50
+ model_cache["depth_name"] = model_name
51
+ return model_cache["depth_proc"], model_cache["depth_model"]
52
+
53
+ def preprocess_image(image, target_size=512):
54
+ if isinstance(image, np.ndarray):
55
+ image = Image.fromarray(image)
56
+ if image.mode != 'RGB':
57
+ image = image.convert('RGB')
58
+ return image.resize((target_size, target_size), Image.Resampling.LANCZOS)
59
+
60
+ def segment_human(image, processor, model):
61
+ inputs = processor(images=image, return_tensors="pt")
62
+ with torch.no_grad():
63
+ outputs = model(**inputs)
64
+ upsampled = torch.nn.functional.interpolate(
65
+ outputs.logits, size=(512, 512), mode="bilinear", align_corners=False
66
+ )
67
+ pred_seg = upsampled.argmax(dim=1)[0].cpu().numpy()
68
+ # Note: Label 12 is 'person' in ADE20k dataset
69
+ return (pred_seg == 12).astype(np.uint8) * 255
70
+
71
+ def apply_background_blur(image, mask, sigma=15):
72
+ img_array = np.array(image).astype(np.float32)
73
+ mask_normalized = mask.astype(np.float32) / 255.0
74
+ mask_smooth = gaussian_filter(mask_normalized, sigma=2)
75
+ mask_smooth = np.clip(mask_smooth, 0, 1)
76
+
77
+ blurred_array = np.zeros_like(img_array)
78
+ for i in range(3):
79
+ blurred_array[:, :, i] = gaussian_filter(img_array[:, :, i], sigma=sigma)
80
+
81
+ mask_3d = np.stack([mask_smooth] * 3, axis=2)
82
+ result = (img_array * mask_3d + blurred_array * (1 - mask_3d)).astype(np.uint8)
83
+ return Image.fromarray(result)
84
+
85
+ def estimate_depth(image, processor, model, invert):
86
+ inputs = processor(images=image, return_tensors="pt")
87
+ with torch.no_grad():
88
+ outputs = model(**inputs)
89
+ prediction = torch.nn.functional.interpolate(
90
+ outputs.predicted_depth.unsqueeze(1), size=(512, 512), mode="bicubic", align_corners=False,
91
+ )
92
+ depth_map = prediction.squeeze().cpu().numpy()
93
+ depth_min, depth_max = depth_map.min(), depth_map.max()
94
+ normalized = (depth_map - depth_min) / (depth_max - depth_min)
95
+ if invert == True:
96
+ normalized = 1.0 - normalized
97
+ return normalized * 15.0
98
+
99
+ def apply_lens_blur(image, depth_map, max_sigma=15):
100
+ img_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR).astype(np.float32)
101
+
102
+ # Create blur pyramid
103
+ num_levels = 10
104
+ blur_pyramid = []
105
+
106
+ for i in range(num_levels):
107
+ sigma = (i / (num_levels - 1)) * max_sigma
108
+ if sigma < 0.5:
109
+ blur_pyramid.append(img_cv.copy())
110
+ else:
111
+ ksize = int(2 * np.ceil(3 * sigma) + 1)
112
+ if ksize % 2 == 0:
113
+ ksize += 1
114
+ blurred = cv2.GaussianBlur(img_cv, (ksize, ksize), sigma)
115
+ blur_pyramid.append(blurred)
116
+
117
+ # Apply variable blur based on depth
118
+ depth_norm = depth_map / 15.0
119
+ output = np.zeros_like(img_cv)
120
+
121
+ depth_scaled = depth_norm * (num_levels - 1)
122
+ level_low = np.floor(depth_scaled).astype(np.int32)
123
+ level_high = np.ceil(depth_scaled).astype(np.int32)
124
+ level_low = np.clip(level_low, 0, num_levels - 1)
125
+ level_high = np.clip(level_high, 0, num_levels - 1)
126
+
127
+ weight = depth_scaled - level_low
128
+ weight = np.expand_dims(weight, axis=2)
129
+
130
+ for y in range(img_cv.shape[0]):
131
+ for x in range(img_cv.shape[1]):
132
+ ll = level_low[y, x]
133
+ lh = level_high[y, x]
134
+ w = weight[y, x, 0]
135
+
136
+ if ll == lh:
137
+ output[y, x] = blur_pyramid[ll][y, x]
138
+ else:
139
+ output[y, x] = (1 - w) * blur_pyramid[ll][y, x] + w * blur_pyramid[lh][y, x]
140
+
141
+ output = np.clip(output, 0, 255).astype(np.uint8)
142
+ output_rgb = cv2.cvtColor(output, cv2.COLOR_BGR2RGB)
143
+ return Image.fromarray(output_rgb)
144
+
145
+ def process_gaussian_blur(image, sigma, model_choice):
146
+ if image is None: return None, "Upload an image!"
147
+ try:
148
+ proc, model = get_seg_model(model_choice)
149
+ img = preprocess_image(image)
150
+ mask = segment_human(img, proc, model)
151
+ result = apply_background_blur(img, mask, sigma)
152
+ return result, f"Applied {model_choice} with σ={sigma}"
153
+ except Exception as e:
154
+ return None, f"Error: {str(e)}"
155
+
156
+ def process_lens_blur(image, max_sigma, model_choice):
157
+ if image is None: return None, None, "Upload an image!"
158
+ try:
159
+ proc, model = get_depth_model(model_choice)
160
+ if model_choice == "Facebook-DPT-Dinov2":
161
+ invert = False
162
+ else:
163
+ invert = True
164
+ img = preprocess_image(image)
165
+ depth = estimate_depth(img, proc, model, invert)
166
+ result = apply_lens_blur(img, depth, max_sigma)
167
+
168
+ depth_vis = cv2.applyColorMap(((depth / 15.0) * 255).astype(np.uint8), cv2.COLORMAP_MAGMA)
169
+ return result, Image.fromarray(cv2.cvtColor(depth_vis, cv2.COLOR_BGR2RGB)), f"Applied {model_choice}"
170
+ except Exception as e:
171
+ return None, None, f"Error: {str(e)}"
172
+
173
+ with gr.Blocks(title="AI Blur Studio", theme=gr.themes.Soft()) as demo:
174
+ gr.Markdown("# AI Blur Studio\nSelect your AI models and adjust blur intensity.")
175
+
176
+ with gr.Tabs():
177
+ with gr.Tab("📹 Gaussian Background Blur"):
178
+ with gr.Row():
179
+ with gr.Column():
180
+ gaussian_input = gr.Image(label="Input Image")
181
+ seg_model_dropdown = gr.Dropdown(
182
+ choices=list(MODEL_CONFIG["segmentation"].keys()),
183
+ value=list(MODEL_CONFIG["segmentation"].keys())[0],
184
+ label="Segmentation Model"
185
+ )
186
+ gaussian_sigma = gr.Slider(0, 30, 15, label="Blur σ")
187
+ gaussian_btn = gr.Button("Process", variant="primary")
188
+ with gr.Column():
189
+ gaussian_output = gr.Image(label="Result")
190
+ gaussian_status = gr.Textbox(label="Status")
191
+
192
+ with gr.Tab("📸 Depth-Based Lens Blur"):
193
+ with gr.Row():
194
+ with gr.Column():
195
+ lens_input = gr.Image(label="Input Image")
196
+ depth_model_dropdown = gr.Dropdown(
197
+ choices=list(MODEL_CONFIG["depth"].keys()),
198
+ value=list(MODEL_CONFIG["depth"].keys())[0],
199
+ label="Depth Estimation Model"
200
+ )
201
+ lens_sigma = gr.Slider(0, 25, 15, label="Max σ")
202
+ lens_btn = gr.Button("Process", variant="primary")
203
+ with gr.Column():
204
+ lens_output = gr.Image(label="Blurred Result")
205
+ lens_depth = gr.Image(label="Depth Map")
206
+ lens_status = gr.Textbox(label="Status")
207
+
208
+ gaussian_btn.click(process_gaussian_blur, [gaussian_input, gaussian_sigma, seg_model_dropdown], [gaussian_output, gaussian_status])
209
+ lens_btn.click(process_lens_blur, [lens_input, lens_sigma, depth_model_dropdown], [lens_output, lens_depth, lens_status])
210
+
211
+ if __name__ == "__main__":
212
+ demo.launch(share=True)