Natwar commited on
Commit
9a2407d
·
verified ·
1 Parent(s): 15cef53

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -333
app.py CHANGED
@@ -1,47 +1,8 @@
1
- # Install required packages
2
- import os
3
- import subprocess
4
- import sys
5
- import importlib
6
- import pkg_resources
7
-
8
- def install_package(package, version=None):
9
- package_spec = f"{package}=={version}" if version else package
10
- print(f"Installing {package_spec}...")
11
- try:
12
- subprocess.check_call([sys.executable, "-m", "pip", "install", "--no-cache-dir", package_spec])
13
- except subprocess.CalledProcessError as e:
14
- print(f"Failed to install {package_spec}: {e}")
15
- raise
16
-
17
- def ensure_package(package, version=None):
18
- try:
19
- if version:
20
- pkg_resources.require(f"{package}=={version}")
21
- else:
22
- importlib.import_module(package)
23
- print(f"{package} is already installed with the correct version.")
24
- except (ImportError, pkg_resources.VersionConflict, pkg_resources.DistributionNotFound) as e:
25
- print(f"Package requirement failed: {e}")
26
- install_package(package, version)
27
-
28
- # Check environment and install dependencies
29
- if not os.path.exists("/.dockerenv") and not os.path.exists("/kaggle"):
30
- print("Setting up environment...")
31
-
32
- # Install core dependencies
33
- ensure_package("numpy", "1.23.5")
34
- ensure_package("protobuf", "3.20.3")
35
- ensure_package("tensorflow", "2.10.0")
36
- ensure_package("opencv-python-headless", "4.7.0.72")
37
- ensure_package("deepface", "0.0.79")
38
- ensure_package("gradio", "3.50.2")
39
-
40
- # Install additional required packages
41
- for pkg in ["matplotlib", "pillow", "pandas"]:
42
- ensure_package(pkg)
43
 
44
- # Now import the required modules
45
  import gradio as gr
46
  import json
47
  import cv2
@@ -50,14 +11,10 @@ from deepface import DeepFace
50
  import matplotlib.pyplot as plt
51
  from PIL import Image
52
  import tempfile
 
53
  import pandas as pd
54
  import shutil
55
 
56
- # Google Drive integration (for Colab users)
57
- if 'google.colab' in sys.modules:
58
- from google.colab import drive
59
- drive.mount('/content/drive')
60
-
61
  def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
62
  temp_dir = tempfile.mkdtemp()
63
  img1_path = os.path.join(temp_dir, "image1.jpg")
@@ -65,17 +22,10 @@ def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
65
 
66
  try:
67
  # Save images
68
- if isinstance(img1, np.ndarray):
69
- Image.fromarray(img1).save(img1_path)
70
- else:
71
- img1.save(img1_path)
72
-
73
- if isinstance(img2, np.ndarray):
74
- Image.fromarray(img2).save(img2_path)
75
- else:
76
- img2.save(img2_path)
77
 
