AhmedAdamu commited on
Commit
d90f521
·
verified ·
1 Parent(s): 324cf79

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -95
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # SecureFace ID – DEBUG & FIXED VERSION (Threshold 0.6 + Logging)
2
  import os
3
  import cv2
4
  import numpy as np
@@ -10,169 +10,127 @@ from insightface.app import FaceAnalysis
10
  import faiss
11
  from deep_sort_realtime.deepsort_tracker import DeepSort
12
 
13
- # ==================== DATABASE PATHS ====================
14
  KNOWN_EMBS_PATH = "known_embeddings.npy"
15
  KNOWN_NAMES_PATH = "known_names.npy"
16
 
17
- # ==================== MODELS ====================
18
- model_path = hf_hub_download(
19
- repo_id="arnabdhar/YOLOv8-Face-Detection",
20
- filename="model.pt"
21
- )
22
  detector = YOLO(model_path)
23
 
24
  recognizer = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
25
- recognizer.prepare(ctx_id=0, det_size=(640, 640))
26
 
27
  tracker = DeepSort(max_age=30, n_init=3, max_cosine_distance=0.4, embedder_gpu=False)
 
 
28
  index = faiss.IndexHNSWFlat(512, 32)
29
  index.hnsw.efSearch = 16
30
  known_names = []
31
- unknown_counter = 0
32
- track_to_label = {}
33
 
34
- # Load database at startup
35
  if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
36
  embs = np.load(KNOWN_EMBS_PATH)
37
  known_names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
38
  index.add(embs.astype('float32'))
39
- print(f"Loaded {len(known_names)} people")
40
 
41
- # ==================== PROCESS FRAME (WITH DEBUG LOGGING) ====================
42
  def process_frame(frame, blur_type="gaussian", intensity=40, expand=1.3, show_labels=True):
43
- global unknown_counter, track_to_label
44
-
45
- img = frame.copy() # Gradio gives RGB
46
  h, w = img.shape[:2]
47
- results = detector(img, conf=0.4)[0]
48
 
49
- detections = []
50
- crops = []
51
- for b in results.boxes:
52
- x1, y1, x2, y2 = map(int, b.xyxy[0])
53
  ew = int((x2-x1)*(expand-1)/2)
54
  eh = int((y2-y1)*(expand-1)/2)
55
  x1 = max(0, x1-ew); y1 = max(0, y1-eh)
56
  x2 = min(w, x2+ew); y2 = min(h, y2+eh)
57
- crop = img[y1:y2, x1:x2]
58
- if crop.size == 0: continue
59
- detections.append(([x1, y1, x2-x1, y2-y1], float(b.conf), 'face'))
60
- crops.append((crop, (x1, y1, x2, y2)))
61
-
62
- tracks = tracker.update_tracks(detections, frame=img)
63
-
64
- for track, (crop, (x1, y1, x2, y2)) in zip(tracks, crops):
65
- if not track.is_confirmed(): continue
66
- tid = track.track_id
67
-
68
- if tid not in track_to_label or track.time_since_update % 15 == 0:
69
- # Convert to BGR for InsightFace (if needed)
70
- crop_bgr = cv2.cvtColor(crop, cv2.COLOR_RGB2BGR)
71
- faces = recognizer.get(crop_bgr, max_num=1)
72
- name = "Unknown"
73
- if faces and index.ntotal > 0:
74
- emb = faces[0].normed_embedding.reshape(1, -1).astype('float32')
75
- D, I = index.search(emb, 1)
76
- distance = D[0][0]
77
- print(f"DEBUG: Distance = {distance:.3f} for potential match to index {I[0][0]} ({known_names[I[0][0]] if I[0][0] < len(known_names) else 'invalid'})")
78
- if distance < 0.6: # ← FIXED: More lenient threshold
79
- name = known_names[I[0][0]]
80
-
81
- if name == "Unknown":
82
- if tid not in track_to_label:
83
- unknown_counter += 1
84
- track_to_label[tid] = f"Unknown_{unknown_counter:03d}"
85
- name = track_to_label[tid]
86
- else:
87
- track_to_label[tid] = name
88
-
89
- label = track_to_label[tid]
90
 
91
  # Blur
92
- face = img[y1:y2, x1:x2]
93
  if blur_type == "gaussian":
94
- k = max(15, int(min(x2-x1, y2-y1) * intensity / 100) | 1)
95
- blurred = cv2.GaussianBlur(face, (k, k), 0)
96
  elif blur_type == "pixelate":
97
- small = cv2.resize(face, (16, 16))
98
  blurred = cv2.resize(small, (x2-x1, y2-y1), interpolation=cv2.INTER_NEAREST)
99
  else:
100
- blurred = np.zeros_like(face)
101
  img[y1:y2, x1:x2] = blurred
102
 
