Update app.py
Browse files
app.py
CHANGED
|
@@ -52,13 +52,21 @@ def get_embedding(face):
|
|
| 52 |
Preprocess the face and compute embedding using ArcFace ONNX model.
|
| 53 |
Fixed to match NHWC format (1, 112, 112, 3).
|
| 54 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
img = cv2.resize(face, (112, 112))
|
| 56 |
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
| 57 |
-
|
| 58 |
-
|
|
|
|
|
|
|
| 59 |
|
| 60 |
emb = arcface_sess.run(None, {arcface_input: img})[0][0]
|
| 61 |
-
|
|
|
|
|
|
|
| 62 |
return emb
|
| 63 |
|
| 64 |
# ------------------------------
|
|
@@ -127,10 +135,26 @@ def register_face(name, image):
|
|
| 127 |
else:
|
| 128 |
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
| 129 |
|
| 130 |
-
#
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
|
| 135 |
# Add to known faces dictionary
|
| 136 |
known_faces[name] = emb
|
|
@@ -211,7 +235,9 @@ def detect_and_recognize(image):
|
|
| 211 |
score = cosine_similarity([emb], [ref_emb])[0][0]
|
| 212 |
if score > best_score:
|
| 213 |
best_name, best_score = name, score
|
| 214 |
-
|
|
|
|
|
|
|
| 215 |
best_name = "Unknown"
|
| 216 |
cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2)
|
| 217 |
cv2.putText(img, f"{best_name} ({best_score:.2f})", (x1, y1-10),
|
|
|
|
| 52 |
Preprocess the face and compute embedding using ArcFace ONNX model.
|
| 53 |
Fixed to match NHWC format (1, 112, 112, 3).
|
| 54 |
"""
|
| 55 |
+
# Ensure face is not empty
|
| 56 |
+
if face.size == 0 or face.shape[0] < 10 or face.shape[1] < 10:
|
| 57 |
+
return None
|
| 58 |
+
|
| 59 |
img = cv2.resize(face, (112, 112))
|
| 60 |
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
|
| 61 |
+
|
| 62 |
+
# Normalize to [-1, 1] range for better feature extraction
|
| 63 |
+
img = (img.astype(np.float32) - 127.5) / 128.0
|
| 64 |
+
img = np.expand_dims(img, axis=0) # (1, 112, 112, 3)
|
| 65 |
|
| 66 |
emb = arcface_sess.run(None, {arcface_input: img})[0][0]
|
| 67 |
+
|
| 68 |
+
# L2 normalization
|
| 69 |
+
emb = emb / (np.linalg.norm(emb) + 1e-8)
|
| 70 |
return emb
|
| 71 |
|
| 72 |
# ------------------------------
|
|
|
|
| 135 |
else:
|
| 136 |
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
| 137 |
|
| 138 |
+
# Detect face first using YOLO to ensure good quality
|
| 139 |
+
results = yolo.predict(source=img, conf=0.25, verbose=False)
|
| 140 |
+
|
| 141 |
+
face_found = False
|
| 142 |
+
for r in results:
|
| 143 |
+
boxes = r.boxes
|
| 144 |
+
if len(boxes) > 0:
|
| 145 |
+
# Use the first detected face
|
| 146 |
+
box = boxes[0]
|
| 147 |
+
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
|
| 148 |
+
crop = img[y1:y2, x1:x2]
|
| 149 |
+
|
| 150 |
+
# Compute embedding from cropped face
|
| 151 |
+
emb = get_embedding(crop)
|
| 152 |
+
if emb is not None and not np.isnan(emb).any():
|
| 153 |
+
face_found = True
|
| 154 |
+
break
|
| 155 |
+
|
| 156 |
+
if not face_found:
|
| 157 |
+
return f"❌ No clear face detected for {name}. Please upload a clearer image with a visible face."
|
| 158 |
|
| 159 |
# Add to known faces dictionary
|
| 160 |
known_faces[name] = emb
|
|
|
|
| 235 |
score = cosine_similarity([emb], [ref_emb])[0][0]
|
| 236 |
if score > best_score:
|
| 237 |
best_name, best_score = name, score
|
| 238 |
+
|
| 239 |
+
# Lower threshold for better matching (0.35 instead of 0.45)
|
| 240 |
+
if best_score < 0.35:
|
| 241 |
best_name = "Unknown"
|
| 242 |
cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2)
|
| 243 |
cv2.putText(img, f"{best_name} ({best_score:.2f})", (x1, y1-10),
|