Natwar commited on
Commit
0e514e1
·
verified ·
1 Parent(s): 4c6ee84

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +107 -131
app.py CHANGED
@@ -1,114 +1,70 @@
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 if running in a standard environment (not Colab/Jupyter)
29
- if not os.path.exists("/.dockerenv") and not os.path.exists("/kaggle"):
30
- print("Setting up environment...")
31
-
32
- # Install packages in the correct order with compatible versions
33
- ensure_package("numpy", "1.23.5") # Compatible with TensorFlow 2.10
34
- ensure_package("protobuf", "3.20.3") # Critical for TensorFlow compatibility
35
- ensure_package("tensorflow", "2.10.0") # Stable version with good compatibility
36
-
37
- # Install core dependencies
38
- for pkg in ["gradio", "opencv-python-headless", "matplotlib", "pillow", "pandas"]:
39
- ensure_package(pkg)
40
-
41
- # Install deepface last after all dependencies are set up
42
- ensure_package("deepface")
43
-
44
- # Now import the required modules
45
  import gradio as gr
46
  import json
47
  import cv2
48
  import numpy as np
 
 
49
  from PIL import Image
50
  import tempfile
 
51
  import pandas as pd
52
  import shutil
53
- import matplotlib.pyplot as plt
54
-
55
- # Import DeepFace after ensuring dependencies are properly installed
56
- from deepface import DeepFace
57
 
58
  def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
59
  temp_dir = tempfile.mkdtemp()
60
  img1_path = os.path.join(temp_dir, "image1.jpg")
61
  img2_path = os.path.join(temp_dir, "image2.jpg")
62
-
63
  if isinstance(img1, np.ndarray):
64
  Image.fromarray(img1).save(img1_path)
65
  else:
66
  img1.save(img1_path)
67
-
68
  if isinstance(img2, np.ndarray):
69
  Image.fromarray(img2).save(img2_path)
70
  else:
71
  img2.save(img2_path)
72
-
73
  try:
74
  result = DeepFace.verify(
75
- img1_path=img1_path,
76
  img2_path=img2_path,
77
  model_name=model,
78
  distance_metric="cosine",
79
  threshold=threshold
80
  )
81
-
82
  fig, ax = plt.subplots(1, 2, figsize=(10, 5))
83
-
84
  img1_display = cv2.imread(img1_path)
85
  img1_display = cv2.cvtColor(img1_display, cv2.COLOR_BGR2RGB)
86
  img2_display = cv2.imread(img2_path)
87
  img2_display = cv2.cvtColor(img2_display, cv2.COLOR_BGR2RGB)
88
-
89
  ax[0].imshow(img1_display)
90
  ax[0].set_title("Image 1")
91
  ax[0].axis("off")
92
-
93
  ax[1].imshow(img2_display)
94
  ax[1].set_title("Image 2")
95
  ax[1].axis("off")
96
-
97
  verification_result = "✅ FACE MATCHED" if result["verified"] else "❌ FACE NOT MATCHED"
98
  confidence = round((1 - result["distance"]) * 100, 2)
99
-
100
- plt.suptitle(f"{verification_result}\nConfidence: {confidence}%\nDistance: {result['distance']:.4f}",
101
- fontsize=16, fontweight='bold',
102
  color='green' if result["verified"] else 'red')
103
-
104
  plt.tight_layout()
105
-
106
  os.remove(img1_path)
107
  os.remove(img2_path)
108
  os.rmdir(temp_dir)
109
-
110
  return fig, json.dumps(result, indent=2)
111
-
112
  except Exception as e:
113
  if os.path.exists(img1_path):
114
  os.remove(img1_path)
@@ -116,107 +72,118 @@ def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
116
  os.remove(img2_path)
117
  if os.path.exists(temp_dir):
118
  os.rmdir(temp_dir)
119
-
120
  error_msg = f"Error: {str(e)}"
121
  if "No face detected" in str(e):
122
  error_msg = "No face detected in one or both images. Please try different images."
123
-
124
  return None, error_msg
125
 
126
  def find_faces(query_img, db_folder, threshold=0.70, model="VGG-Face"):
127
  temp_dir = tempfile.mkdtemp()
128
  query_path = os.path.join(temp_dir, "query.jpg")
