| import gradio as gr |
| import numpy as np |
| from PIL import Image |
| import os |
| import json |
| from datetime import datetime |
|
|
| |
| INSIGHTFACE_AVAILABLE = False |
| try: |
| from insightface.app.face_analysis import FaceAnalysis |
| import onnxruntime as ort |
| INSIGHTFACE_AVAILABLE = True |
| print("β InsightFace available") |
| except Exception as e: |
| print(f"InsightFace not available: {e}") |
| print("Will use demo mode") |
|
|
| class FaceMatchingSystem: |
| def __init__(self): |
| """Initialize the face matching system""" |
| self.app = None |
| self.face_database = {} |
| self.model_status = "Initializing..." |
| self.setup_models() |
| |
| def setup_models(self): |
| """Setup the face recognition models""" |
| try: |
| if INSIGHTFACE_AVAILABLE: |
| print("Attempting to load InsightFace models...") |
| try: |
| self.app = FaceAnalysis( |
| name='buffalo_l', |
| providers=['CPUExecutionProvider'] |
| ) |
| self.app.prepare(ctx_id=0, det_thresh=0.5, det_size=(640, 640)) |
| self.model_status = "β InsightFace models loaded successfully" |
| print(self.model_status) |
| return |
| except Exception as e: |
| print(f"Failed to load InsightFace models: {e}") |
| |
| |
| self.app = MockFaceApp() |
| self.model_status = "Demo mode active (InsightFace not available)" |
| print(self.model_status) |
| |
| except Exception as e: |
| print(f"Error in model setup: {e}") |
| self.app = MockFaceApp() |
| self.model_status = f"Demo mode (Error: {str(e)})" |
| |
| def extract_face_embedding(self, image): |
| """Extract face embedding from image""" |
| try: |
| if image is None: |
| return None, "No image provided" |
| |
| |
| if isinstance(image, Image.Image): |
| image_array = np.array(image.convert('RGB')) |
| else: |
| image_array = image |
| |
| |
| if hasattr(self.app, 'get'): |
| faces = self.app.get(image_array) |
| else: |
| return np.random.rand(512), "Demo mode: mock embedding generated" |
| |
| if len(faces) == 0: |
| return None, "No face detected in the image" |
| |
| |
| if len(faces) > 1: |
| faces = sorted(faces, key=lambda x: (x.bbox[2] - x.bbox[0]) * (x.bbox[3] - x.bbox[1]), reverse=True) |
| |
| face = faces[0] |
| embedding = face.embedding |
| confidence = getattr(face, 'det_score', 0.95) |
| |
| return embedding, f"Face detected (confidence: {confidence:.3f})" |
| |
| except Exception as e: |
| print(f"Error extracting face embedding: {e}") |
| return None, f"Error processing image: {str(e)}" |
| |
| def add_face_to_database(self, image, person_name): |
| """Add a face to the database""" |
| if not person_name or not person_name.strip(): |
| return "Please provide a valid person name", "" |
| |
| person_name = person_name.strip() |
| |
| embedding, message = self.extract_face_embedding(image) |
| if embedding is None: |
| return f"Failed to add {person_name}: {message}", "" |
| |
| |
| self.face_database[person_name] = { |
| 'embedding': embedding.tolist() if hasattr(embedding, 'tolist') else embedding, |
| 'added_at': datetime.now().isoformat() |
| } |
| |
| |
| self.save_database() |
| |
| return f"β Successfully added {person_name} to database ({message})", self.get_database_info() |
| |
| def match_face(self, image, threshold=0.6): |
| """Match a face against the database""" |
| if not self.face_database: |
| return "Database is empty. Please add faces first.", "", 0.0 |
| |
| embedding, message = self.extract_face_embedding(image) |
| if embedding is None: |
| return f"Face matching failed: {message}", "", 0.0 |
| |
| best_match = None |
| best_similarity = 0.0 |
| |
| for person_name, data in self.face_database.items(): |
| stored_embedding = np.array(data['embedding']) |
| |
| |
| similarity = np.dot(embedding, stored_embedding) / ( |
| np.linalg.norm(embedding) * np.linalg.norm(stored_embedding) |
| ) |
| |
| if similarity > best_similarity: |
| best_similarity = similarity |
| best_match = person_name |
| |
| if best_similarity >= threshold: |
| confidence_percentage = best_similarity * 100 |
| return ( |
| f"β Match Found: {best_match}", |
| f"Confidence: {confidence_percentage:.1f}%", |
| confidence_percentage |
| ) |
| else: |
| return ( |
| "β No match found", |
| f"Best similarity: {best_similarity*100:.1f}% (below threshold {threshold*100:.1f}%)", |
| best_similarity * 100 |
| ) |
| |
| def save_database(self): |
| """Save the face database""" |
| try: |
| with open('face_database.json', 'w') as f: |
| json.dump(self.face_database, f, indent=2) |
| except Exception as e: |
| print(f"Failed to save database: {e}") |
| |
| def load_database(self): |
| """Load the face database""" |
| try: |
| if os.path.exists('face_database.json'): |
| with open('face_database.json', 'r') as f: |
| self.face_database = json.load(f) |
| print(f"Loaded {len(self.face_database)} faces from database") |
| except Exception as e: |
| print(f"Failed to load database: {e}") |
| self.face_database = {} |
| |
| def get_database_info(self): |
| """Get information about the current database""" |
| if not self.face_database: |
| return "Database is empty" |
| |
| info = f"Database contains {len(self.face_database)} faces:\\n" |
| for name, data in self.face_database.items(): |
| added_date = data.get('added_at', 'Unknown')[:10] |
| info += f"β’ {name} (added: {added_date})\\n" |
| |
| return info |
| |
| def clear_database(self): |
| """Clear the entire database""" |
| self.face_database = {} |
| self.save_database() |
| return "Database cleared successfully", "" |
|
|
| class MockFaceApp: |
| """Mock face app for demo purposes when InsightFace is not available""" |
| def __init__(self): |
| self.face_counter = 0 |
| |
| def get(self, image): |
| if image is None: |
| return [] |
| |
| |
| image_hash = hash(str(np.array(image).mean())) % 1000 |
| |
| class MockFace: |
| def __init__(self, image_hash): |
| np.random.seed(image_hash) |
| self.embedding = np.random.rand(512) |
| self.embedding = self.embedding / np.linalg.norm(self.embedding) |
| self.det_score = 0.85 + (image_hash % 15) / 100 |
| self.bbox = [50, 50, 200, 200] |
| |
| return [MockFace(image_hash)] |
|
|
| |
| print("Initializing Face Matching System...") |
| face_system = FaceMatchingSystem() |
| face_system.load_database() |
|
|
| |
| with gr.Blocks(title="FaceMatch Pro") as demo: |
| |
| gr.Markdown("# π― FaceMatch Pro") |
| gr.Markdown("### Professional Face Recognition System") |
| |
| |
| status_display = gr.Textbox( |
| label="System Status", |
| value=face_system.model_status, |
| interactive=False |
| ) |
| |
| with gr.Tabs(): |
| |
| with gr.Tab("Add Face"): |
| gr.Markdown("### Add a face to the database") |
| |
| with gr.Row(): |
| with gr.Column(): |
| add_image = gr.Image(label="Upload Photo", type="pil") |
| person_name = gr.Textbox(label="Person Name", placeholder="Enter name...") |
| add_btn = gr.Button("Add to Database", variant="primary") |
| |
| with gr.Column(): |
| add_result = gr.Textbox(label="Result", lines=3) |
| database_info = gr.Textbox( |
| label="Database Info", |
| lines=6, |
| value=face_system.get_database_info() |
| ) |
| |
| add_btn.click( |
| face_system.add_face_to_database, |
| inputs=[add_image, person_name], |
| outputs=[add_result, database_info] |
| ) |
| |
| |
| with gr.Tab("Match Face"): |
| gr.Markdown("### Find face matches") |
| |
| with gr.Row(): |
| with gr.Column(): |
| match_image = gr.Image(label="Upload Photo to Match", type="pil") |
| threshold = gr.Slider( |
| minimum=0.3, |
| maximum=0.9, |
| value=0.6, |
| step=0.05, |
| label="Matching Threshold" |
| ) |
| match_btn = gr.Button("Find Matches", variant="primary") |
| |
| with gr.Column(): |
| match_result = gr.Textbox(label="Match Result", lines=2) |
| confidence_text = gr.Textbox(label="Confidence Details", lines=2) |
| confidence_score = gr.Number(label="Confidence Score (%)", precision=1) |
| |
| match_btn.click( |
| face_system.match_face, |
| inputs=[match_image, threshold], |
| outputs=[match_result, confidence_text, confidence_score] |
| ) |
| |
| |
| with gr.Tab("Database"): |
| gr.Markdown("### Database Management") |
| |
| db_stats = gr.Textbox( |
| label="Database Contents", |
| lines=8, |
| value=face_system.get_database_info() |
| ) |
| |
| with gr.Row(): |
| refresh_btn = gr.Button("Refresh Info", variant="secondary") |
| clear_btn = gr.Button("Clear Database", variant="stop") |
| |
| clear_result = gr.Textbox(label="Action Result", lines=2) |
| |
| refresh_btn.click( |
| lambda: face_system.get_database_info(), |
| outputs=[db_stats] |
| ) |
| |
| clear_btn.click( |
| face_system.clear_database, |
| outputs=[clear_result, db_stats] |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|