Spaces:
Sleeping
Sleeping
File size: 3,545 Bytes
0c009d7 61e47bd 3122e55 61e47bd 0c009d7 3122e55 0c009d7 3122e55 0c009d7 3122e55 0c009d7 495aa3e 61e47bd 0c009d7 61e47bd 0c009d7 61e47bd 3122e55 61e47bd 0c009d7 3122e55 0c009d7 61e47bd 0c009d7 3122e55 495aa3e 61e47bd 0c009d7 61e47bd 3122e55 61e47bd 0c009d7 61e47bd 0c009d7 495aa3e 3122e55 0c009d7 3122e55 61e47bd 0c009d7 61e47bd 495aa3e 61e47bd 0c009d7 61e47bd 3122e55 61e47bd 3122e55 0c009d7 61e47bd 3122e55 61e47bd 3122e55 61e47bd 3122e55 61e47bd 3122e55 61e47bd 3122e55 61e47bd 3122e55 61e47bd 3122e55 61e47bd 3122e55 61e47bd 3122e55 0c009d7 | 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 | import gradio as gr
import numpy as np
import cv2
import plotly.graph_objects as go
from sklearn.metrics.pairwise import cosine_distances
# =========================
# FACE SETUP
# =========================
face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
)
def extract_face(image):
if image is None:
return None, None
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
if len(faces) == 0:
return image, None
x, y, w, h = faces[0]
cv2.rectangle(image, (x,y), (x+w,y+h), (0,255,0), 2)
face = cv2.resize(gray[y:y+h, x:x+w], (64,64))
return image, face.flatten()
def embed(face):
vec = face @ np.random.randn(face.shape[0], 128)
return vec / np.linalg.norm(vec)
# =========================
# STEP FUNCTIONS
# =========================
def step_detect(img):
img, _ = extract_face(img)
return img
def step_enroll(img):
img, face = extract_face(img)
if face is None:
return img, None, "β No face detected"
emb = embed(face)
return img, emb, "β
Face enrolled"
def step_verify(img, stored):
img, face = extract_face(img)
if face is None or stored is None:
return img, "β Missing data", None
live = embed(face)
dist = cosine_distances([stored], [live])[0][0]
status = "π UNLOCKED" if dist < 0.35 else "π DENIED"
fig = go.Figure(go.Indicator(
mode="gauge+number",
value=dist,
title={"text": status},
gauge={"axis": {"range": [0, 1]}}
))
return img, f"Distance: {dist:.3f}", fig
# =========================
# UI
# =========================
with gr.Blocks(theme=gr.themes.Soft()) as demo:
page = gr.State(0)
stored_embedding = gr.State()
gr.Markdown("# π Face Unlock β How Mobile Face ID Works")
with gr.Row():
back = gr.Button("β¬
Back")
nextb = gr.Button("Next β‘")
# ---------- PAGE 0 ----------
page0 = gr.Column(visible=True)
with page0:
gr.Markdown("## πΈ Face Detection")
cam0 = gr.Image(sources=["webcam"], type="numpy")
out0 = gr.Image()
gr.Button("Detect Face").click(step_detect, cam0, out0)
# ---------- PAGE 1 ----------
page1 = gr.Column(visible=False)
with page1:
gr.Markdown("## π§ Face Enrollment")
cam1 = gr.Image(sources=["webcam"], type="numpy")
out1 = gr.Image()
msg1 = gr.Markdown()
gr.Button("Enroll Face").click(
step_enroll,
cam1,
[out1, stored_embedding, msg1]
)
# ---------- PAGE 2 ----------
page2 = gr.Column(visible=False)
with page2:
gr.Markdown("## π Face Verification")
cam2 = gr.Image(sources=["webcam"], type="numpy")
out2 = gr.Image()
msg2 = gr.Markdown()
gauge = gr.Plot()
gr.Button("Verify").click(
step_verify,
[cam2, stored_embedding],
[out2, msg2, gauge]
)
# =========================
# NAVIGATION
# =========================
def navigate(p, step):
p = min(2, max(0, p + step))
return (
p,
gr.update(visible=p == 0),
gr.update(visible=p == 1),
gr.update(visible=p == 2)
)
back.click(navigate, [page, gr.State(-1)], [page, page0, page1, page2])
nextb.click(navigate, [page, gr.State(1)], [page, page0, page1, page2])
demo.launch() |