78
- # Perform verification
79
  result = DeepFace.verify(
80
  img1_path=img1_path,
81
  img2_path=img2_path,
@@ -86,50 +36,23 @@ def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
86
 
87
  # Create visualization
88
  fig, ax = plt.subplots(1, 2, figsize=(10, 5))
 
 
 
 
 
89
 
90
- img1_display = cv2.imread(img1_path)
91
- img1_display = cv2.cvtColor(img1_display, cv2.COLOR_BGR2RGB)
92
- img2_display = cv2.imread(img2_path)
93
- img2_display = cv2.cvtColor(img2_display, cv2.COLOR_BGR2RGB)
94
-
95
- ax[0].imshow(img1_display)
96
- ax[0].set_title("Image 1")
97
- ax[0].axis("off")
98
-
99
- ax[1].imshow(img2_display)
100
- ax[1].set_title("Image 2")
101
- ax[1].axis("off")
102
-
103
- verification_result = "✅ FACE MATCHED" if result["verified"] else "❌ FACE NOT MATCHED"
104
  confidence = round((1 - result["distance"]) * 100, 2)
 
 
105
 
106
- plt.suptitle(f"{verification_result}\nConfidence: {confidence}%\nDistance: {result['distance']:.4f}",
107
- fontsize=16, fontweight='bold',
108
- color='green' if result["verified"] else 'red')
109
-
110
- plt.tight_layout()
111
-
112
- # Clean up
113
- os.remove(img1_path)
114
- os.remove(img2_path)
115
- os.rmdir(temp_dir)
116
-
117
- return fig, result # Return raw dict instead of JSON string
118
-
119
  except Exception as e:
120
- # Clean up even if error occurs
121
- if os.path.exists(img1_path):
122
- os.remove(img1_path)
123
- if os.path.exists(img2_path):
124
- os.remove(img2_path)
125
- if os.path.exists(temp_dir):
126
- os.rmdir(temp_dir)
127
-
128
- error_msg = str(e)
129
- if "No face detected" in error_msg:
130
- error_msg = "No face detected in one or both images. Please try different images."
131
-
132
- return None, {"error": error_msg}
133
 
134
  def find_faces(query_img, db_folder, threshold=0.70, model="VGG-Face"):
135
  temp_dir = tempfile.mkdtemp()
@@ -137,114 +60,50 @@ def find_faces(query_img, db_folder, threshold=0.70, model="VGG-Face"):
137
 
138
  try:
139
  # Save query image
140
- if isinstance(query_img, np.ndarray):
141
- Image.fromarray(query_img).save(query_path)
142
- else:
143
- query_img.save(query_path)
144
 
145
  # Handle database path
146
  if isinstance(db_folder, str):
147
- if db_folder.startswith("/content/drive"):
148
- db_path = db_folder
149
- else:
150
- db_path = os.path.abspath(db_folder)
151
- if not os.path.exists(db_path):
152
- return None, {"error": "Invalid database path - directory does not exist"}
153
  else:
154
  db_path = os.path.join(temp_dir, "db")
155
  os.makedirs(db_path, exist_ok=True)
156
-
157
  for i, file in enumerate(db_folder):
158
- orig_filename = file.orig_name
159
- file_ext = os.path.splitext(orig_filename)[1]
160
- new_filename = f"image_{i}{file_ext}"
161
- shutil.copy(file.name, os.path.join(db_path, new_filename))
162
 
163
- # Find matches
164
  dfs = DeepFace.find(
165
  img_path=query_path,
166
  db_path=db_path,
167
  model_name=model,
168
  distance_metric="cosine",
169
- threshold=threshold,
170
  silent=True
171
  )
172
 
173
  # Process results
174
- if isinstance(dfs, list):
175
- if len(dfs) == 0:
176
- return None, {"error": "No matching faces found in the database."}
177
- df = dfs[0]
178
- else:
179
- df = dfs
180
-
181
- if df.empty:
182
- return None, {"error": "No matching faces found in the database."}
183
-
184
- df = df.sort_values(by=["distance"])
185
 
186
  # Create visualization
187
- num_matches = min(4, len(df))
188
- fig, axes = plt.subplots(1, num_matches + 1, figsize=(15, 5))
189
-
190
- query_display = cv2.imread(query_path)
191
- query_display = cv2.cvtColor(query_display, cv2.COLOR_BGR2RGB)
192
- axes[0].imshow(query_display)
193
  axes[0].set_title("Query Image")
194
- axes[0].axis("off")
195
 
196
- valid_matches = 0
197
- for i in range(num_matches):
198
- if i >= len(df):
199
- break
200
-
201
- match_path = df.iloc[i]["identity"]
202
- if not os.path.exists(match_path):
203
- continue
204
-
205
- try:
206
- match_img = cv2.imread(match_path)
207
- if match_img is None:
208
- continue
209
-
210
- match_img = cv2.cvtColor(match_img, cv2.COLOR_BGR2RGB)
211
- axes[valid_matches+1].imshow(match_img)
212
- axes[valid_matches+1].set_title(f"Match #{valid_matches+1}")
213
- axes[valid_matches+1].axis("off")
214
- valid_matches += 1
215
- except Exception as e:
216
- continue
217
 
218
- # Hide empty axes
219
- for j in range(valid_matches+1, num_matches+1):
220
- axes[j].axis("off")
221
-
222
- plt.suptitle(f"Found {len(df)} matching faces", fontsize=16, fontweight='bold')
223
- plt.tight_layout()
224
-
225
- # Prepare results
226
- results = df[["identity", "distance"]].copy()
227
- results["confidence"] = (1 - results["distance"]) * 100
228
- results["confidence"] = results["confidence"].round(2)
229
- results = results.rename(columns={"identity": "Image Path"}).to_dict('records')
230
-
231
- return fig, results
232
-
233
  except Exception as e:
234
- error_msg = str(e)
235
- if "No face detected" in error_msg:
236
- error_msg = "No face detected in the query image. Please try a different image."
237
- elif "No such file or directory" in error_msg:
238
- error_msg = "Invalid database path or corrupted image files"
239
-
240
- return None, {"error": error_msg}
241
 
242
  finally:
243
- # Clean up
244
- if os.path.exists(query_path):
245
- os.remove(query_path)
246
- if 'db_path' in locals() and not isinstance(db_folder, str):
247
- shutil.rmtree(db_path, ignore_errors=True)
248
 
249
  def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
250
  temp_dir = tempfile.mkdtemp()
@@ -252,179 +111,89 @@ def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
252
 
253
  try:
254
  # Save image
255
- if isinstance(img, np.ndarray):
256
- Image.fromarray(img).save(img_path)
257
- else:
258
- img.save(img_path)
259
 
260
- # Analyze image
261
  results = DeepFace.analyze(
262
  img_path=img_path,
263
  actions=actions,
264
- enforce_detection=True,
265
  detector_backend='opencv'
266
  )
267
 
268
  # Process results
269
- if isinstance(results, list):
270
- num_faces = len(results)
271
- else:
272
- num_faces = 1
273
- results = [results]
274
-
275
- # Create visualization
276
- fig = plt.figure(figsize=(14, 7))
277
-
278
- img_display = cv2.imread(img_path)
279
- img_display = cv2.cvtColor(img_display, cv2.COLOR_BGR2RGB)
280
-
281
- main_ax = plt.subplot2grid((2, 4), (0, 0), colspan=2, rowspan=2)
282
- main_ax.imshow(img_display)
283
- main_ax.set_title(f"Analyzed Image ({num_faces} face{'s' if num_faces > 1 else ''} detected)")
284
- main_ax.axis('off')
285
 
286
- for i, face_result in enumerate(results[:4]):
287
- # Get analysis data
288
- age = face_result.get('age', 'N/A')
289
- gender = face_result.get('dominant_gender', 'N/A')
290
- race = face_result.get('dominant_race', 'N/A')
291
- emotion = face_result.get('dominant_emotion', 'N/A')
292
-
293
- # Create subplot
294
- ax = plt.subplot2grid((2, 4), (0 if i < 2 else 1, 2 + (i % 2)))
295
- text = f"Face #{i+1}\n\nAge: {age}\nGender: {gender}\nRace: {race}\nEmotion: {emotion}"
296
- ax.text(0.5, 0.5, text, ha='center', va='center', fontsize=11)
297
- ax.axis('off')
298
-
299
- plt.tight_layout()
300
 
301
- # Format results
302
- formatted_results = []
303
- for i, res in enumerate(results[:8]):
304
- face_data = {
305
- "face_number": i+1,
306
- "age": res.get("age", "N/A"),
307
- "gender": res.get("dominant_gender", "N/A"),
308
- "race": res.get("dominant_race", "N/A"),
309
- "emotion": res.get("dominant_emotion", "N/A")
310
- }
311
- formatted_results.append(face_data)
312
 
313
- return fig, formatted_results
314
 
315
  except Exception as e:
316
- error_msg = str(e)
317
- if "No face detected" in error_msg:
318
- error_msg = "No face detected in the image. Please try a different image."
319
-
320
- return None, {"error": error_msg}
321
 
322
  finally:
323
- # Clean up
324
- if os.path.exists(img_path):
325
- os.remove(img_path)
326
- if os.path.exists(temp_dir):
327
- os.rmdir(temp_dir)
328
 
329
- # Create Gradio interface
330
- with gr.Blocks(title="Complete Face Recognition Tool", theme=gr.themes.Soft()) as demo:
331
- gr.Markdown("""
332
- # 🔍 Complete Face Recognition Tool
333
-
334
- This tool provides three face recognition features:
335
- - **Verify Faces**: Compare two images to check if they contain the same person
336
- - **Find Faces**: Search for matching faces in a database/folder
337
- - **Analyze Face**: Determine age, gender, race, and emotion from facial images
338
- """)
339
 
340
  with gr.Tabs():
341
- # Verify Faces Tab
342
- with gr.TabItem("Verify Faces"):
343
  with gr.Row():
344
- img1 = gr.Image(label="First Image", type="pil")
345
- img2 = gr.Image(label="Second Image", type="pil")
 
 
 
 
 
346
 
347
- with gr.Row():
348
- verify_threshold = gr.Slider(0.1, 0.9, value=0.6, step=0.05,
349
- label="Similarity Threshold (lower = stricter)")
350
- verify_model = gr.Dropdown(
351
- choices=["VGG-Face", "Facenet", "OpenFace", "DeepFace", "ArcFace"],
352
- value="VGG-Face",
353
- label="Recognition Model"
354
- )
355
-
356
- verify_btn = gr.Button("Verify Faces", variant="primary")
357
-
358
- with gr.Row():
359
- verify_plot = gr.Plot(label="Comparison Result")
360
- verify_results = gr.JSON(label="Verification Details")
361
-
362
- # Find Faces Tab
363
- with gr.TabItem("Find Faces"):
364
- query_img = gr.Image(label="Query Image", type="pil")
365
-
366
- with gr.Row():
367
- db_path = gr.Textbox(
368
- label="Database Path",
369
- placeholder="/content/drive/MyDrive/your_folder or local path"
370
- )
371
- db_files = gr.File(label="Or upload images", file_count="multiple")
372
-
373
- with gr.Row():
374
- find_threshold = gr.Slider(0.1, 0.9, value=0.6, step=0.05,
375
- label="Similarity Threshold")
376
- find_model = gr.Dropdown(
377
- choices=["VGG-Face", "Facenet", "OpenFace", "DeepFace", "ArcFace"],
378
- value="VGG-Face",
379
- label="Recognition Model"
380
- )
381
-
382
- find_btn = gr.Button("Find Matches", variant="primary")
383
-
384
- with gr.Row():
385
- find_plot = gr.Plot(label="Matching Results")
386
- find_results = gr.JSON(label="Match Details")
387
-
388
- # Analyze Face Tab
389
- with gr.TabItem("Analyze Face"):
390
- analyze_img = gr.Image(label="Input Image", type="pil")
391
- analyze_actions = gr.CheckboxGroup(
392
- choices=["age", "gender", "race", "emotion"],
393
- value=["age", "gender", "race", "emotion"],
394
- label="Analysis Features"
395
  )
 
 
 
 
 
 
 
 
 
396
 
397
- analyze_btn = gr.Button("Analyze Face", variant="primary")
 
 
 
 
 
 
 
 
 
 
 
 
398
 
399
- with gr.Row():
400
- analyze_plot = gr.Plot(label="Analysis Visualization")
401
- analyze_results = gr.JSON(label="Detailed Analysis")
402
-
403
- # Event handlers
404
- verify_btn.click(
405
- verify_faces,
406
- inputs=[img1, img2, verify_threshold, verify_model],
407
- outputs=[verify_plot, verify_results]
408
- )
409
-
410
- find_btn.click(
411
- find_faces,
412
- inputs=[query_img, db_path, find_threshold, find_model],
413
- outputs=[find_plot, find_results]
414
- )
415
-
416
- db_files.change(
417
- lambda x: "",
418
- inputs=db_files,
419
- outputs=db_path
420
- )
421
-
422
- analyze_btn.click(
423
- analyze_face,
424
- inputs=[analyze_img, analyze_actions],
425
- outputs=[analyze_plot, analyze_results]
426
- )
427
 
428
- # Launch the app
429
- if __name__ == "__main__":
430
- demo.launch()
 
1
+ # Install required packages with version locking
2
+ from google.colab import drive
3
+ drive.mount('/content/drive')
4
+ !pip install deepface==0.0.79 tensorflow==2.10.0 opencv-python-headless==4.7.0.72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
 
6
  import gradio as gr
7
  import json
8
  import cv2
 
11
  import matplotlib.pyplot as plt
12
  from PIL import Image
13
  import tempfile
14
+ import os
15
  import pandas as pd
16
  import shutil
17
 
 
 
 
 
 
18
  def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
19
  temp_dir = tempfile.mkdtemp()
20
  img1_path = os.path.join(temp_dir, "image1.jpg")
 
22
 
23
  try:
24
  # Save images
25
+ Image.fromarray(img1).save(img1_path) if isinstance(img1, np.ndarray) else img1.save(img1_path)
26
+ Image.fromarray(img2).save(img2_path) if isinstance(img2, np.ndarray) else img2.save(img2_path)
 
 
 
 
 
 
 
27
 
28
+ # Verify faces with proper API parameters
29
  result = DeepFace.verify(
30
  img1_path=img1_path,
31
  img2_path=img2_path,
 
36
 
37
  # Create visualization
38
  fig, ax = plt.subplots(1, 2, figsize=(10, 5))
39
+ for idx, path in enumerate([img1_path, img2_path]):
40
+ img = cv2.cvtColor(cv2.imread(path), cv2.COLOR_BGR2RGB)
41
+ ax[idx].imshow(img)
42
+ ax[idx].set_title(f"Image {idx+1}")
43
+ ax[idx].axis("off")
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  confidence = round((1 - result["distance"]) * 100, 2)
46
+ plt.suptitle(f"{'✅ MATCH' if result['verified'] else '❌ NO MATCH'}\nConfidence: {confidence}%",
47
+ fontsize=14, y=1.05)
48
 
49
+ return fig, result
50
+
 
 
 
 
 
 
 
 
 
 
 
51
  except Exception as e:
52
+ return None, {"error": str(e)}
53
+
54
+ finally:
55
+ shutil.rmtree(temp_dir, ignore_errors=True)
 
 
 
 
 
 
 
 
 
56
 
57
  def find_faces(query_img, db_folder, threshold=0.70, model="VGG-Face"):
58
  temp_dir = tempfile.mkdtemp()
 
60
 
61
  try:
62
  # Save query image
63
+ Image.fromarray(query_img).save(query_path) if isinstance(query_img, np.ndarray) else query_img.save(query_path)
 
 
 
64
 
65
  # Handle database path
66
  if isinstance(db_folder, str):
67
+ db_path = db_folder
 
 
 
 
 
68
  else:
69
  db_path = os.path.join(temp_dir, "db")
70
  os.makedirs(db_path, exist_ok=True)
 
71
  for i, file in enumerate(db_folder):
72
+ ext = os.path.splitext(file.name)[1]
73
+ shutil.copy(file.name, os.path.join(db_path, f"img_{i}{ext}"))
 
 
74
 
75
+ # Find faces with corrected API parameters
76
  dfs = DeepFace.find(
77
  img_path=query_path,
78
  db_path=db_path,
79
  model_name=model,
80
  distance_metric="cosine",
81
+ enforce_detection=False,
82
  silent=True
83
  )
84
 
85
  # Process results
86
+ df = dfs[0] if isinstance(dfs, list) else dfs
87
+ df = df[df['distance'] <= threshold].sort_values('distance')
 
 
 
 
 
 
 
 
 
88
 
89
  # Create visualization
90
+ fig, axes = plt.subplots(1, min(4, len(df)) if len(df) > 0 else plt.subplots(1, 1))
91
+ axes[0].imshow(cv2.cvtColor(cv2.imread(query_path), cv2.COLOR_BGR2RGB))
 
 
 
 
92
  axes[0].set_title("Query Image")
 
93
 
94
+ for idx, (_, row) in enumerate(df.head(3).iterrows()):
95
+ if idx >= len(axes)-1: break
96
+ match_img = cv2.cvtColor(cv2.imread(row['identity']), cv2.COLOR_BGR2RGB)
97
+ axes[idx+1].imshow(match_img)
98
+ axes[idx+1].set_title(f"Match {idx+1}\n{row['distance']:.2f}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
+ return fig, df[['identity', 'distance']].to_dict('records')
101
+
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  except Exception as e:
103
+ return None, {"error": str(e)}
 
 
 
 
 
 
104
 
105
  finally:
106
+ shutil.rmtree(temp_dir, ignore_errors=True)
 
 
 
 
107
 
108
  def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
109
  temp_dir = tempfile.mkdtemp()
 
111
 
112
  try:
113
  # Save image
114
+ Image.fromarray(img).save(img_path) if isinstance(img, np.ndarray) else img.save(img_path)
 
 
 
115
 
116
+ # Analyze face
117
  results = DeepFace.analyze(
118
  img_path=img_path,
119
  actions=actions,
120
+ enforce_detection=False,
121
  detector_backend='opencv'
122
  )
123
 
124
  # Process results
125
+ results = results if isinstance(results, list) else [results]
126
+ fig = plt.figure(figsize=(10, 5))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
+ # Display main image
129
+ plt.subplot(121)
130
+ plt.imshow(cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB))
131
+ plt.title("Input Image")
132
+ plt.axis('off')
 
 
 
 
 
 
 
 
 
133
 
134
+ # Display attributes
135
+ plt.subplot(122)
136
+ attrs = {k:v for res in results for k,v in res.items() if k != 'region'}
137
+ plt.barh(list(attrs.keys()), list(attrs.values()))
138
+ plt.title("Analysis Results")
 
 
 
 
 
 
139
 
140
+ return fig, results
141
 
142
  except Exception as e:
143
+ return None, {"error": str(e)}
 
 
 
 
144
 
145
  finally:
146
+ shutil.rmtree(temp_dir, ignore_errors=True)
 
 
 
 
147
 
148
+ # Gradio interface
149
+ with gr.Blocks(title="Face Analysis Tool", theme=gr.themes.Soft()) as demo:
150
+ gr.Markdown("# 🔍 Face Analysis Toolkit")
 
 
 
 
 
 
 
151
 
152
  with gr.Tabs():
153
+ with gr.Tab("Verify Faces"):
154
+ gr.Markdown("## Compare two faces")
155
  with gr.Row():
156
+ img1 = gr.Image(type="pil", label="First Face")
157
+ img2 = gr.Image(type="pil", label="Second Face")
158
+ thresh = gr.Slider(0.1, 1.0, 0.6, label="Matching Threshold")
159
+ model = gr.Dropdown(["VGG-Face", "Facenet", "OpenFace"], value="VGG-Face")
160
+ verify_btn = gr.Button("Compare Faces")
161
+ result_plot = gr.Plot()
162
+ result_json = gr.JSON()
163
 
164
+ verify_btn.click(
165
+ verify_faces,
166
+ [img1, img2, thresh, model],
167
+ [result_plot, result_json]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  )
169
+
170
+ with gr.Tab("Find Faces"):
171
+ gr.Markdown("## Find similar faces in database")
172
+ query = gr.Image(type="pil", label="Query Image")
173
+ db = gr.Textbox("/content/drive/MyDrive/db", label="Database Path")
174
+ files = gr.File(file_count="multiple", label="Or upload files")
175
+ find_btn = gr.Button("Search Faces")
176
+ matches_plot = gr.Plot()
177
+ matches_json = gr.JSON()
178
 
179
+ find_btn.click(
180
+ find_faces,
181
+ [query, db, thresh, model],
182
+ [matches_plot, matches_json]
183
+ )
184
+ files.change(lambda x: None, [files], [db])
185
+
186
+ with gr.Tab("Analyze Face"):
187
+ gr.Markdown("## Analyze facial attributes")
188
+ inp_img = gr.Image(type="pil", label="Input Image")
189
+ analyze_btn = gr.Button("Analyze")
190
+ analysis_plot = gr.Plot()
191
+ analysis_json = gr.JSON()
192
 
193
+ analyze_btn.click(
194
+ analyze_face,
195
+ [inp_img],
196
+ [analysis_plot, analysis_json]
197
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
 
199
+ demo.launch()