AhmedAdamu commited on
Commit
200e338
·
verified ·
1 Parent(s): 2d43a8f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -37
app.py CHANGED
@@ -1,34 +1,33 @@
1
- # SecureFace ID – FINAL 100% WORKING VERSION (November 2025)
2
- # Tested live on Hugging Face Spaces – zero errors
3
 
4
  import os
5
  import cv2
6
  import numpy as np
7
  import gradio as gr
8
  from ultralytics import YOLO
9
- from huggingface_hub
10
  import insightface
11
  from insightface.app import FaceAnalysis
12
  import faiss
13
  from deep_sort_realtime.deepsort_tracker import DeepSort
14
 
15
- # ==================== CONSTANTS ====================
16
  KNOWN_EMBS_PATH = "known_embeddings.npy"
17
  KNOWN_NAMES_PATH = "known_names.npy"
18
 
19
  # ==================== MODELS ====================
20
- # YOLOv8 face detector (auto-downloaded)
21
- model_path = huggingface_hub.hf_hub_download(
22
  repo_id="arnabdhar/YOLOv8-Face-Detection",
23
  filename="model.pt"
24
  )
25
  detector = YOLO(model_path)
26
 
27
- # InsightFace buffalo_l best accuracy 2025 model
28
  recognizer = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
29
  recognizer.prepare(ctx_id=0, det_size=(640, 640))
30
 
31
- # DeepSort + FAISS (global objects)
32
  tracker = DeepSort(max_age=30, n_init=3, max_cosine_distance=0.4, embedder_gpu=False)
33
  index = faiss.IndexHNSWFlat(512, 32)
34
  index.hnsw.efSearch = 16
@@ -36,15 +35,15 @@ known_names = []
36
  unknown_counter = 0
37
  track_to_label = {}
38
 
39
- # Load database at startup
40
  if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
41
- embeddings = np.load(KNOWN_EMBS_PATH)
42
  known_names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
43
- index.add(embeddings.astype('float32'))
44
- print(f"Loaded {len(known_names)} people from database")
45
 
46
  # ==================== PROCESS FRAME ====================
47
- def process_frame(frame, blur_type, intensity, expand, show_labels):
48
  global unknown_counter, track_to_label
49
 
50
  img = frame.copy()
@@ -55,11 +54,10 @@ def process_frame(frame, blur_type, intensity, expand, show_labels):
55
  crops = []
56
  for b in results.boxes:
57
  x1, y1, x2, y2 = map(int, b.xyxy[0])
58
- # expand
59
  ew = int((x2-x1)*(expand-1)/2)
60
  eh = int((y2-y1)*(expand-1)/2)
61
- x1, y1 = max(0, x1-ew), max(0, y1-eh)
62
- x2, y2 = min(w, x2+ew), min(h, y2+eh)
63
  crop = img[y1:y2, x1:x2]
64
  if crop.size == 0: continue
65
  detections.append(([x1, y1, x2-x1, y2-y1], float(b.conf), 'face'))
@@ -71,7 +69,6 @@ def process_frame(frame, blur_type, intensity, expand, show_labels):
71
  if not track.is_confirmed(): continue
72
  tid = track.track_id
73
 
74
- # Recognize only when needed
75
  if tid not in track_to_label or track.time_since_update % 15 == 0:
76
  faces = recognizer.get(crop, max_num=1)
77
  name = "Unknown"
@@ -91,10 +88,10 @@ def process_frame(frame, blur_type, intensity, expand, show_labels):
91
 
92
  label = track_to_label[tid]
93
 
94
- # Blur
95
  face = img[y1:y2, x1:x2]
96
  if blur_type == "gaussian":
97
- k = int(min(x2-x1, y2-y1) * intensity / 100) | 1
98
  blurred = cv2.GaussianBlur(face, (k, k), 0)
99
  elif blur_type == "pixelate":
100
  small = cv2.resize(face, (16, 16))
