vrfefavr commited on
Commit
811af8d
·
verified ·
1 Parent(s): 1724c8d

Update services/vision.py

Browse files
Files changed (1) hide show
  1. services/vision.py +53 -46
services/vision.py CHANGED
@@ -1,13 +1,14 @@
1
  import cv2
2
  import os
3
  import time
 
4
  from deepface import DeepFace
5
  from core.config import DETECTOR, MODELS, THRESHOLDS, MIN_FACE_AREA, REQUIRED_AVERAGE_CONFIDENCE
6
 
7
  def process_frame_synchronous(frame):
8
  """
9
- The Smart-Hard Pipeline:
10
- Calculates weighted average across models and returns failure details.
11
  """
12
  report = []
13
  pipeline_status = {"detected": 0, "identified": 0}
@@ -19,58 +20,64 @@ def process_frame_synchronous(frame):
19
  for face_obj in raw_faces:
20
  region = face_obj.get('facial_area', {})
21
  w, h = region.get('w', 0), region.get('h', 0)
22
-
23
- if (w * h) < MIN_FACE_AREA:
24
- continue
25
-
26
  x, y = region.get('x', 0), region.get('y', 0)
27
- cropped_face = frame[y:y+h, x:x+w]
28
- if cropped_face.size == 0: continue
29
-
30
- predictions = {}
31
- confidences = {}
32
 
33
- for model in MODELS:
34
- results = DeepFace.find(img_path=cropped_face, db_path="faces_db", model_name=model,
35
- enforce_detection=False, detector_backend="skip",
36
- distance_metric="cosine", silent=True)
37
-
38
- if len(results) > 0 and not results[0].empty:
39
- df = results[0].sort_values(by="distance")
40
- best_match = df.iloc[0]
41
- dist = best_match["distance"]
42
-
43
- # Convert distance to confidence (0.0 distance = 100%)
44
- conf = round((1.0 - dist) * 100, 1)
45
- name = os.path.basename(best_match['identity']).split('.')[0]
 
 
 
46
 
47
- predictions[model] = name
48
- confidences[model] = conf
49
- else:
50
- predictions[model] = "Unknown"
51
- confidences[model] = 0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- # --- SMART CONSENSUS LOGIC ---
54
- # 1. Check if they agree on the NAME
55
- all_names = [n for n in predictions.values() if n != "Unknown"]
56
- unique_names = set(all_names)
57
-
58
- avg_conf = sum(confidences.values()) / len(MODELS)
 
 
 
 
 
 
 
59
 
60
- if len(unique_names) == 1 and avg_conf >= REQUIRED_AVERAGE_CONFIDENCE:
61
- confirmed_name = all_names[0]
62
- report.append({"status": "match", "name": confirmed_name, "score": avg_conf})
63
- pipeline_status["identified"] += 1
64
- else:
65
- # Failure Report: Tell the user WHO we thought it was and WHAT the score was
66
- best_guess = "Unknown"
67
- if unique_names: best_guess = list(unique_names)[0]
68
- report.append({"status": "fail", "name": best_guess, "score": avg_conf})
69
 
70
  return report, pipeline_status
71
 
72
- except ValueError:
73
- return [], pipeline_status
74
  except Exception as e:
75
  print(f"🔴 Critical Pipeline Error: {e}")
76
  return [], pipeline_status
 
1
  import cv2
2
  import os
3
  import time
4
+ import base64
5
  from deepface import DeepFace
6
  from core.config import DETECTOR, MODELS, THRESHOLDS, MIN_FACE_AREA, REQUIRED_AVERAGE_CONFIDENCE
7
 
8
  def process_frame_synchronous(frame):
9
  """
10
+ The Visual-Hard Pipeline:
11
+ Identifies faces and returns base64 crops for debugging.
12
  """
13
  report = []
14
  pipeline_status = {"detected": 0, "identified": 0}
 
20
  for face_obj in raw_faces:
21
  region = face_obj.get('facial_area', {})
22
  w, h = region.get('w', 0), region.get('h', 0)
 
 
 
 
23
  x, y = region.get('x', 0), region.get('y', 0)
 
 
 
 
 
24
 
25
+ # Prepare face data structure
26
+ face_info = {
27
+ "status": "unknown",
28
+ "name": "Unknown",
29
+ "score": 0,
30
+ "box": {"x": x, "y": y, "w": w, "h": h},
31
+ "crop_b64": ""
32
+ }
33
+
34
+ # Generate Debug Crop
35
+ if w > 0 and h > 0 and x >= 0 and y >= 0:
36
+ cropped_face = frame[y:y+h, x:x+w]
37
+ if cropped_face.size != 0:
38
+ # Encode crop to base64 so user can see it in browser
39
+ _, buffer = cv2.imencode('.jpg', cropped_face)
40
+ face_info["crop_b64"] = "data:image/jpeg;base64," + base64.b64encode(buffer).decode('utf-8')
41
 
42
+ # Quality Gate
43
+ if (w * h) >= MIN_FACE_AREA:
44
+ # Recognition Logic
45
+ predictions = {}
46
+ confidences = {}
47
+ for model in MODELS:
48
+ results = DeepFace.find(img_path=cropped_face, db_path="faces_db", model_name=model,
49
+ enforce_detection=False, detector_backend="skip",
50
+ distance_metric="cosine", silent=True)
51
+
52
+ if len(results) > 0 and not results[0].empty:
53
+ df = results[0].sort_values(by="distance")
54
+ best_match = df.iloc[0]
55
+ conf = round((1.0 - best_match["distance"]) * 100, 1)
56
+ predictions[model] = os.path.basename(best_match['identity']).split('.')[0]
57
+ confidences[model] = conf
58
+ else:
59
+ predictions[model] = "Unknown"
60
+ confidences[model] = 0.0
61
 
62
+ all_names = [n for n in predictions.values() if n != "Unknown"]
63
+ unique_names = set(all_names)
64
+ avg_conf = sum(confidences.values()) / len(MODELS)
65
+
66
+ if len(unique_names) == 1 and avg_conf >= REQUIRED_AVERAGE_CONFIDENCE:
67
+ face_info["status"] = "match"
68
+ face_info["name"] = all_names[0]
69
+ face_info["score"] = avg_conf
70
+ pipeline_status["identified"] += 1
71
+ else:
72
+ face_info["status"] = "fail"
73
+ if unique_names: face_info["name"] = list(unique_names)[0]
74
+ face_info["score"] = avg_conf
75
 
76
+ report.append(face_info)
 
 
 
 
 
 
 
 
77
 
78
  return report, pipeline_status
79
 
80
+ except ValueError: return [], pipeline_status
 
81
  except Exception as e:
82
  print(f"🔴 Critical Pipeline Error: {e}")
83
  return [], pipeline_status