129
-
130
  if isinstance(query_img, np.ndarray):
131
  Image.fromarray(query_img).save(query_path)
132
  else:
133
  query_img.save(query_path)
134
-
135
  if isinstance(db_folder, str):
136
  db_path = db_folder
137
  else:
138
  db_path = os.path.join(temp_dir, "db")
139
  os.makedirs(db_path, exist_ok=True)
140
-
141
  for i, file in enumerate(db_folder):
142
- file_ext = os.path.splitext(file.name)[1]
143
- shutil.copy(file.name, os.path.join(db_path, f"image_{i}{file_ext}"))
144
-
 
 
145
  try:
146
  dfs = DeepFace.find(
147
  img_path=query_path,
148
  db_path=db_path,
149
  model_name=model,
150
  distance_metric="cosine",
151
- threshold=threshold
 
152
  )
153
-
154
  if isinstance(dfs, list):
155
  if len(dfs) == 0:
156
  return None, "No matching faces found in the database."
157
  df = dfs[0]
158
  else:
159
  df = dfs
160
-
161
  if df.empty:
162
  return None, "No matching faces found in the database."
163
-
164
  df = df.sort_values(by=["distance"])
165
-
166
  num_matches = min(4, len(df))
167
  fig, axes = plt.subplots(1, num_matches + 1, figsize=(15, 5))
168
-
169
  query_display = cv2.imread(query_path)
170
  query_display = cv2.cvtColor(query_display, cv2.COLOR_BGR2RGB)
171
  axes[0].imshow(query_display)
172
  axes[0].set_title("Query Image")
173
  axes[0].axis("off")
174
-
175
  for i in range(num_matches):
176
  match_path = df.iloc[i]["identity"]
 
 
 
177
  distance = df.iloc[i]["distance"]
178
  confidence = round((1 - distance) * 100, 2)
179
-
180
  match_img = cv2.imread(match_path)
 
 
 
181
  match_img = cv2.cvtColor(match_img, cv2.COLOR_BGR2RGB)
182
-
183
  axes[i+1].imshow(match_img)
184
  axes[i+1].set_title(f"Match #{i+1}\nConfidence: {confidence}%")
185
  axes[i+1].axis("off")
186
-
187
  plt.suptitle(f"Found {len(df)} matching faces", fontsize=16, fontweight='bold')
188
  plt.tight_layout()
189
-
190
  results = df[["identity", "distance"]].copy()
191
  results["confidence"] = (1 - results["distance"]) * 100
192
  results["confidence"] = results["confidence"].round(2)
193
  results = results.rename(columns={"identity": "Image Path"})
194
-
195
  os.remove(query_path)
196
  if not isinstance(db_folder, str):
197
  shutil.rmtree(db_path)
198
-
199
  return fig, results.to_dict('records')
200
-
201
  except Exception as e:
202
  if os.path.exists(query_path):
203
  os.remove(query_path)
204
-
205
  error_msg = f"Error: {str(e)}"
206
  if "No face detected" in str(e):
207
  error_msg = "No face detected in the query image. Please try a different image."
208
-
 
 
209
  return None, error_msg
210
 
211
  def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
212
  temp_dir = tempfile.mkdtemp()
213
  img_path = os.path.join(temp_dir, "analyze.jpg")
214
-
215
  if isinstance(img, np.ndarray):
216
  Image.fromarray(img).save(img_path)
217
  else:
218
  img.save(img_path)
219
-
220
  try:
221
  results = DeepFace.analyze(
222
  img_path=img_path,
@@ -224,55 +191,55 @@ def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
224
  enforce_detection=True,
225
  detector_backend='opencv'
226
  )
227
-
228
  if isinstance(results, list):
229
  num_faces = len(results)
230
  else:
231
  num_faces = 1
232
  results = [results]
233
-
234
  fig = plt.figure(figsize=(14, 7))
235
-
236
  img_display = cv2.imread(img_path)
237
  img_display = cv2.cvtColor(img_display, cv2.COLOR_BGR2RGB)
238
-
239
  main_ax = plt.subplot2grid((2, 4), (0, 0), colspan=2, rowspan=2)
240
  main_ax.imshow(img_display)