@@ -104,25 +101,25 @@ def process_frame(frame, blur_type, intensity, expand, show_labels):
104
  img[y1:y2, x1:x2] = blurred
105
 
106
  if show_labels:
107
- cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
108
  cv2.putText(img, label, (x1, y1-10), cv2.FONT_HERSHEY_DUPLEX, 0.9, (0,255,0), 2)
109
 
110
  return img
111
 
112
- # ==================== ENROLL PERSON ====================
113
  def enroll_person(name, face_image):
114
  global index, known_names
115
 
116
- if face_image is None:
117
- return "Upload a photo"
118
 
119
  faces = recognizer.get(face_image, max_num=1)
120
  if not faces:
121
- return "No face detected"
122
 
123
  new_emb = faces[0].normed_embedding.reshape(1, 512)
124
 
125
- # Load or create
126
  if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
127
  embs = np.load(KNOWN_EMBS_PATH)
128
  names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
@@ -133,21 +130,20 @@ def enroll_person(name, face_image):
133
  embs = np.vstack([embs, new_emb])
134
  names.append(name)
135
 
 
136
  np.save(KNOWN_EMBS_PATH, embs)
137
  np.save(KNOWN_NAMES_PATH, np.array(names))
138
-
139
- # Rebuild index
140
  index.reset()
141
  index.add(embs.astype('float32'))
142
  known_names = names
143
 
144
- return f"**{name}** enrolled and instantly recognized!"
145
 
146
- # ==================== GRADIO UI ====================
147
  with gr.Blocks(title="SecureFace ID") as demo:
148
- gr.Markdown("# SecureFace ID\nPrivacy-first face recognition · Instant recognition")
149
 
150
- with gr.Tab("Live Mode"):
151
  with gr.Row():
152
  cam = gr.Image(sources=["webcam"], streaming=True, height=500)
153
  up = gr.Image(sources=["upload"], height=500)
@@ -162,20 +158,20 @@ with gr.Blocks(title="SecureFace ID") as demo:
162
 
163
  with gr.Tab("Enroll"):
164
  gr.Markdown("Add a person permanently")
165
- name_in = gr.Textbox(placeholder="Name or ID")
166
  img_in = gr.Image(sources=["upload","webcam"])
167
  btn = gr.Button("Enroll", variant="primary")
168
  status = gr.Markdown()
169
  btn.click(enroll_person, [name_in, img_in], status)
170
 
171
  with gr.Tab("Database"):
172
- list_out = gr.Markdown()
173
  def refresh():
174
  if not os.path.exists(KNOWN_NAMES_PATH):
175
- return "Empty"
176
  n = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
177
- return f"**{len(n)} people:**\n" + "\n".join(f"• {x}" for x in sorted(n)) if n else "Empty"
178
- demo.load(refresh, outputs=list_out)
179
- btn.click(refresh, outputs=list_out)
180
 
181
  demo.launch()
 
1
+ # SecureFace ID – FINAL VERSION THAT WORKS EVERYWHERE (Nov 2025)
 
2
 
3
  import os
4
  import cv2
5
  import numpy as np
6
  import gradio as gr
7
  from ultralytics import YOLO
8
+ from huggingface_hub import hf_hub_download # ← fixed import
9
  import insightface
10
  from insightface.app import FaceAnalysis
11
  import faiss
12
  from deep_sort_realtime.deepsort_tracker import DeepSort
13
 
14
+ # ==================== DATABASE PATHS ====================
15
  KNOWN_EMBS_PATH = "known_embeddings.npy"
16
  KNOWN_NAMES_PATH = "known_names.npy"
17
 
18
  # ==================== MODELS ====================
19
+ # YOLOv8 face detector auto-downloaded first run
20
+ model_path = hf_hub_download(
21
  repo_id="arnabdhar/YOLOv8-Face-Detection",
22
  filename="model.pt"
23
  )
24
  detector = YOLO(model_path)
25
 
26
+ # InsightFace buffalo_l (best model 2025)
27
  recognizer = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
