# --- 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()