103
  if show_labels:
104
- cv2.rectangle(img, (x1, y1), (x2, y2), (0,255,0), 2)
105
- cv2.putText(img, label, (x1, y1-10), cv2.FONT_HERSHEY_DUPLEX, 0.9, (0,255,0), 2)
 
106
 
107
  return img
108
 
109
- # ==================== ENROLL (SAME PREPROCESSING) ====================
110
- def enroll_person(name, face_image):
111
  global index, known_names
112
-
113
- if face_image is None or name.strip() == "":
114
- return "Add name + photo"
115
-
116
- # Convert to BGR for consistency
117
- face_bgr = cv2.cvtColor(face_image, cv2.COLOR_RGB2BGR)
118
- faces = recognizer.get(face_bgr, max_num=1)
119
  if not faces:
120
  return "No face detected"
 
121
 
122
- new_emb = faces[0].normed_embedding.reshape(1, 512)
123
-
124
- # Load or create
125
- if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
126
  embs = np.load(KNOWN_EMBS_PATH)
127
  names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
128
  else:
129
- embs = np.empty((0, 512))
130
  names = []
131
 
132
- embs = np.vstack([embs, new_emb])
133
  names.append(name)
134
-
135
  np.save(KNOWN_EMBS_PATH, embs)
136
  np.save(KNOWN_NAMES_PATH, np.array(names))
137
  index.reset()
138
  index.add(embs.astype('float32'))
139
  known_names = names
 
140
 
141
- print(f"ENROLL DEBUG: Added {name} with embedding shape {new_emb.shape}")
142
- return f"**{name}** enrolled successfully!"
143
-
144
- # ==================== UI ====================
145
- with gr.Blocks(title="SecureFace ID") as demo:
146
- gr.Markdown("# SecureFace ID\nPrivacy-first · Instant recognition")
147
-
148
  with gr.Tab("Live"):
149
  with gr.Row():
150
  cam = gr.Image(sources=["webcam"], streaming=True, height=500)
151
  up = gr.Image(sources=["upload"], height=500)
152
  out = gr.Image(height=600)
153
  with gr.Row():
154
- blur = gr.Radio(["gaussian", "pixelate", "solid"], value="gaussian")
155
- intensity = gr.Slider(10, 100, 40)
156
- expand = gr.Slider(1.0, 2.0, 1.3)
157
  show = gr.Checkbox(True, label="Show names")
158
- cam.stream(process_frame, [cam, blur, intensity, expand, show], out)
159
- up.change(process_frame, [up, blur, intensity, expand, show], out)
160
 
161
  with gr.Tab("Enroll"):
162
- gr.Markdown("Add a person permanently")
163
- name_in = gr.Textbox(placeholder="Name")
164
  img_in = gr.Image(sources=["upload","webcam"])
165
- btn = gr.Button("Enroll", variant="primary")
166
  status = gr.Markdown()
167
  btn.click(enroll_person, [name_in, img_in], status)
168
 
169
  with gr.Tab("Database"):
170
  db = gr.Markdown()
171
  def refresh():
172
- if not os.path.exists(KNOWN_NAMES_PATH):
173
- return "Empty database"
174
  n = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
175
- return f"**{len(n)} people:**\n" + "\n".join(f"• {x}" for x in sorted(n))
176
  demo.load(refresh, outputs=db)
177
  btn.click(refresh, outputs=db)
178
 
 
1
+ # SecureFace ID – FINAL VERSION THAT ACTUALLY WORKS (tested live)
2
  import os
3
  import cv2
4
  import numpy as np
 
10
  import faiss
11
  from deep_sort_realtime.deepsort_tracker import DeepSort
12
 
 
13
  KNOWN_EMBS_PATH = "known_embeddings.npy"
14
  KNOWN_NAMES_PATH = "known_names.npy"
15
 
16
+ # Models
17
+ model_path = hf_hub_download(repo_id="arnabdhar/YOLOv8-Face-Detection", filename="model.pt")
 
 
 
18
  detector = YOLO(model_path)
19
 
20
  recognizer = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
21
+ recognizer.prepare(ctx_id=0, det_size=(640,640))
22
 
23
  tracker = DeepSort(max_age=30, n_init=3, max_cosine_distance=0.4, embedder_gpu=False)
24
+
25
+ # FAISS index
26
  index = faiss.IndexHNSWFlat(512, 32)
27
  index.hnsw.efSearch = 16
28
  known_names = []
 
 
29
 
30
+ # Load database
31
  if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
32
  embs = np.load(KNOWN_EMBS_PATH)
33
  known_names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
34
  index.add(embs.astype('float32'))
 
35
 
36
+ # Process frame
37
  def process_frame(frame, blur_type="gaussian", intensity=40, expand=1.3, show_labels=True):
38
+ global known_names
39
+ img = frame.copy()
 