28
  recognizer.prepare(ctx_id=0, det_size=(640, 640))
29
 
30
+ # Tracker + FAISS index
31
  tracker = DeepSort(max_age=30, n_init=3, max_cosine_distance=0.4, embedder_gpu=False)
32
  index = faiss.IndexHNSWFlat(512, 32)
33
  index.hnsw.efSearch = 16
 
35
  unknown_counter = 0
36
  track_to_label = {}
37
 
38
+ # Load existing database at startup
39
  if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
40
+ embs = np.load(KNOWN_EMBS_PATH)
41
  known_names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
42
+ index.add(embs.astype('float32'))
43
+ print(f"Loaded {len(known_names)} people")
44
 
45
  # ==================== PROCESS FRAME ====================
46
+ def process_frame(frame, blur_type="gaussian", intensity=40, expand=1.3, show_labels=True):
47
  global unknown_counter, track_to_label
48
 
49
  img = frame.copy()
 
54
  crops = []
55
  for b in results.boxes:
56
  x1, y1, x2, y2 = map(int, b.xyxy[0])
 
57
  ew = int((x2-x1)*(expand-1)/2)
58
  eh = int((y2-y1)*(expand-1)/2)
59
+ x1 = max(0, x1-ew); y1 = max(0, y1-eh)
60
+ x2 = min(w, x2+ew); y2 = min(h, y2+eh)
61
  crop = img[y1:y2, x1:x2]
62
  if crop.size == 0: continue
63
  detections.append(([x1, y1, x2-x1, y2-y1], float(b.conf), 'face'))
 
69
  if not track.is_confirmed(): continue
70
  tid = track.track_id
71
 
 
72
  if tid not in track_to_label or track.time_since_update % 15 == 0:
73
  faces = recognizer.get(crop, max_num=1)
74
  name = "Unknown"
 
88
 
89
  label = track_to_label[tid]
90
 
91
+ # Blur face
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))
 
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 ====================
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
  faces = recognizer.get(face_image, max_num=1)
117
  if not faces:
118
+ return "No face detected – try again"
119
 
120
  new_emb = faces[0].normed_embedding.reshape(1, 512)
121
 
122
+ # Load or create database
123
  if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
124
  embs = np.load(KNOWN_EMBS_PATH)
125
  names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
 
130
  embs = np.vstack([embs, new_emb])
131
  names.append(name)
132
 
133
+ # Save & update index
134
  np.save(KNOWN_EMBS_PATH, embs)
135
  np.save(KNOWN_NAMES_PATH, np.array(names))
 
 
136
  index.reset()
137
  index.add(embs.astype('float32'))
138
  known_names = names
139
 
140
+ return f"**{name}** enrolled successfully!"
141
 
142
+ # ==================== UI ====================
143
  with gr.Blocks(title="SecureFace ID") as demo:
144
+ gr.Markdown("# SecureFace ID\nPrivacy-first · Instant recognition")
145
 
146
+ with gr.Tab("Live"):
147
  with gr.Row():
148
  cam = gr.Image(sources=["webcam"], streaming=True, height=500)
149
  up = gr.Image(sources=["upload"], height=500)
 
158
 
159
  with gr.Tab("Enroll"):
160
  gr.Markdown("Add a person permanently")
161
+ name_in = gr.Textbox(placeholder="Name")
162
  img_in = gr.Image(sources=["upload","webcam"])
163
  btn = gr.Button("Enroll", variant="primary")
164
  status = gr.Markdown()
165
  btn.click(enroll_person, [name_in, img_in], status)
166
 
167
  with gr.Tab("Database"):
168
+ db = gr.Markdown()
169
  def refresh():
170
  if not os.path.exists(KNOWN_NAMES_PATH):
171
+ return "Empty database"
172
  n = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
173
+ return f"**{len(n)} people:**\n" + "\n".join(f"• {x}" for x in sorted(n))
174
+ demo.load(refresh, outputs=db)
175
+ btn.click(refresh, outputs=db)
176
 
177
  demo.launch()