Raswanth commited on
Commit
a01f91f
Β·
verified Β·
1 Parent(s): db5d432

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +233 -0
  2. requirements (1).txt +8 -0
app.py ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ from PIL import Image
5
+ import torch
6
+ from transformers import AutoImageProcessor, AutoModelForSemanticSegmentation, AutoModelForDepthEstimation
7
+
8
+ # Load models
9
+ print("Loading models...")
10
+ seg_processor = AutoImageProcessor.from_pretrained("nvidia/segformer-b0-finetuned-ade-512-512")
11
+ seg_model = AutoModelForSemanticSegmentation.from_pretrained("nvidia/segformer-b0-finetuned-ade-512-512")
12
+
13
+ depth_processor = AutoImageProcessor.from_pretrained("Intel/dpt-large")
14
+ depth_model = AutoModelForDepthEstimation.from_pretrained("Intel/dpt-large")
15
+
16
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
17
+ seg_model = seg_model.to(device)
18
+ depth_model = depth_model.to(device)
19
+ print(f"Models loaded on {device}")
20
+
21
+ def get_person_mask(image):
22
+ """Get segmentation mask for person"""
23
+ inputs = seg_processor(images=image, return_tensors="pt").to(device)
24
+
25
+ with torch.no_grad():
26
+ outputs = seg_model(**inputs)
27
+
28
+ segmentation = outputs.logits.argmax(dim=1).squeeze().cpu().numpy()
29
+ person_mask = (segmentation == 12).astype(np.uint8)
30
+
31
+ # Clean up mask
32
+ kernel = np.ones((5, 5), np.uint8)
33
+ person_mask = cv2.morphologyEx(person_mask, cv2.MORPH_CLOSE, kernel, iterations=3)
34
+ person_mask = cv2.morphologyEx(person_mask, cv2.MORPH_OPEN, kernel, iterations=2)
35
+
36
+ return person_mask
37
+
38
+ def get_depth_map(image):
39
+ """Get depth map using DPT"""
40
+ inputs = depth_processor(images=image, return_tensors="pt").to(device)
41
+
42
+ with torch.no_grad():
43
+ outputs = depth_model(**inputs)
44
+ predicted_depth = outputs.predicted_depth
45
+
46
+ h, w = image.size[1], image.size[0]
47
+ prediction = torch.nn.functional.interpolate(
48
+ predicted_depth.unsqueeze(1),
49
+ size=(h, w),
50
+ mode="bicubic",
51
+ align_corners=False,
52
+ ).squeeze()
53
+
54
+ depth_map = prediction.cpu().numpy()
55
+
56
+ # Normalize to [0, 1]
57
+ depth_normalized = (depth_map - depth_map.min()) / (depth_map.max() - depth_map.min())
58
+
59
+ # Invert so closer = smaller values
60
+ depth_normalized = 1 - depth_normalized
61
+
62
+ return depth_normalized
63
+
64
+ def apply_gaussian_blur(image, person_mask, sigma):
65
+ """Apply Gaussian blur to background only"""
66
+ img_array = np.array(image)
67
+ blurred_image = cv2.GaussianBlur(img_array, (0, 0), sigmaX=sigma)
68
+
69
+ result = img_array.copy()
70
+ result[person_mask == 0] = blurred_image[person_mask == 0]
71
+
72
+ return Image.fromarray(result)
73
+
74
+ def apply_variable_blur(image, depth_map, max_sigma, num_layers=20):
75
+ """Apply variable blur based on depth"""
76
+ img_array = np.array(image)
77
+ result = np.zeros_like(img_array, dtype=np.float32)
78
+ depth_levels = np.linspace(0, 1, num_layers + 1)
79
+
80
+ for i in range(num_layers):
81
+ mask = ((depth_map >= depth_levels[i]) & (depth_map < depth_levels[i+1]))
82
+
83
+ if mask.sum() < 1:
84
+ continue
85
+
86
+ avg_depth = (depth_levels[i] + depth_levels[i+1]) / 2
87
+ sigma = avg_depth * max_sigma
88
+
89
+ if sigma > 0.5:
90
+ blurred = cv2.GaussianBlur(img_array, (0, 0), sigma)
91
+ else:
92
+ blurred = img_array
93
+
94
+ mask_3ch = np.stack([mask, mask, mask], axis=-1)
95
+ result += blurred * mask_3ch
96
+
97
+ return Image.fromarray(np.clip(result, 0, 255).astype(np.uint8))
98
+
99
+ def process_image(image, effect_type, sigma_value):
100
+ """Main processing function"""
101
+ if image is None:
102
+ return None, None, None, "Please upload an image"
103
+
104
+ # Resize to manageable size
105
+ image = image.resize((512, 512), Image.LANCZOS)
106
+
107
+ if effect_type == "Gaussian Blur":
108
+ # Get person mask
109
+ person_mask = get_person_mask(image)
110
+
111
+ # Apply Gaussian blur
112
+ result = apply_gaussian_blur(image, person_mask, sigma_value)
113
+
114
+ # Create mask visualization
115
+ mask_vis = Image.fromarray(person_mask * 255)
116
+
117
+ info = f"βœ… Gaussian Blur Applied\nSigma: {sigma_value}\nMethod: Uniform background blur"
118
+
119
+ return result, mask_vis, None, info
120
+
121
+ else: # Lens Blur
122
+ # Get depth map
123
+ depth_map = get_depth_map(image)
124
+
125
+ # Apply lens blur
126
+ result = apply_variable_blur(image, depth_map, max_sigma=sigma_value, num_layers=20)
127
+
128
+ # Create depth visualization
129
+ depth_uint8 = (depth_map * 255).astype(np.uint8)
130
+ depth_colored = cv2.applyColorMap(depth_uint8, cv2.COLORMAP_TURBO)
131
+ depth_colored = cv2.cvtColor(depth_colored, cv2.COLOR_BGR2RGB)
132
+ depth_vis = Image.fromarray(depth_colored)
133
+
134
+ info = f"βœ… Depth-Based Lens Blur Applied\nMax Sigma: {sigma_value}\nMethod: Variable blur by depth"
135
+
136
+ return result, depth_vis, None, info
137
+
138
+ # Create Gradio interface
139
+ with gr.Blocks(title="Portrait Blur Effects - Vision Transformer Demo", theme=gr.themes.Soft()) as demo:
140
+ gr.Markdown("""
141
+ # 🎨 Portrait Blur Effects with Vision Transformers
142
+ ### EEE 598 Assignment 4 - Problem 3 Interactive Demo
143
+
144
+ Upload a portrait image and apply either **Gaussian Blur** (uniform background blur) or **Lens Blur** (depth-based realistic blur).
145
+
146
+ **Models Used:**
147
+ - 🧠 **SegFormer** (nvidia/segformer-b0-finetuned-ade-512-512) for segmentation
148
+ - 🧠 **DPT** (Intel/dpt-large) for depth estimation
149
+ """)
150
+
151
+ with gr.Row():
152
+ with gr.Column(scale=1):
153
+ gr.Markdown("### πŸ“€ Input")
154
+ input_image = gr.Image(type="pil", label="Upload Portrait Image")
155
+
156
+ effect_type = gr.Radio(
157
+ choices=["Gaussian Blur", "Lens Blur"],
158
+ value="Gaussian Blur",
159
+ label="Effect Type",
160
+ info="Choose blur method"
161
+ )
162
+
163
+ sigma_slider = gr.Slider(
164
+ minimum=1,
165
+ maximum=30,
166
+ value=15,
167
+ step=1,
168
+ label="Blur Strength (Sigma)",
169
+ info="Higher = more blur"
170
+ )
171
+
172
+ process_btn = gr.Button("πŸš€ Apply Blur Effect", variant="primary", size="lg")
173
+
174
+ info_box = gr.Textbox(label="Status", lines=3, interactive=False)
175
+
176
+ with gr.Column(scale=2):
177
+ gr.Markdown("### πŸ“₯ Results")
178
+
179
+ with gr.Row():
180
+ output_image = gr.Image(type="pil", label="Result", interactive=False)
181
+ aux_image = gr.Image(type="pil", label="Segmentation Mask / Depth Map", interactive=False)
182
+
183
+ with gr.Row():
184
+ gr.Markdown("""
185
+ ---
186
+ ### πŸ“– How It Works
187
+
188
+ #### Gaussian Blur (Task 2):
189
+ 1. **SegFormer** segments the image to identify the person
190
+ 2. Gaussian blur (Οƒ=15) is applied uniformly to the background
191
+ 3. Person remains sharp, creating a portrait mode effect
192
+
193
+ #### Lens Blur (Task 4):
194
+ 1. **DPT** estimates depth at each pixel
195
+ 2. Blur intensity varies based on distance from camera
196
+ 3. Creates realistic depth-of-field like expensive cameras
197
+
198
+ ---
199
+ **Comparison:**
200
+ - **Gaussian Blur:** Fast, sharp boundaries, good for video calls (Zoom effect)
201
+ - **Lens Blur:** Realistic, smooth gradients, good for photography
202
+
203
+ ---
204
+ πŸŽ“ **EEE 598 Deep Learning for Engineers** | Arizona State University
205
+ """)
206
+
207
+ # Examples
208
+ gr.Markdown("### 🎯 Try These Examples")
209
+ gr.Examples(
210
+ examples=[
211
+ [None, "Gaussian Blur", 15],
212
+ [None, "Lens Blur", 15],
213
+ [None, "Gaussian Blur", 25],
214
+ [None, "Lens Blur", 10],
215
+ ],
216
+ inputs=[input_image, effect_type, sigma_slider],
217
+ label="Quick Examples (Upload your own image first)"
218
+ )
219
+
220
+ # Event handler
221
+ process_btn.click(
222
+ fn=process_image,
223
+ inputs=[input_image, effect_type, sigma_slider],
224
+ outputs=[output_image, aux_image, None, info_box]
225
+ )
226
+
227
+ # Launch
228
+ if __name__ == "__main__":
229
+ demo.launch(
230
+ server_name="0.0.0.0",
231
+ server_port=7860,
232
+ share=False
233
+ )
requirements (1).txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ transformers==4.44.0
3
+ torch==2.1.0
4
+ torchvision==0.16.0
5
+ opencv-python-headless==4.10.0.84
6
+ pillow==10.4.0
7
+ numpy==1.26.4
8
+ scipy==1.13.1