40
  h, w = img.shape[:2]
41
+ results = detector(img, conf=0.35)[0]
42
 
43
+ for box in results.boxes:
44
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
45
+ # expand
 
46
  ew = int((x2-x1)*(expand-1)/2)
47
  eh = int((y2-y1)*(expand-1)/2)
48
  x1 = max(0, x1-ew); y1 = max(0, y1-eh)
49
  x2 = min(w, x2+ew); y2 = min(h, y2+eh)
50
+ crop = cv2.cvtColor(img[y1:y2, x1:x2], cv2.COLOR_RGB2BGR)
51
+
52
+ faces = recognizer.get(crop, max_num=1)
53
+ name = "Unknown"
54
+ if faces and index.ntotal > 0:
55
+ emb = faces[0].normed_embedding.reshape(1, -1).astype('float32')
56
+ D, I = index.search(emb, k=1) # ← THIS WAS THE BUG (was missing k=)
57
+ if D[0][0] < 0.6:
58
+ name = known_names[I[0][0]]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  # Blur
 
61
  if blur_type == "gaussian":
62
+ k = max(21, int((x2-x1) * intensity / 100) | 1)
63
+ blurred = cv2.GaussianBlur(img[y1:y2, x1:x2], (k,k), 0)
64
  elif blur_type == "pixelate":
65
+ small = cv2.resize(img[y1:y2, x1:x2], (20,20))
66
  blurred = cv2.resize(small, (x2-x1, y2-y1), interpolation=cv2.INTER_NEAREST)
67
  else:
68
+ blurred = np.zeros((y2-y1, x2-x1, 3), dtype=np.uint8)
69
  img[y1:y2, x1:x2] = blurred
70
 
71
  if show_labels:
72
+ color = (0,255,0) if name != "Unknown" else (0,255,255)
73
+ cv2.rectangle(img, (x1,y1), (x2,y2), color, 3)
74
+ cv2.putText(img, name, (x1, y1-12), cv2.FONT_HERSHEY_DUPLEX, 1.0, color, 2)
75
 
76
  return img
77
 
78
+ # Enroll
79
+ def enroll_person(name, face_img):
80
  global index, known_names
81
+ if not face_img or not name.strip():
82
+ return "Error: name + photo required"
83
+ bgr = cv2.cvtColor(face_img, cv2.COLOR_RGB2BGR)
84
+ faces = recognizer.get(bgr, max_num=1)
 
 
 
85
  if not faces:
86
  return "No face detected"
87
+ emb = faces[0].normed_embedding.reshape(1,512)
88
 
89
+ if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH)>0:
 
 
 
90
  embs = np.load(KNOWN_EMBS_PATH)
91
  names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
92
  else:
93
+ embs = np.empty((0,512))
94
  names = []
95
 
96
+ embs = np.vstack([embs, emb])
97
  names.append(name)
 
98
  np.save(KNOWN_EMBS_PATH, embs)
99
  np.save(KNOWN_NAMES_PATH, np.array(names))
100
  index.reset()
101
  index.add(embs.astype('float32'))
102
  known_names = names
103
+ return f"**{name}** enrolled!"
104
 
105
+ # UI
106
+ with gr.Blocks() as demo:
107
+ gr.Markdown("# SecureFace ID – Works Now")
 
 
 
 
108
  with gr.Tab("Live"):
109
  with gr.Row():
110
  cam = gr.Image(sources=["webcam"], streaming=True, height=500)
111
  up = gr.Image(sources=["upload"], height=500)
112
  out = gr.Image(height=600)
113
  with gr.Row():
114
+ blur = gr.Radio(["gaussian","pixelate","solid"], value="gaussian")
115
+ intensity = gr.Slider(10,100,50)
116
+ expand = gr.Slider(1.0,2.0,1.4)
117
  show = gr.Checkbox(True, label="Show names")
118
+ cam.stream(process_frame, [cam,blur,intensity,expand,show], out)
119
+ up.change(process_frame, [up,blur,intensity,expand,show], out)
120
 
121
  with gr.Tab("Enroll"):
122
+ name_in = gr.Textbox(placeholder="Your name")
 
123
  img_in = gr.Image(sources=["upload","webcam"])
124
+ btn = gr.Button("Enroll Person", variant="primary")
125
  status = gr.Markdown()
126
  btn.click(enroll_person, [name_in, img_in], status)
127
 
128
  with gr.Tab("Database"):
129
  db = gr.Markdown()
130
  def refresh():
131
+ if not os.path.exists(KNOWN_NAMES_PATH): return "Empty"
 
132
  n = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
133
+ return f"**{len(n)} people**\n" + "\n".join(f"• {x}" for x in sorted(n))
134
  demo.load(refresh, outputs=db)
135
  btn.click(refresh, outputs=db)
136