Spaces:
Sleeping
Sleeping
File size: 7,041 Bytes
9e9b090 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | # --- Hugging Face fixes (add these 4 lines at the very top) ---
import os
if os.path.exists("/usr/bin/apt"):
import subprocess, sys
subprocess.check_call([sys.executable, "-m", "pip", "install", "insightface==0.7.3", "faiss-gpu", "deep-sort-realtime", "ultralytics", "onnxruntime-gpu", "--no-cache-dir"])
# ---------------------------------------------------------------
# SECUREFACE ID - FINAL UNIFIED APP
# Privacy by default + Accurate Recognition + Persistent Tracking
# Combines your two perfect apps into one
import os
import cv2
import numpy as np
import gradio as gr
from ultralytics import YOLO
import insightface
from insightface.app import FaceAnalysis
import faiss
from deep_sort_realtime.deepsort_tracker import DeepSort
from pathlib import Path
# ==================== 1. MODELS & DATABASE ====================
detector = YOLO("yolov8n-face.pt")
recognizer = FaceAnalysis(name='buffalo_l', providers=['CUDAExecutionProvider'])
recognizer.prepare(ctx_id=0, det_size=(640,640))
# FAISS index for known faces
KNOWN_EMBS_PATH = "known_embeddings.npy"
KNOWN_NAMES_PATH = "known_names.npy"
index = None
known_names = []
if os.path.exists(KNOWN_EMBS_PATH):
embeddings = np.load(KNOWN_EMBS_PATH)
known_names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
dim = embeddings.shape[1]
index = faiss.IndexHNSWFlat(dim, 32)
index.hnsw.efSearch = 16
index.add(embeddings.astype('float32'))
print(f"Loaded {len(known_names)} known people")
# Tracker for persistent IDs
tracker = DeepSort(max_age=30, n_init=3, max_cosine_distance=0.4, nn_budget=None, embedder_gpu=True)
unknown_counter = 0
track_to_label = {} # track_id → "Alice" or "Unknown_003"
# ==================== 2. CORE PROCESSING FUNCTION ====================
def process_frame(frame: np.ndarray, blur_type: str = "gaussian", intensity: float = 30, expand: float = 1.2, show_labels: bool = True):
global unknown_counter, track_to_label
img = frame.copy()
h, w = img.shape[:2]
# Detect faces
results = detector(img, conf=0.4)[0]
detections = []
crops = []
for box in results.boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0])
# Expand bbox
expand_w = int((x2 - x1) * (expand - 1) / 2)
expand_h = int((y2 - y1) * (expand - 1) / 2)
x1 = max(0, x1 - expand_w)
y1 = max(0, y1 - expand_h)
x2 = min(w, x2 + expand_w)
y2 = min(h, y2 + expand_h)
crop = img[y1:y2, x1:x2]
if crop.size == 0: continue
detections.append(([x1, y1, x2-x1, y2-y1], box.conf[0].item(), 'face'))
crops.append((crop, (x1, y1, x2, y2)))
# Track
tracks = tracker.update_tracks(detections, frame=img)
for track, (crop, (x1, y1, x2, y2)) in zip(tracks, crops):
if not track.is_confirmed(): continue
track_id = track.track_id
# Recognize only when needed
if track_id not in track_to_label or track.time_since_update % 15 == 0:
faces = recognizer.get(crop, max_num=1)
name = "Unknown"
if faces and index is not None:
emb = faces[0].normed_embedding.reshape(1, -1).astype('float32')
D, I = index.search(emb, k=1)
if D[0][0] < 0.45:
name = known_names[I[0][0]]
if name == "Unknown":
if track_id not in track_to_label:
unknown_counter += 1
track_to_label[track_id] = f"Unknown_{unknown_counter:03d}"
name = track_to_label[track_id]
else:
track_to_label[track_id] = name
label = track_to_label.get(track_id, "Unknown")
# ALWAYS BLUR
face_region = img[y1:y2, x1:x2]
if blur_type == "gaussian":
k = int(min(x2-x1, y2-y1) * (intensity / 100)) | 1
blurred = cv2.GaussianBlur(face_region, (k, k), 0)
elif blur_type == "pixelate":
small = cv2.resize(face_region, (20, 20), interpolation=cv2.INTER_LINEAR)
blurred = cv2.resize(small, (x2-x1, y2-y1), interpolation=cv2.INTER_NEAREST)
else: # solid
blurred = np.zeros_like(face_region)
blurred[:] = (0, 0, 0)
img[y1:y2, x1:x2] = blurred
# Optional: show label
if show_labels:
color = (0, 255, 0) if "Unknown" not in label else (0, 255, 255)
cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
cv2.putText(img, label, (x1, y1-10), cv2.FONT_HERSHEY_DUPLEX, 0.9, color, 2)
return img
# ==================== 3. ENROLLMENT FUNCTION ====================
def enroll_person(name: str, face_image: np.ndarray):
global index, known_names
if face_image is None:
return "Please upload a clear face photo"
faces = recognizer.get(face_image, max_num=1)
if not faces:
return "No face detected! Please try a clearer photo."
emb = faces[0].normed_embedding
# Save to disk
embs = np.load(KNOWN_EMBS_PATH) if os.path.exists(KNOWN_EMBS_PATH) else np.empty((0, 512))
names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist() if os.path.exists(KNOWN_NAMES_PATH) else []
embs = np.vstack([embs, emb])
names.append(name)
np.save(KNOWN_EMBS_PATH, embs)
np.save(KNOWN_NAMES_PATH, np.array(names))
# Rebuild index
dim = 512
index = faiss.IndexHNSWFlat(dim, 32)
index.add(embs.astype('float32'))
known_names = names
return f"Successfully enrolled: {name}"
# ==================== 4. GRADIO UI ====================
with gr.Blocks(title="SecureFace ID – Privacy-First Recognition", theme=gr.themes.Soft()) as demo:
gr.Markdown("# SecureFace ID")
gr.Markdown("**Every face is always blurred • Only authorized people are identified • Persistent tracking**")
with gr.Tab("Live Privacy Mode"):
with gr.Row():
inp = gr.Image(sources=["webcam", "upload"], streaming=True, height=600)
out = gr.Image(height=600)
with gr.Row():
blur_type = gr.Radio(["gaussian", "pixelate", "solid"], value="gaussian", label="Blur Style")
intensity = gr.Slider(10, 100, 40, label="Blur Intensity")
expand = gr.Slider(1.0, 2.0, 1.3, label="Blur Area Size")
show_labels = gr.Checkbox(True, label="Show Names / Unknown IDs")
inp.stream(process_frame, [inp, blur_type, intensity, expand, show_labels], out)
with gr.Tab("Enroll New Person"):
gr.Markdown("### Add someone to the database")
name_in = gr.Textbox(label="Full Name or ID", placeholder="Alice Smith")
img_in = gr.Image(label="Clear face photo", sources=["upload", "webcam"])
btn = gr.Button("Enroll Person", variant="primary")
status = gr.Markdown()
btn.click(enroll_person, [name_in, img_in], status)
with gr.Tab("Database"):
gr.Markdown(f"**{len(known_names)} people in database:**")
for name in known_names:
gr.Markdown(f"• {name}")
demo.launch() |