molecularmax commited on
Commit
49f1ccb
·
1 Parent(s): 13be63e

Initial face anonymization demo with Gradio interface

Browse files

- Add InsightFace-based face detection using antelopev2 model
- Implement blur and pixelation anonymization methods
- Create interactive Gradio UI with sample image support
- Add adjustable parameters for blur strength and pixel size

Files changed (3) hide show
  1. app.py +228 -0
  2. assets/README.md +9 -0
  3. requirements.txt +7 -0
app.py ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import numpy as np
4
+ from PIL import Image, ImageFilter
5
+ import insightface
6
+ from insightface.app import FaceAnalysis
7
+ import os
8
+ import tempfile
9
+ from huggingface_hub import hf_hub_download
10
+
11
+ class FaceAnonymizer:
12
+ def __init__(self):
13
+ self.app = FaceAnalysis(name='antelopev2', providers=['CPUExecutionProvider'])
14
+ self.app.prepare(ctx_id=0, det_size=(640, 640))
15
+
16
+ def detect_faces(self, image):
17
+ """Detect faces in the image using InsightFace"""
18
+ if isinstance(image, Image.Image):
19
+ image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
20
+ else:
21
+ image_cv = image
22
+
23
+ faces = self.app.get(image_cv)
24
+ return faces
25
+
26
+ def blur_faces(self, image, blur_strength=15):
27
+ """Apply Gaussian blur to detected faces"""
28
+ if isinstance(image, Image.Image):
29
+ pil_image = image.copy()
30
+ image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
31
+ else:
32
+ image_cv = image.copy()
33
+ pil_image = Image.fromarray(cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB))
34
+
35
+ faces = self.detect_faces(image_cv)
36
+
37
+ for face in faces:
38
+ bbox = face.bbox.astype(int)
39
+ x1, y1, x2, y2 = bbox
40
+
41
+ # Extract face region
42
+ face_region = pil_image.crop((x1, y1, x2, y2))
43
+
44
+ # Apply blur
45
+ blurred_face = face_region.filter(ImageFilter.GaussianBlur(radius=blur_strength))
46
+
47
+ # Paste back
48
+ pil_image.paste(blurred_face, (x1, y1))
49
+
50
+ return pil_image
51
+
52
+ def pixelate_faces(self, image, pixel_size=20):
53
+ """Apply pixelation to detected faces"""
54
+ if isinstance(image, Image.Image):
55
+ pil_image = image.copy()
56
+ image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
57
+ else:
58
+ image_cv = image.copy()
59
+ pil_image = Image.fromarray(cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB))
60
+
61
+ faces = self.detect_faces(image_cv)
62
+
63
+ for face in faces:
64
+ bbox = face.bbox.astype(int)
65
+ x1, y1, x2, y2 = bbox
66
+
67
+ # Extract face region
68
+ face_region = pil_image.crop((x1, y1, x2, y2))
69
+
70
+ # Calculate dimensions for pixelation
71
+ width, height = face_region.size
72
+ small_width = max(1, width // pixel_size)
73
+ small_height = max(1, height // pixel_size)
74
+
75
+ # Resize down and back up for pixelation effect
76
+ pixelated_face = face_region.resize((small_width, small_height), Image.NEAREST)
77
+ pixelated_face = pixelated_face.resize((width, height), Image.NEAREST)
78
+
79
+ # Paste back
80
+ pil_image.paste(pixelated_face, (x1, y1))
81
+
82
+ return pil_image
83
+
84
+ # Initialize the anonymizer
85
+ anonymizer = FaceAnonymizer()
86
+
87
+ def anonymize_image(image, anonymization_method, blur_strength, pixel_size):
88
+ """Main function to anonymize faces in an image"""
89
+ if image is None:
90
+ return None
91
+
92
+ try:
93
+ # Convert to PIL Image if needed
94
+ if isinstance(image, np.ndarray):
95
+ image = Image.fromarray(image)
96
+
97
+ if anonymization_method == "Blur":
98
+ result = anonymizer.blur_faces(image, blur_strength=blur_strength)
99
+ elif anonymization_method == "Pixelation":
100
+ result = anonymizer.pixelate_faces(image, pixel_size=pixel_size)
101
+ else:
102
+ result = image
103
+
104
+ return result
105
+ except Exception as e:
106
+ print(f"Error processing image: {str(e)}")
107
+ return image
108
+
109
+ def load_sample_image(sample_name):
110
+ """Load a sample image from assets folder"""
111
+ asset_path = f"assets/{sample_name}"
112
+ if os.path.exists(asset_path):
113
+ return Image.open(asset_path)
114
+ return None
115
+
116
+ # Create assets folder if it doesn't exist
117
+ os.makedirs("assets", exist_ok=True)
118
+
119
+ # Gradio Interface
120
+ with gr.Blocks(title="Face Anonymization Demo", theme=gr.themes.Soft()) as demo:
121
+ gr.Markdown("""
122
+ # 🎭 Face Anonymization Demo
123
+
124
+ Upload an image or select a sample to anonymize faces using different methods.
125
+ The app uses InsightFace for face detection and provides blur and pixelation options.
126
+ """)
127
+
128
+ with gr.Row():
129
+ with gr.Column():
130
+ gr.Markdown("### Input")
131
+
132
+ # Image input
133
+ input_image = gr.Image(
134
+ label="Upload Image",
135
+ type="pil",
136
+ height=400
137
+ )
138
+
139
+ # Sample images
140
+ gr.Markdown("**Or select a sample:**")
141
+ with gr.Row():
142
+ sample_btn1 = gr.Button("Face 1", size="sm")
143
+ sample_btn2 = gr.Button("Face 2", size="sm")
144
+ sample_btn3 = gr.Button("Face 3", size="sm")
145
+
146
+ # Anonymization controls
147
+ gr.Markdown("### Anonymization Settings")
148
+
149
+ anonymization_method = gr.Radio(
150
+ choices=["Blur", "Pixelation"],
151
+ label="Anonymization Method",
152
+ value="Blur"
153
+ )
154
+
155
+ with gr.Group():
156
+ blur_strength = gr.Slider(
157
+ minimum=5,
158
+ maximum=50,
159
+ value=15,
160
+ step=1,
161
+ label="Blur Strength",
162
+ visible=True
163
+ )
164
+
165
+ pixel_size = gr.Slider(
166
+ minimum=5,
167
+ maximum=50,
168
+ value=20,
169
+ step=1,
170
+ label="Pixel Size",
171
+ visible=False
172
+ )
173
+
174
+ # Process button
175
+ process_btn = gr.Button("🎭 Anonymize Faces", variant="primary", size="lg")
176
+
177
+ with gr.Column():
178
+ gr.Markdown("### Result")
179
+ output_image = gr.Image(
180
+ label="Anonymized Image",
181
+ type="pil",
182
+ height=400
183
+ )
184
+
185
+ # Event handlers
186
+ def update_controls(method):
187
+ if method == "Blur":
188
+ return gr.update(visible=True), gr.update(visible=False)
189
+ else:
190
+ return gr.update(visible=False), gr.update(visible=True)
191
+
192
+ anonymization_method.change(
193
+ fn=update_controls,
194
+ inputs=[anonymization_method],
195
+ outputs=[blur_strength, pixel_size]
196
+ )
197
+
198
+ # Sample image buttons
199
+ sample_btn1.click(
200
+ fn=lambda: load_sample_image("face1.jpg"),
201
+ outputs=input_image
202
+ )
203
+
204
+ sample_btn2.click(
205
+ fn=lambda: load_sample_image("face2.jpg"),
206
+ outputs=input_image
207
+ )
208
+
209
+ sample_btn3.click(
210
+ fn=lambda: load_sample_image("face3.jpg"),
211
+ outputs=input_image
212
+ )
213
+
214
+ # Process button
215
+ process_btn.click(
216
+ fn=anonymize_image,
217
+ inputs=[input_image, anonymization_method, blur_strength, pixel_size],
218
+ outputs=output_image
219
+ )
220
+
221
+ gr.Markdown("""
222
+ ---
223
+ **Note:** This demo uses InsightFace for face detection and applies anonymization techniques locally.
224
+ No images are stored or transmitted externally.
225
+ """)
226
+
227
+ if __name__ == "__main__":
228
+ demo.launch()
assets/README.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ # Assets Folder
2
+
3
+ Please upload the following sample images to this folder:
4
+
5
+ - `face1.jpg` - Sample face image 1
6
+ - `face2.jpg` - Sample face image 2
7
+ - `face3.jpg` - Sample face image 3
8
+
9
+ These images will be used as sample inputs in the face anonymization demo.
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ insightface==0.7.3
3
+ opencv-python==4.8.1.78
4
+ pillow==10.0.1
5
+ numpy==1.24.3
6
+ onnxruntime==1.16.3
7
+ huggingface-hub==0.19.4