241
  main_ax.set_title(f"Analyzed Image ({num_faces} face{'s' if num_faces > 1 else ''} detected)")
242
  main_ax.axis('off')
243
-
244
  for i, face_result in enumerate(results):
245
  if i >= 4:
246
  break
247
-
248
  age = face_result.get('age', 'N/A')
249
  gender = face_result.get('dominant_gender', 'N/A')
250
  race = face_result.get('dominant_race', 'N/A')
251
  emotion = face_result.get('dominant_emotion', 'N/A')
252
-
253
  gender_conf = 'N/A'
254
  if 'gender' in face_result and isinstance(face_result['gender'], dict):
255
  for g, conf in face_result['gender'].items():
256
  if g.lower() == gender.lower():
257
  gender_conf = f"{conf:.1f}%"
258
  break
259
-
260
  race_conf = 'N/A'
261
  if 'race' in face_result and isinstance(face_result['race'], dict):
262
  for r, conf in face_result['race'].items():
263
  if r.lower() == race.lower():
264
  race_conf = f"{conf:.1f}%"
265
  break
266
-
267
  emotion_conf = 'N/A'
268
  if 'emotion' in face_result and isinstance(face_result['emotion'], dict):
269
  for e, conf in face_result['emotion'].items():
270
  if e.lower() == emotion.lower():
271
  emotion_conf = f"{conf:.1f}%"
272
  break
273
-
274
  ax = plt.subplot2grid((2, 4), (0 if i < 2 else 1, 2 + (i % 2)))
275
-
276
  text = (
277
  f"Face #{i+1}\n\n"
278
  f"Age: {age}\n\n"
@@ -280,15 +247,15 @@ def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
280
  f"Race: {race} ({race_conf})\n\n"
281
  f"Emotion: {emotion} ({emotion_conf})"
282
  )
283
-
284
  ax.text(0.5, 0.5, text, ha='center', va='center', fontsize=11)
285
  ax.axis('off')
286
-
287
  plt.tight_layout()
288
-
289
  os.remove(img_path)
290
  os.rmdir(temp_dir)
291
-
292
  formatted_results = []
293
  for i, res in enumerate(results[:8]):
294
  face_data = {
@@ -308,87 +275,93 @@ def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
308
  }
309
  }
310
  formatted_results.append(face_data)
311
-
312
  return fig, formatted_results
313
-
314
  except Exception as e:
315
  if os.path.exists(img_path):
316
  os.remove(img_path)
317
  if os.path.exists(temp_dir):
318
  os.rmdir(temp_dir)
319
-
320
  error_msg = f"Error: {str(e)}"
321
  if "No face detected" in str(e):
322
  error_msg = "No face detected in the image. Please try a different image."
323
-
324
  return None, error_msg
325
 
 
326
  with gr.Blocks(title="Complete Face Recognition Tool", theme=gr.themes.Soft()) as demo:
327
  gr.Markdown("""
328
  # 🔍 Complete Face Recognition Tool
 
329
  This tool provides three face recognition features:
330
  - **Verify Faces**: Compare two specific images to check if they contain the same person
331
  - **Find Faces**: Search for matching faces in a database/folder
332
  - **Analyze Face**: Determine age, gender, race, and emotion from a facial image
333
  """)
334
-
335
  with gr.Tabs():
336
  with gr.TabItem("Verify Faces"):
337
  with gr.Row():
338
  img1_input = gr.Image(label="First Image", type="pil")
339
  img2_input = gr.Image(label="Second Image", type="pil")
340
-
341
  with gr.Row():
342
- verify_threshold = gr.Slider(minimum=0.1, maximum=0.9, value=0.6, step=0.05,
343
  label="Similarity Threshold (lower = stricter matching)")
344
  verify_model = gr.Dropdown(
345
- choices=["VGG-Face", "Facenet", "OpenFace", "DeepFace", "ArcFace"],
346
- value="VGG-Face",
347
  label="Face Recognition Model"
348
  )
349
-
350
  verify_button = gr.Button("Verify Faces", variant="primary")
351
-
352
  verify_result_plot = gr.Plot(label="Verification Result")
353
  verify_json = gr.JSON(label="Technical Details")
