Test / app.py
AhmedAdamu's picture
Create app.py
9e9b090 verified
raw
history blame
7.04 kB
# --- 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()