Pranesh64 commited on
Commit
0c009d7
Β·
verified Β·
1 Parent(s): a2cff26

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +218 -0
app.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import cv2
4
+ import plotly.graph_objects as go
5
+ from sklearn.decomposition import PCA
6
+ from sklearn.metrics.pairwise import cosine_distances
7
+
8
+ # ===============================
9
+ # FACE & EMBEDDING UTILITIES
10
+ # ===============================
11
+
12
+ face_cascade = cv2.CascadeClassifier(
13
+ cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
14
+ )
15
+
16
+ def detect_face(image):
17
+ if image is None:
18
+ return None, None
19
+
20
+ gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
21
+ faces = face_cascade.detectMultiScale(gray, 1.3, 5)
22
+
23
+ if len(faces) == 0:
24
+ return image, None
25
+
26
+ (x, y, w, h) = faces[0]
27
+ cv2.rectangle(image, (x, y), (x+w, y+h), (0,255,0), 2)
28
+ face = gray[y:y+h, x:x+w]
29
+ face = cv2.resize(face, (64,64))
30
+ return image, face.flatten()
31
+
32
+ def face_to_embedding(face_vector):
33
+ np.random.seed(0)
34
+ projection = np.random.randn(face_vector.shape[0], 128)
35
+ embedding = face_vector @ projection
36
+ embedding = embedding / np.linalg.norm(embedding)
37
+ return embedding
38
+
39
+ # ===============================
40
+ # VISUALIZATION HELPERS
41
+ # ===============================
42
+
43
+ def embedding_plot(embedding, title):
44
+ fig = go.Figure()
45
+ fig.add_trace(go.Scatter(
46
+ y=embedding[:50],
47
+ mode="lines+markers"
48
+ ))
49
+ fig.update_layout(
50
+ title=title,
51
+ height=300,
52
+ xaxis_title="Dimension",
53
+ yaxis_title="Value"
54
+ )
55
+ return fig
56
+
57
+ def embedding_3d_plot(embeddings, labels):
58
+ pca = PCA(n_components=3)
59
+ reduced = pca.fit_transform(embeddings)
60
+
61
+ fig = go.Figure()
62
+ for i, label in enumerate(labels):
63
+ fig.add_trace(go.Scatter3d(
64
+ x=[reduced[i,0]],
65
+ y=[reduced[i,1]],
66
+ z=[reduced[i,2]],
67
+ mode="markers+text",
68
+ text=[label],
69
+ marker=dict(size=6)
70
+ ))
71
+
72
+ fig.update_layout(
73
+ title="3D Face Embedding Space",
74
+ height=450
75
+ )
76
+ return fig
77
+
78
+ # ===============================
79
+ # TAB LOGIC FUNCTIONS
80
+ # ===============================
81
+
82
+ def enroll_face(image):
83
+ img, face = detect_face(image)
84
+ if face is None:
85
+ return img, None, "❌ No face detected"
86
+
87
+ emb = face_to_embedding(face)
88
+ return img, emb, "βœ… Face enrolled successfully"
89
+
90
+ def verify_face(image, stored_embedding, threshold):
91
+ img, face = detect_face(image)
92
+ if face is None or stored_embedding is None:
93
+ return img, "❌ Face / Enrollment missing", None
94
+
95
+ emb = face_to_embedding(face)
96
+ distance = cosine_distances([stored_embedding], [emb])[0][0]
97
+
98
+ status = "πŸ”“ UNLOCKED" if distance < threshold else "πŸ”’ DENIED"
99
+
100
+ fig = go.Figure(go.Indicator(
101
+ mode="gauge+number",
102
+ value=distance,
103
+ gauge={
104
+ "axis": {"range": [0,1]},
105
+ "threshold": {
106
+ "line": {"color": "red", "width": 4},
107
+ "value": threshold
108
+ }
109
+ },
110
+ title={"text": status}
111
+ ))
112
+
113
+ return img, f"Distance: {distance:.3f}", fig
114
+
115
+ # ===============================
116
+ # TAB NAVIGATION
117
+ # ===============================
118
+
119
+ def next_tab(t): return min(t+1, 3)
120
+ def prev_tab(t): return max(t-1, 0)
121
+
122
+ # ===============================
123
+ # GRADIO UI
124
+ # ===============================
125
+
126
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
127
+ gr.Markdown("# πŸ” How Face Unlock Works (Visual Simulator)")
128
+ gr.Markdown("Understand mobile face authentication step-by-step")
129
+
130
+ current_tab = gr.State(0)
131
+
132
+ with gr.Row():
133
+ back = gr.Button("β¬… Back")
134
+ nextb = gr.Button("Next ➑")
135
+
136
+ with gr.Tabs() as tabs:
137
+ # ---------------- TAB 0 ----------------
138
+ with gr.Tab("πŸ“Έ Face Detection"):
139
+ cam1 = gr.Image(source="webcam", streaming=True)
140
+ out1 = gr.Image()
141
+ btn1 = gr.Button("Detect Face")
142
+
143
+ btn1.click(
144
+ detect_face,
145
+ inputs=cam1,
146
+ outputs=[out1, gr.State()]
147
+ )
148
+
149
+ # ---------------- TAB 1 ----------------
150
+ with gr.Tab("🧠 Face β†’ Vector"):
151
+ cam2 = gr.Image(source="webcam")
152
+ img2 = gr.Image()
153
+ enroll_msg = gr.Markdown()
154
+ stored_embedding = gr.State()
155
+ emb_plot = gr.Plot()
156
+
157
+ gr.Button("Enroll Face").click(
158
+ enroll_face,
159
+ inputs=cam2,
160
+ outputs=[img2, stored_embedding, enroll_msg]
161
+ ).then(
162
+ lambda e: embedding_plot(e, "Face Embedding"),
163
+ inputs=stored_embedding,
164
+ outputs=emb_plot
165
+ )
166
+
167
+ # ---------------- TAB 2 ----------------
168
+ with gr.Tab("πŸ“ Matching & Threshold"):
169
+ cam3 = gr.Image(source="webcam")
170
+ img3 = gr.Image()
171
+ threshold = gr.Slider(0.1, 0.8, 0.35, label="Unlock Threshold")
172
+ match_msg = gr.Markdown()
173
+ gauge = gr.Plot()
174
+
175
+ gr.Button("Verify Face").click(
176
+ verify_face,
177
+ inputs=[cam3, stored_embedding, threshold],
178
+ outputs=[img3, match_msg, gauge]
179
+ )
180
+
181
+ # ---------------- TAB 3 ----------------
182
+ with gr.Tab("🌐 3D Embedding Space"):
183
+ plot3d = gr.Plot()
184
+
185
+ gr.Button("Visualize").click(
186
+ lambda e: embedding_3d_plot(
187
+ np.vstack([e, e + np.random.normal(0,0.05,e.shape)]),
188
+ ["Enrolled", "Live"]
189
+ ),
190
+ inputs=stored_embedding,
191
+ outputs=plot3d
192
+ )
193
+
194
+ # ===============================
195
+ # NAV BUTTON LOGIC (SAFE)
196
+ # ===============================
197
+
198
+ back.click(
199
+ prev_tab,
200
+ current_tab,
201
+ current_tab
202
+ ).then(
203
+ lambda i: i,
204
+ current_tab,
205
+ tabs
206
+ )
207
+
208
+ nextb.click(
209
+ next_tab,
210
+ current_tab,
211
+ current_tab
212
+ ).then(
213
+ lambda i: i,
214
+ current_tab,
215
+ tabs
216
+ )
217
+
218
+ demo.launch()