354
-
355
  verify_button.click(
356
- verify_faces,
357
- inputs=[img1_input, img2_input, verify_threshold, verify_model],
358
  outputs=[verify_result_plot, verify_json]
359
  )
360
-
 
 
361
  with gr.TabItem("Find Faces"):
362
  query_img = gr.Image(label="Query Image (Face to find)", type="pil")
363
  db_path_input = gr.Textbox(label="Database Path (folder containing images to search in)")
364
  db_files_input = gr.File(label="Or upload images for database", file_count="multiple")
365
-
366
  with gr.Row():
367
- find_threshold = gr.Slider(minimum=0.1, maximum=0.9, value=0.6, step=0.05,
368
  label="Similarity Threshold (lower = stricter matching)")
369
  find_model = gr.Dropdown(
370
- choices=["VGG-Face", "Facenet", "OpenFace", "DeepFace", "ArcFace"],
371
- value="VGG-Face",
372
  label="Face Recognition Model"
373
  )
374
-
375
  find_button = gr.Button("Find Matching Faces", variant="primary")
376
-
377
  find_result_plot = gr.Plot(label="Search Results")
378
  find_results_table = gr.JSON(label="Detailed Results")
379
-
380
  find_button.click(
381
  find_faces,
382
  inputs=[query_img, db_path_input, find_threshold, find_model],
383
  outputs=[find_result_plot, find_results_table]
384
  )
385
-
386
  db_files_input.change(
387
  lambda x: "",
388
  inputs=db_files_input,
389
  outputs=db_path_input
390
  )
391
-
 
 
392
  with gr.TabItem("Analyze Face"):
393
  analyze_img = gr.Image(label="Upload Image for Analysis", type="pil")
394
  actions_checkboxes = gr.CheckboxGroup(
@@ -396,16 +369,19 @@ with gr.Blocks(title="Complete Face Recognition Tool", theme=gr.themes.Soft()) a
396
  value=["age", "gender", "race", "emotion"],
397
  label="Select Attributes to Analyze"
398
  )
399
-
400
  analyze_button = gr.Button("Analyze Face", variant="primary")
401
-
402
  analyze_result_plot = gr.Plot(label="Analysis Results")
403
  analyze_json = gr.JSON(label="Detailed Analysis")
404
-
405
  analyze_button.click(
406
  analyze_face,
407
  inputs=[analyze_img, actions_checkboxes],
408
  outputs=[analyze_result_plot, analyze_json]
409
  )
 
 
410
 
 
411
  demo.launch()
 
1
  # Install required packages
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import gradio as gr
3
  import json
4
  import cv2
5
  import numpy as np
6
+ from deepface import DeepFace
7
+ import matplotlib.pyplot as plt
8
  from PIL import Image
9
  import tempfile
10
+ import os
11
  import pandas as pd
12
  import shutil
 
 
 
 
13
 
14
  def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
15
  temp_dir = tempfile.mkdtemp()
16
  img1_path = os.path.join(temp_dir, "image1.jpg")
17
  img2_path = os.path.join(temp_dir, "image2.jpg")
18
+
19
  if isinstance(img1, np.ndarray):
20
  Image.fromarray(img1).save(img1_path)
21
  else:
22
  img1.save(img1_path)
23
+
24
  if isinstance(img2, np.ndarray):
25
  Image.fromarray(img2).save(img2_path)
26
  else:
27
  img2.save(img2_path)
28
+
29
  try:
30
  result = DeepFace.verify(
31
+ img1_path=img1_path,
32
  img2_path=img2_path,
33
  model_name=model,
34
  distance_metric="cosine",
35
  threshold=threshold
36
  )
37
+
38
  fig, ax = plt.subplots(1, 2, figsize=(10, 5))
39
+
40
  img1_display = cv2.imread(img1_path)
41
  img1_display = cv2.cvtColor(img1_display, cv2.COLOR_BGR2RGB)
42
  img2_display = cv2.imread(img2_path)
43
  img2_display = cv2.cvtColor(img2_display, cv2.COLOR_BGR2RGB)
44
+
45
  ax[0].imshow(img1_display)
46
  ax[0].set_title("Image 1")
47
  ax[0].axis("off")
48
+
49
  ax[1].imshow(img2_display)
50
  ax[1].set_title("Image 2")
