Update app.py
Browse files
app.py
CHANGED
@@ -123,91 +123,6 @@ def verify_faces(img1, img2, threshold=0.70, model="VGG-Face"):
|
|
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")
|
@@ -323,12 +238,11 @@ def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
|
|
323 |
|
324 |
return None, error_msg
|
325 |
|
326 |
-
with gr.Blocks(title="
|
327 |
gr.Markdown("""
|
328 |
-
# 🔍
|
329 |
-
This tool provides
|
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 |
|
@@ -358,37 +272,6 @@ with gr.Blocks(title="Complete Face Recognition Tool", theme=gr.themes.Soft()) a
|
|
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(
|
|
|
123 |
|
124 |
return None, error_msg
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
def analyze_face(img, actions=['age', 'gender', 'race', 'emotion']):
|
127 |
temp_dir = tempfile.mkdtemp()
|
128 |
img_path = os.path.join(temp_dir, "analyze.jpg")
|
|
|
238 |
|
239 |
return None, error_msg
|
240 |
|
241 |
+
with gr.Blocks(title="Face Recognition Tool", theme=gr.themes.Soft()) as demo:
|
242 |
gr.Markdown("""
|
243 |
+
# 🔍 Face Recognition Tool
|
244 |
+
This tool provides two main features:
|
245 |
- **Verify Faces**: Compare two specific images to check if they contain the same person
|
|
|
246 |
- **Analyze Face**: Determine age, gender, race, and emotion from a facial image
|
247 |
""")
|
248 |
|
|
|
272 |
outputs=[verify_result_plot, verify_json]
|
273 |
)
|
274 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
with gr.TabItem("Analyze Face"):
|
276 |
analyze_img = gr.Image(label="Upload Image for Analysis", type="pil")
|
277 |
actions_checkboxes = gr.CheckboxGroup(
|