houloude9 commited on
Commit
a330172
·
verified ·
1 Parent(s): b341afc

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -0
app.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Facial Recognition Service with Gradio UI
4
+ Runs on Hugging Face Spaces
5
+ """
6
+
7
+ import warnings
8
+ import os
9
+ import sys
10
+ import numpy as np
11
+ import cv2
12
+ import insightface
13
+ from insightface.app import FaceAnalysis
14
+ import gradio as gr
15
+
16
+ # Suppress warnings and verbose logs
17
+ warnings.filterwarnings('ignore')
18
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
19
+ os.environ['ONNXRUNTIME_LOG_SEVERITY_LEVEL'] = '4'
20
+
21
+
22
+ class FacialRecognitionService:
23
+ def __init__(self):
24
+ """Initialize InsightFace model"""
25
+ self.app = FaceAnalysis(providers=['CPUExecutionProvider'])
26
+ self.app.prepare(ctx_id=0, det_size=(640, 640))
27
+
28
+ def extract_face_embedding(self, image: np.ndarray):
29
+ """Extract face embedding from an uploaded image (numpy array)"""
30
+ try:
31
+ # Convert BGR to RGB if needed
32
+ if image.shape[2] == 3:
33
+ img_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
34
+ else:
35
+ img_rgb = image
36
+
37
+ faces = self.app.get(img_rgb)
38
+ if len(faces) == 0:
39
+ return None
40
+
41
+ # Return embedding of the largest face
42
+ largest_face = max(faces, key=lambda x: (x.bbox[2]-x.bbox[0])*(x.bbox[3]-x.bbox[1]))
43
+ return largest_face.embedding
44
+
45
+ except Exception as e:
46
+ print(f"Error extracting embedding: {e}", file=sys.stderr)
47
+ return None
48
+
49
+ def calculate_similarity(self, emb1, emb2):
50
+ """Cosine similarity normalized to 0-1"""
51
+ try:
52
+ norm1, norm2 = np.linalg.norm(emb1), np.linalg.norm(emb2)
53
+ if norm1 == 0 or norm2 == 0:
54
+ return 0.0
55
+ emb1, emb2 = emb1 / norm1, emb2 / norm2
56
+ return float((np.dot(emb1, emb2) + 1) / 2)
57
+ except:
58
+ return 0.0
59
+
60
+ def match_faces(self, target_image: np.ndarray, candidate_images: list, threshold: float = 0.6):
61
+ """Compare target image to candidate images and return matches"""
62
+ matches = []
63
+ target_emb = self.extract_face_embedding(target_image)
64
+ if target_emb is None:
65
+ return "No face detected in target image"
66
+
67
+ for idx, candidate in enumerate(candidate_images):
68
+ candidate_emb = self.extract_face_embedding(candidate)
69
+ if candidate_emb is None:
70
+ continue
71
+ similarity = self.calculate_similarity(target_emb, candidate_emb)
72
+ if similarity >= threshold:
73
+ matches.append({
74
+ 'index': idx,
75
+ 'confidence': similarity,
76
+ 'score': int(similarity * 100)
77
+ })
78
+
79
+ if not matches:
80
+ return "No matches found"
81
+ return matches
82
+
83
+
84
+ # Initialize service
85
+ service = FacialRecognitionService()
86
+
87
+
88
+ # Gradio functions
89
+ def extract_face(image):
90
+ embedding = service.extract_face_embedding(image)
91
+ if embedding is None:
92
+ return "No face detected"
93
+ return embedding.tolist()
94
+
95
+
96
+ def match_faces(target_image, *candidate_images):
97
+ candidates = [img for img in candidate_images if img is not None]
98
+ result = service.match_faces(target_image, candidates)
99
+ return str(result)
100
+
101
+
102
+ # Gradio UI
103
+ with gr.Blocks() as demo:
104
+ gr.Markdown("## Facial Recognition Service (InsightFace)")
105
+
106
+ with gr.Tab("Extract Embedding"):
107
+ input_img = gr.Image(label="Upload Image")
108
+ output_embed = gr.Textbox(label="Face Embedding")
109
+ btn_extract = gr.Button("Extract")
110
+ btn_extract.click(fn=extract_face, inputs=input_img, outputs=output_embed)
111
+
112
+ with gr.Tab("Match Faces"):
113
+ target_img = gr.Image(label="Target Image")
114
+ candidate_imgs = [gr.Image(label=f"Candidate Image {i+1}") for i in range(5)]
115
+ output_matches = gr.Textbox(label="Matches")
116
+ btn_match = gr.Button("Match")
117
+ btn_match.click(fn=match_faces, inputs=[target_img] + candidate_imgs, outputs=output_matches)
118
+
119
+ demo.launch()