51
  ax[1].axis("off")
52
+
53
  verification_result = "✅ FACE MATCHED" if result["verified"] else "❌ FACE NOT MATCHED"
54
  confidence = round((1 - result["distance"]) * 100, 2)
55
+
56
+ plt.suptitle(f"{verification_result}\nConfidence: {confidence}%\nDistance: {result['distance']:.4f}",
57
+ fontsize=16, fontweight='bold',
58
  color='green' if result["verified"] else 'red')
59
+
60
  plt.tight_layout()
61
+
62
  os.remove(img1_path)
63
  os.remove(img2_path)
64
  os.rmdir(temp_dir)
65
+
66
  return fig, json.dumps(result, indent=2)
67
+
68
  except Exception as e:
69
  if os.path.exists(img1_path):
70
  os.remove(img1_path)
 
72
  os.remove(img2_path)
73
  if os.path.exists(temp_dir):
74
  os.rmdir(temp_dir)
75
+
76
  error_msg = f"Error: {str(e)}"
77
  if "No face detected" in str(e):
78
  error_msg = "No face detected in one or both images. Please try different images."
79
+
80
  return None, error_msg
81
 
82
  def find_faces(query_img, db_folder, threshold=0.70, model="VGG-Face"):
83
  temp_dir = tempfile.mkdtemp()
84
  query_path = os.path.join(temp_dir, "query.jpg")
85
+
86
  if isinstance(query_img, np.ndarray):
87
  Image.fromarray(query_img).save(query_path)
88
  else:
89
  query_img.save(query_path)
90
+
91
  if isinstance(db_folder, str):
92
  db_path = db_folder
93
  else:
94
  db_path = os.path.join(temp_dir, "db")
95
  os.makedirs(db_path, exist_ok=True)
96
+
97
  for i, file in enumerate(db_folder):
98
+ orig_filename = file.orig_name # Get original filename with extension
99
+ file_ext = os.path.splitext(orig_filename)[1]
100
+ new_filename = f"image_{i}{file_ext}"
101
+ shutil.copy(file.name, os.path.join(db_path, new_filename))
102
+
103
  try:
104
  dfs = DeepFace.find(
105
  img_path=query_path,
106
  db_path=db_path,
107
  model_name=model,
108
  distance_metric="cosine",
109
+ threshold=threshold,
110
+ silent=True # Disable unnecessary logging
111
  )
112
+
113
  if isinstance(dfs, list):
114
  if len(dfs) == 0:
115
  return None, "No matching faces found in the database."
116
  df = dfs[0]
117
  else:
118
  df = dfs
119
+
120
  if df.empty:
121
  return None, "No matching faces found in the database."
122
+
123
  df = df.sort_values(by=["distance"])
124
+
125
  num_matches = min(4, len(df))
126
  fig, axes = plt.subplots(1, num_matches + 1, figsize=(15, 5))
127
+
128
  query_display = cv2.imread(query_path)
129
  query_display = cv2.cvtColor(query_display, cv2.COLOR_BGR2RGB)
130
  axes[0].imshow(query_display)
131
  axes[0].set_title("Query Image")
132
  axes[0].axis("off")
133
+
134
  for i in range(num_matches):
135
  match_path = df.iloc[i]["identity"]
136
+ if not os.path.exists(match_path):
137
+ continue # Skip invalid paths
138
+
139
  distance = df.iloc[i]["distance"]
140
  confidence = round((1 - distance) * 100, 2)
141
+
142
  match_img = cv2.imread(match_path)
143
+ if match_img is None:
144
+ continue # Skip unreadable images
145
+
146
  match_img = cv2.cvtColor(match_img, cv2.COLOR_BGR2RGB)
147
+
148
  axes[i+1].imshow(match_img)
149
  axes[i+1].set_title(f"Match #{i+1}\nConfidence: {confidence}%")
150
  axes[i+1].axis("off")
151
+
152
  plt.suptitle(f"Found {len(df)} matching faces", fontsize=16, fontweight='bold')
153
  plt.tight_layout()
154
+
155
  results = df[["identity", "distance"]].copy()
156
  results["confidence"] = (1 - results["distance"]) * 100
157
  results["confidence"] = results["confidence"].round(2)
