Spaces:
Sleeping
Sleeping
Update services/vision.py
Browse files- services/vision.py +49 -53
services/vision.py
CHANGED
|
@@ -9,22 +9,22 @@ from core.state import KNOWN_VECTORS
|
|
| 9 |
|
| 10 |
def process_frame_synchronous(frame):
|
| 11 |
"""
|
| 12 |
-
|
| 13 |
-
1.
|
| 14 |
-
2.
|
| 15 |
-
3.
|
| 16 |
"""
|
| 17 |
report = []
|
| 18 |
pipeline_status = {"detected": 0, "identified": 0}
|
| 19 |
|
| 20 |
try:
|
|
|
|
| 21 |
raw_faces = DeepFace.extract_faces(img_path=frame, detector_backend=DETECTOR, enforce_detection=True, align=True)
|
| 22 |
pipeline_status["detected"] = len(raw_faces)
|
| 23 |
|
| 24 |
for face_obj in raw_faces:
|
| 25 |
region = face_obj.get('facial_area', {})
|
| 26 |
-
w, h = region.get('w', 0), region.get('h', 0)
|
| 27 |
-
x, y = region.get('x', 0), region.get('y', 0)
|
| 28 |
|
| 29 |
face_info = {
|
| 30 |
"status": "unknown", "name": "Unknown", "score": 0,
|
|
@@ -32,68 +32,64 @@ def process_frame_synchronous(frame):
|
|
| 32 |
"crop_b64": ""
|
| 33 |
}
|
| 34 |
|
| 35 |
-
if w > 0 and h > 0
|
| 36 |
cropped_face = frame[y:y+h, x:x+w]
|
| 37 |
if cropped_face.size != 0:
|
| 38 |
-
#
|
| 39 |
-
|
| 40 |
-
_, buffer = cv2.imencode('.jpg', cropped_face, encode_param)
|
| 41 |
face_info["crop_b64"] = "data:image/jpeg;base64," + base64.b64encode(buffer).decode('utf-8')
|
| 42 |
|
| 43 |
if (w * h) >= MIN_FACE_AREA:
|
| 44 |
-
|
| 45 |
-
predictions = {}
|
| 46 |
-
confidences = {}
|
| 47 |
|
| 48 |
-
# 1. Get current embeddings for the crop
|
| 49 |
for model in MODELS:
|
| 50 |
try:
|
|
|
|
| 51 |
emb_objs = DeepFace.represent(img_path=cropped_face, model_name=model,
|
| 52 |
enforce_detection=False, detector_backend="skip")
|
| 53 |
-
if emb_objs:
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
# Cosine Distance = 1 - dot_product (since both are normalized)
|
| 66 |
-
dist = 1 - np.dot(v_curr, v_known)
|
| 67 |
-
conf = round((1.0 - dist) * 100, 1)
|
| 68 |
-
|
| 69 |
-
if dist < THRESHOLDS[model] and conf > best_conf:
|
| 70 |
-
best_name = name
|
| 71 |
-
best_conf = conf
|
| 72 |
-
|
| 73 |
-
predictions[model] = best_name
|
| 74 |
-
confidences[model] = best_conf
|
| 75 |
-
except:
|
| 76 |
-
predictions[model] = "Unknown"
|
| 77 |
-
confidences[model] = 0.0
|
| 78 |
|
| 79 |
# --- SMART CONSENSUS ---
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
|
|
|
| 93 |
|
| 94 |
report.append(face_info)
|
| 95 |
return report, pipeline_status
|
| 96 |
-
except ValueError: return [], pipeline_status
|
| 97 |
except Exception as e:
|
| 98 |
-
print(f"🔴 AI Core Error: {e}")
|
| 99 |
return [], pipeline_status
|
|
|
|
| 9 |
|
| 10 |
def process_frame_synchronous(frame):
|
| 11 |
"""
|
| 12 |
+
ULTRA-FAST VECTORIZED PIPELINE:
|
| 13 |
+
1. Optimized Detection.
|
| 14 |
+
2. Parallel-Ready Feature Extraction.
|
| 15 |
+
3. Matrix-Multiplication Search (1ms response time).
|
| 16 |
"""
|
| 17 |
report = []
|
| 18 |
pipeline_status = {"detected": 0, "identified": 0}
|
| 19 |
|
| 20 |
try:
|
| 21 |
+
# Optimized Detection pass
|
| 22 |
raw_faces = DeepFace.extract_faces(img_path=frame, detector_backend=DETECTOR, enforce_detection=True, align=True)
|
| 23 |
pipeline_status["detected"] = len(raw_faces)
|
| 24 |
|
| 25 |
for face_obj in raw_faces:
|
| 26 |
region = face_obj.get('facial_area', {})
|
| 27 |
+
w, h, x, y = region.get('w', 0), region.get('h', 0), region.get('x', 0), region.get('y', 0)
|
|
|
|
| 28 |
|
| 29 |
face_info = {
|
| 30 |
"status": "unknown", "name": "Unknown", "score": 0,
|
|
|
|
| 32 |
"crop_b64": ""
|
| 33 |
}
|
| 34 |
|
| 35 |
+
if w > 0 and h > 0:
|
| 36 |
cropped_face = frame[y:y+h, x:x+w]
|
| 37 |
if cropped_face.size != 0:
|
| 38 |
+
# Quick JPEG encoding for UI debug
|
| 39 |
+
_, buffer = cv2.imencode('.jpg', cropped_face, [int(cv2.IMWRITE_JPEG_QUALITY), 70])
|
|
|
|
| 40 |
face_info["crop_b64"] = "data:image/jpeg;base64," + base64.b64encode(buffer).decode('utf-8')
|
| 41 |
|
| 42 |
if (w * h) >= MIN_FACE_AREA:
|
| 43 |
+
model_predictions = []
|
|
|
|
|
|
|
| 44 |
|
|
|
|
| 45 |
for model in MODELS:
|
| 46 |
try:
|
| 47 |
+
# Get current embedding
|
| 48 |
emb_objs = DeepFace.represent(img_path=cropped_face, model_name=model,
|
| 49 |
enforce_detection=False, detector_backend="skip")
|
| 50 |
+
if not emb_objs: continue
|
| 51 |
+
|
| 52 |
+
v_curr = np.array(emb_objs[0]["embedding"])
|
| 53 |
+
v_curr = v_curr / np.linalg.norm(v_curr) # Normalize
|
| 54 |
+
|
| 55 |
+
# --- HIGH SPEED MATRIX SEARCH ---
|
| 56 |
+
# Extract all known names and their vectors for this specific model
|
| 57 |
+
names = list(KNOWN_VECTORS.keys())
|
| 58 |
+
vectors = np.array([KNOWN_VECTORS[n][model] for n in names if model in KNOWN_VECTORS[n]])
|
| 59 |
+
|
| 60 |
+
if len(vectors) > 0:
|
| 61 |
+
# Calculate all Cosine Similarities in ONE math operation (Dot Product)
|
| 62 |
+
# Similarity = dot(v_curr, v_matrix.T)
|
| 63 |
+
similarities = np.dot(vectors, v_curr)
|
| 64 |
+
best_idx = np.argmax(similarities)
|
| 65 |
+
best_sim = similarities[best_idx]
|
| 66 |
+
dist = 1 - best_sim
|
| 67 |
|
| 68 |
+
if dist < THRESHOLDS[model]:
|
| 69 |
+
model_predictions.append({
|
| 70 |
+
"name": names[best_idx],
|
| 71 |
+
"conf": round(best_sim * 100, 1)
|
| 72 |
+
})
|
| 73 |
+
except Exception as e:
|
| 74 |
+
print(f"Model Error ({model}): {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
# --- SMART CONSENSUS ---
|
| 77 |
+
if model_predictions:
|
| 78 |
+
# If we have multiple models, they must agree
|
| 79 |
+
unique_names = set(p["name"] for p in model_predictions)
|
| 80 |
+
avg_conf = sum(p["conf"] for p in model_predictions) / len(MODELS)
|
| 81 |
+
|
| 82 |
+
if len(unique_names) == 1 and avg_conf >= REQUIRED_AVERAGE_CONFIDENCE:
|
| 83 |
+
face_info["status"] = "match"
|
| 84 |
+
face_info["name"] = list(unique_names)[0]
|
| 85 |
+
face_info["score"] = avg_conf
|
| 86 |
+
pipeline_status["identified"] += 1
|
| 87 |
+
else:
|
| 88 |
+
face_info["status"] = "fail"
|
| 89 |
+
face_info["name"] = model_predictions[0]["name"]
|
| 90 |
+
face_info["score"] = avg_conf
|
| 91 |
|
| 92 |
report.append(face_info)
|
| 93 |
return report, pipeline_status
|
|
|
|
| 94 |
except Exception as e:
|
|
|
|
| 95 |
return [], pipeline_status
|