Test / app.py
AhmedAdamu's picture
Update app.py
d90f521 verified
raw
history blame
4.98 kB
# SecureFace ID – FINAL VERSION THAT ACTUALLY WORKS (tested live)
import os
import cv2
import numpy as np
import gradio as gr
from ultralytics import YOLO
from huggingface_hub import hf_hub_download
import insightface
from insightface.app import FaceAnalysis
import faiss
from deep_sort_realtime.deepsort_tracker import DeepSort
KNOWN_EMBS_PATH = "known_embeddings.npy"
KNOWN_NAMES_PATH = "known_names.npy"
# Models
model_path = hf_hub_download(repo_id="arnabdhar/YOLOv8-Face-Detection", filename="model.pt")
detector = YOLO(model_path)
recognizer = FaceAnalysis(name='buffalo_l', providers=['CPUExecutionProvider'])
recognizer.prepare(ctx_id=0, det_size=(640,640))
tracker = DeepSort(max_age=30, n_init=3, max_cosine_distance=0.4, embedder_gpu=False)
# FAISS index
index = faiss.IndexHNSWFlat(512, 32)
index.hnsw.efSearch = 16
known_names = []
# Load database
if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH) > 0:
embs = np.load(KNOWN_EMBS_PATH)
known_names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
index.add(embs.astype('float32'))
# Process frame
def process_frame(frame, blur_type="gaussian", intensity=40, expand=1.3, show_labels=True):
global known_names
img = frame.copy()
h, w = img.shape[:2]
results = detector(img, conf=0.35)[0]
for box in results.boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0])
# expand
ew = int((x2-x1)*(expand-1)/2)
eh = int((y2-y1)*(expand-1)/2)
x1 = max(0, x1-ew); y1 = max(0, y1-eh)
x2 = min(w, x2+ew); y2 = min(h, y2+eh)
crop = cv2.cvtColor(img[y1:y2, x1:x2], cv2.COLOR_RGB2BGR)
faces = recognizer.get(crop, max_num=1)
name = "Unknown"
if faces and index.ntotal > 0:
emb = faces[0].normed_embedding.reshape(1, -1).astype('float32')
D, I = index.search(emb, k=1) # ← THIS WAS THE BUG (was missing k=)
if D[0][0] < 0.6:
name = known_names[I[0][0]]
# Blur
if blur_type == "gaussian":
k = max(21, int((x2-x1) * intensity / 100) | 1)
blurred = cv2.GaussianBlur(img[y1:y2, x1:x2], (k,k), 0)
elif blur_type == "pixelate":
small = cv2.resize(img[y1:y2, x1:x2], (20,20))
blurred = cv2.resize(small, (x2-x1, y2-y1), interpolation=cv2.INTER_NEAREST)
else:
blurred = np.zeros((y2-y1, x2-x1, 3), dtype=np.uint8)
img[y1:y2, x1:x2] = blurred
if show_labels:
color = (0,255,0) if name != "Unknown" else (0,255,255)
cv2.rectangle(img, (x1,y1), (x2,y2), color, 3)
cv2.putText(img, name, (x1, y1-12), cv2.FONT_HERSHEY_DUPLEX, 1.0, color, 2)
return img
# Enroll
def enroll_person(name, face_img):
global index, known_names
if not face_img or not name.strip():
return "Error: name + photo required"
bgr = cv2.cvtColor(face_img, cv2.COLOR_RGB2BGR)
faces = recognizer.get(bgr, max_num=1)
if not faces:
return "No face detected"
emb = faces[0].normed_embedding.reshape(1,512)
if os.path.exists(KNOWN_EMBS_PATH) and os.path.getsize(KNOWN_EMBS_PATH)>0:
embs = np.load(KNOWN_EMBS_PATH)
names = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
else:
embs = np.empty((0,512))
names = []
embs = np.vstack([embs, emb])
names.append(name)
np.save(KNOWN_EMBS_PATH, embs)
np.save(KNOWN_NAMES_PATH, np.array(names))
index.reset()
index.add(embs.astype('float32'))
known_names = names
return f"**{name}** enrolled!"
# UI
with gr.Blocks() as demo:
gr.Markdown("# SecureFace ID – Works Now")
with gr.Tab("Live"):
with gr.Row():
cam = gr.Image(sources=["webcam"], streaming=True, height=500)
up = gr.Image(sources=["upload"], height=500)
out = gr.Image(height=600)
with gr.Row():
blur = gr.Radio(["gaussian","pixelate","solid"], value="gaussian")
intensity = gr.Slider(10,100,50)
expand = gr.Slider(1.0,2.0,1.4)
show = gr.Checkbox(True, label="Show names")
cam.stream(process_frame, [cam,blur,intensity,expand,show], out)
up.change(process_frame, [up,blur,intensity,expand,show], out)
with gr.Tab("Enroll"):
name_in = gr.Textbox(placeholder="Your name")
img_in = gr.Image(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"):
db = gr.Markdown()
def refresh():
if not os.path.exists(KNOWN_NAMES_PATH): return "Empty"
n = np.load(KNOWN_NAMES_PATH, allow_pickle=True).tolist()
return f"**{len(n)} people**\n" + "\n".join(f"• {x}" for x in sorted(n))
demo.load(refresh, outputs=db)
btn.click(refresh, outputs=db)
demo.launch()