158
  results = results.rename(columns={"identity": "Image Path"})
159
+
160
  os.remove(query_path)
161
  if not isinstance(db_folder, str):
162
  shutil.rmtree(db_path)
163
+
164
  return fig, results.to_dict('records')
165
+
166
  except Exception as e:
167
  if os.path.exists(query_path):
168
  os.remove(query_path)
169
+
170
  error_msg = f"Error: {str(e)}"
171
  if "No face detected" in str(e):
172
  error_msg = "No face detected in the query image. Please try a different image."
173
+ elif "No such file or directory" in str(e):
174
+ error_msg = "Invalid database path or corrupted image files"
175
+
176
  return None, error_msg
177
 
178
  def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
179
  temp_dir = tempfile.mkdtemp()
180
  img_path = os.path.join(temp_dir, "analyze.jpg")
181
+
182
  if isinstance(img, np.ndarray):
183
  Image.fromarray(img).save(img_path)
184
  else:
185
  img.save(img_path)
186
+
187
  try:
188
  results = DeepFace.analyze(
189
  img_path=img_path,
 
191
  enforce_detection=True,
192
  detector_backend='opencv'
193
  )
194
+
195
  if isinstance(results, list):
196
  num_faces = len(results)
197
  else:
198
  num_faces = 1
199
  results = [results]
200
+
201
  fig = plt.figure(figsize=(14, 7))
202
+
203
  img_display = cv2.imread(img_path)
204
  img_display = cv2.cvtColor(img_display, cv2.COLOR_BGR2RGB)
205
+
206
  main_ax = plt.subplot2grid((2, 4), (0, 0), colspan=2, rowspan=2)
207
  main_ax.imshow(img_display)
208
  main_ax.set_title(f"Analyzed Image ({num_faces} face{'s' if num_faces > 1 else ''} detected)")
209
  main_ax.axis('off')
210
+
211
  for i, face_result in enumerate(results):
212
  if i >= 4:
213
  break
214
+
215
  age = face_result.get('age', 'N/A')
216
  gender = face_result.get('dominant_gender', 'N/A')
217
  race = face_result.get('dominant_race', 'N/A')
218
  emotion = face_result.get('dominant_emotion', 'N/A')
219
+
220
  gender_conf = 'N/A'
221
  if 'gender' in face_result and isinstance(face_result['gender'], dict):
222
  for g, conf in face_result['gender'].items():
223
  if g.lower() == gender.lower():
224
  gender_conf = f"{conf:.1f}%"
225
  break
226
+
227
  race_conf = 'N/A'
228
  if 'race' in face_result and isinstance(face_result['race'], dict):
229
  for r, conf in face_result['race'].items():
230
  if r.lower() == race.lower():
231
  race_conf = f"{conf:.1f}%"
232
  break
233
+
234
  emotion_conf = 'N/A'
235
  if 'emotion' in face_result and isinstance(face_result['emotion'], dict):
236
  for e, conf in face_result['emotion'].items():
237
  if e.lower() == emotion.lower():
238
  emotion_conf = f"{conf:.1f}%"
239
  break
240
+
241
  ax = plt.subplot2grid((2, 4), (0 if i < 2 else 1, 2 + (i % 2)))
242
+
243
  text = (
244
  f"Face #{i+1}\n\n"
245
  f"Age: {age}\n\n"
 
247
  f"Race: {race} ({race_conf})\n\n"
248
  f"Emotion: {emotion} ({emotion_conf})"
249
  )
250
+
251
  ax.text(0.5, 0.5, text, ha='center', va='center', fontsize=11)
252
  ax.axis('off')
253
+
254
  plt.tight_layout()
255
+
256
  os.remove(img_path)
257
  os.rmdir(temp_dir)
258
+
259
  formatted_results = []
260
  for i, res in enumerate(results[:8]):
261
  face_data = {
 
275
  }
276
  }
277
  formatted_results.append(face_data)
278
+
279
  return fig, formatted_results
280
+
281
  except Exception as e:
282
  if os.path.exists(img_path):
283
  os.remove(img_path)
284
  if os.path.exists(temp_dir):
285
  os.rmdir(temp_dir)
286
+
287
  error_msg = f"Error: {str(e)}"
