|
import gradio as gr |
|
import numpy as np |
|
from PIL import Image |
|
import os |
|
import json |
|
|
|
|
|
INSIGHTFACE_AVAILABLE = False |
|
try: |
|
from insightface.app.face_analysis import FaceAnalysis |
|
INSIGHTFACE_AVAILABLE = True |
|
print("β InsightFace available") |
|
except: |
|
print("InsightFace not available, using demo mode") |
|
|
|
|
|
face_app = None |
|
face_database = {} |
|
|
|
def setup_models(): |
|
global face_app |
|
if INSIGHTFACE_AVAILABLE: |
|
try: |
|
print("Loading InsightFace models...") |
|
face_app = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider']) |
|
face_app.prepare(ctx_id=0, det_thresh=0.5, det_size=(640, 640)) |
|
print("β InsightFace models loaded") |
|
except Exception as e: |
|
print(f"Failed to load InsightFace: {e}") |
|
|
|
def load_database(): |
|
global face_database |
|
try: |
|
if os.path.exists('faces.json'): |
|
with open('faces.json', 'r') as f: |
|
face_database = json.load(f) |
|
print(f"Loaded {len(face_database)} faces from database") |
|
except: |
|
face_database = {} |
|
|
|
def save_database(): |
|
try: |
|
with open('faces.json', 'w') as f: |
|
json.dump(face_database, f) |
|
except: |
|
pass |
|
|
|
def get_embedding(image): |
|
global face_app |
|
if not face_app or not image: |
|
if image is not None: |
|
seed = int(np.array(image).mean() * 1000) % 1000 |
|
np.random.seed(seed) |
|
emb = np.random.rand(512) |
|
return emb / np.linalg.norm(emb), "Demo embedding" |
|
return None, "No image" |
|
|
|
try: |
|
img_array = np.array(image.convert('RGB')) |
|
faces = face_app.get(img_array) |
|
if not faces: |
|
return None, "No face detected" |
|
face = faces[0] |
|
return face.embedding, f"Face detected (confidence: {face.det_score:.2f})" |
|
except Exception as e: |
|
return None, f"Error: {str(e)}" |
|
|
|
def add_face(image, name): |
|
if not name or not name.strip(): |
|
return "Please enter a name" |
|
|
|
name = name.strip() |
|
embedding, msg = get_embedding(image) |
|
|
|
if embedding is None: |
|
return f"Failed: {msg}" |
|
|
|
face_database[name] = embedding.tolist() |
|
save_database() |
|
|
|
return f"β Added {name} ({msg}). Database now has {len(face_database)} faces." |
|
|
|
def match_face(image): |
|
if not face_database: |
|
return "Database is empty. Please add faces first." |
|
|
|
if not image: |
|
return "Please upload an image" |
|
|
|
embedding, msg = get_embedding(image) |
|
if embedding is None: |
|
return f"Failed: {msg}" |
|
|
|
best_match = None |
|
best_score = -1 |
|
|
|
for name, stored_emb in face_database.items(): |
|
stored_emb = np.array(stored_emb) |
|
score = np.dot(embedding, stored_emb) / (np.linalg.norm(embedding) * np.linalg.norm(stored_emb)) |
|
if score > best_score: |
|
best_score = score |
|
best_match = name |
|
|
|
if best_score > 0.6: |
|
return f"β Match Found: {best_match} (confidence: {best_score*100:.1f}%)" |
|
else: |
|
return f"β No match found. Best score: {best_score*100:.1f}% (threshold: 60%)" |
|
|
|
def get_status(): |
|
status = "β InsightFace loaded" if face_app else "Demo mode" |
|
db_count = len(face_database) |
|
return f"System: {status} | Database: {db_count} faces" |
|
|
|
def clear_database(): |
|
global face_database |
|
face_database = {} |
|
save_database() |
|
return "Database cleared successfully" |
|
|
|
|
|
print("Starting FaceMatch system...") |
|
setup_models() |
|
load_database() |
|
|
|
css = """ |
|
#col-left { |
|
margin: 0 auto; |
|
max-width: 450px; |
|
} |
|
#col-right { |
|
margin: 0 auto; |
|
max-width: 450px; |
|
} |
|
""" |
|
|
|
with gr.Blocks(css=css) as demo: |
|
gr.HTML(""" |
|
<div style="text-align: center; margin-bottom: 20px;"> |
|
<h1>π― FaceMatch Pro</h1> |
|
<p>Professional Face Recognition System</p> |
|
</div> |
|
""") |
|
|
|
with gr.Row(): |
|
with gr.Column(elem_id="col-left"): |
|
gr.HTML(""" |
|
<div style="text-align: center; font-size: 18px; margin-bottom: 10px;"> |
|
<b>π₯ Add Face to Database</b> |
|
</div> |
|
""") |
|
add_image = gr.Image(label="Upload Photo", sources='upload', type="pil") |
|
add_name = gr.Textbox(label="Person Name", placeholder="Enter name...") |
|
add_button = gr.Button("Add to Database", variant="primary") |
|
add_result = gr.Textbox(label="Result") |
|
|
|
with gr.Column(elem_id="col-right"): |
|
gr.HTML(""" |
|
<div style="text-align: center; font-size: 18px; margin-bottom: 10px;"> |
|
<b>π Find Face Match</b> |
|
</div> |
|
""") |
|
match_image = gr.Image(label="Upload Photo to Match", sources='upload', type="pil") |
|
match_button = gr.Button("Find Match", variant="primary") |
|
match_result = gr.Textbox(label="Match Result") |
|
|
|
gr.HTML("<hr>") |
|
|
|
with gr.Row(): |
|
status_button = gr.Button("Check Status") |
|
clear_button = gr.Button("Clear Database", variant="stop") |
|
status_output = gr.Textbox(label="System Status") |
|
|
|
|
|
add_button.click(fn=add_face, inputs=[add_image, add_name], outputs=add_result) |
|
match_button.click(fn=match_face, inputs=match_image, outputs=match_result) |
|
status_button.click(fn=get_status, outputs=status_output) |
|
clear_button.click(fn=clear_database, outputs=status_output) |
|
|
|
if __name__ == "__main__": |
|
demo.launch() |
|
|