288
  if "No face detected" in str(e):
289
  error_msg = "No face detected in the image. Please try a different image."
290
+
291
  return None, error_msg
292
 
293
+ # Create Gradio interface
294
  with gr.Blocks(title="Complete Face Recognition Tool", theme=gr.themes.Soft()) as demo:
295
  gr.Markdown("""
296
  # 🔍 Complete Face Recognition Tool
297
+
298
  This tool provides three face recognition features:
299
  - **Verify Faces**: Compare two specific images to check if they contain the same person
300
  - **Find Faces**: Search for matching faces in a database/folder
301
  - **Analyze Face**: Determine age, gender, race, and emotion from a facial image
302
  """)
303
+
304
  with gr.Tabs():
305
  with gr.TabItem("Verify Faces"):
306
  with gr.Row():
307
  img1_input = gr.Image(label="First Image", type="pil")
308
  img2_input = gr.Image(label="Second Image", type="pil")
309
+
310
  with gr.Row():
311
+ verify_threshold = gr.Slider(minimum=0.1, maximum=0.9, value=0.6, step=0.05,
312
  label="Similarity Threshold (lower = stricter matching)")
313
  verify_model = gr.Dropdown(
314
+ choices=["VGG-Face", "Facenet", "OpenFace", "DeepFace", "ArcFace"],
315
+ value="VGG-Face",
316
  label="Face Recognition Model"
317
  )
318
+
319
  verify_button = gr.Button("Verify Faces", variant="primary")
320
+
321
  verify_result_plot = gr.Plot(label="Verification Result")
322
  verify_json = gr.JSON(label="Technical Details")
323
+
324
  verify_button.click(
325
+ verify_faces,
326
+ inputs=[img1_input, img2_input, verify_threshold, verify_model],
327
  outputs=[verify_result_plot, verify_json]
328
  )
329
+
330
+ gr.Markdown("""... (keep existing markdown) ...""")
331
+
332
  with gr.TabItem("Find Faces"):
333
  query_img = gr.Image(label="Query Image (Face to find)", type="pil")
334
  db_path_input = gr.Textbox(label="Database Path (folder containing images to search in)")
335
  db_files_input = gr.File(label="Or upload images for database", file_count="multiple")
336
+
337
  with gr.Row():
338
+ find_threshold = gr.Slider(minimum=0.1, maximum=0.9, value=0.6, step=0.05,
339
  label="Similarity Threshold (lower = stricter matching)")
340
  find_model = gr.Dropdown(
341
+ choices=["VGG-Face", "Facenet", "OpenFace", "DeepFace", "ArcFace"],
342
+ value="VGG-Face",
343
  label="Face Recognition Model"
344
  )
345
+
346
  find_button = gr.Button("Find Matching Faces", variant="primary")
347
+
348
  find_result_plot = gr.Plot(label="Search Results")
349
  find_results_table = gr.JSON(label="Detailed Results")
350
+
351
  find_button.click(
352
  find_faces,
353
  inputs=[query_img, db_path_input, find_threshold, find_model],
354
  outputs=[find_result_plot, find_results_table]
355
  )
356
+
357
  db_files_input.change(
358
  lambda x: "",
359
  inputs=db_files_input,
360
  outputs=db_path_input
361
  )
362
+
363
+ gr.Markdown("""... (keep existing markdown) ...""")
364
+
365
  with gr.TabItem("Analyze Face"):
366
  analyze_img = gr.Image(label="Upload Image for Analysis", type="pil")
367
  actions_checkboxes = gr.CheckboxGroup(
 
369
  value=["age", "gender", "race", "emotion"],
370
  label="Select Attributes to Analyze"
371
  )
372
+
373
  analyze_button = gr.Button("Analyze Face", variant="primary")
374
+
375
  analyze_result_plot = gr.Plot(label="Analysis Results")
376
  analyze_json = gr.JSON(label="Detailed Analysis")
377
+
378
  analyze_button.click(
379
  analyze_face,
380
  inputs=[analyze_img, actions_checkboxes],
381
  outputs=[analyze_result_plot, analyze_json]
382
  )
383
+
384
+ gr.Markdown("""... (keep existing markdown) ...""")
385
 
386
+ # Launch the app
387
  demo.launch()