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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -120
app.py CHANGED
@@ -6,7 +6,7 @@ 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(
@@ -23,196 +23,159 @@ def detect_face(image):
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()
 
6
  from sklearn.metrics.pairwise import cosine_distances
7
 
8
  # ===============================
9
+ # FACE DETECTION
10
  # ===============================
11
 
12
  face_cascade = cv2.CascadeClassifier(
 
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
+
29
  face = gray[y:y+h, x:x+w]
30
  face = cv2.resize(face, (64,64))
31
  return image, face.flatten()
32
 
33
  def face_to_embedding(face_vector):
34
+ np.random.seed(42)
35
+ proj = np.random.randn(face_vector.shape[0], 128)
36
+ emb = face_vector @ proj
37
+ emb = emb / np.linalg.norm(emb)
38
+ return emb
39
 
40
  # ===============================
41
+ # VISUALS
42
  # ===============================
43
 
44
+ def plot_embedding(embedding):
45
  fig = go.Figure()
46
  fig.add_trace(go.Scatter(
47
  y=embedding[:50],
48
  mode="lines+markers"
49
  ))
50
  fig.update_layout(
51
+ title="Face Embedding (Vector Representation)",
52
+ height=300
 
 
53
  )
54
  return fig
55
 
56
+ def plot_3d(enroll, live):
57
  pca = PCA(n_components=3)
58
+ reduced = pca.fit_transform(np.vstack([enroll, live]))
59
 
60
  fig = go.Figure()
61
+ fig.add_trace(go.Scatter3d(
62
+ x=[reduced[0,0]], y=[reduced[0,1]], z=[reduced[0,2]],
63
+ mode="markers+text",
64
+ text=["Enrolled"],
65
+ marker=dict(size=6)
66
+ ))
67
+ fig.add_trace(go.Scatter3d(
68
+ x=[reduced[1,0]], y=[reduced[1,1]], z=[reduced[1,2]],
69
+ mode="markers+text",
70
+ text=["Live"],
71
+ marker=dict(size=6)
72
+ ))
73
 
74
+ fig.update_layout(title="3D Face Embedding Space")
 
 
 
75
  return fig
76
 
77
  # ===============================
78
+ # LOGIC
79
  # ===============================
80
 
81
+ def enroll(image):
82
  img, face = detect_face(image)
83
  if face is None:
84
+ return img, None, "❌ No face detected", None
85
 
86
  emb = face_to_embedding(face)
87
+ return img, emb, "βœ… Face enrolled", plot_embedding(emb)
88
 
89
+ def verify(image, stored, threshold):
90
  img, face = detect_face(image)
91
+ if face is None or stored is None:
92
+ return img, "❌ Missing face or enrollment", None, None
93
 
94
+ live = face_to_embedding(face)
95
+ dist = cosine_distances([stored], [live])[0][0]
96
 
97
+ status = "πŸ”“ UNLOCKED" if dist < threshold else "πŸ”’ DENIED"
98
 
99
+ gauge = go.Figure(go.Indicator(
100
  mode="gauge+number",
101
+ value=dist,
102
  gauge={
103
  "axis": {"range": [0,1]},
104
+ "threshold": {"value": threshold}
 
 
 
105
  },
106
  title={"text": status}
107
  ))
108
 
109
+ return img, f"Distance: {dist:.3f}", gauge, plot_3d(stored, live)
110
 
111
  # ===============================
112
+ # NAVIGATION
113
  # ===============================
114
 
115
+ def next_tab(t): return min(t+1, 2)
116
  def prev_tab(t): return max(t-1, 0)
117
 
118
  # ===============================
119
+ # UI
120
  # ===============================
121
 
122
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
123
+ gr.Markdown("# πŸ” How Face Unlock Works (Visual)")
124
+ tab_state = gr.State(0)
 
 
125
 
126
  with gr.Row():
127
  back = gr.Button("β¬… Back")
128
  nextb = gr.Button("Next ➑")
129
 
130
+ with gr.Tabs(selected=0) as tabs:
 
 
 
 
 
131
 
132
+ with gr.Tab("πŸ“Έ Capture"):
133
+ cam1 = gr.Image(
134
+ sources=["webcam"],
135
+ type="numpy",
136
+ streaming=True
137
  )
138
+ out1 = gr.Image()
139
+ gr.Button("Detect").click(detect_face, cam1, [out1, gr.State()])
140
 
141
+ with gr.Tab("🧠 Enroll"):
142
+ cam2 = gr.Image(
143
+ sources=["webcam"],
144
+ type="numpy"
145
+ )
146
+ out2 = gr.Image()
147
+ msg2 = gr.Markdown()
148
+ emb_state = gr.State()
149
+ plot2 = gr.Plot()
150
 
151
  gr.Button("Enroll Face").click(
152
+ enroll,
153
+ cam2,
154
+ [out2, emb_state, msg2, plot2]
 
 
 
 
155
  )
156
 
157
+ with gr.Tab("πŸ”“ Verify"):
158
+ cam3 = gr.Image(
159
+ sources=["webcam"],
160
+ type="numpy"
 
 
 
 
 
 
 
 
161
  )
162
+ out3 = gr.Image()
163
+ threshold = gr.Slider(0.1, 0.8, 0.35)
164
+ msg3 = gr.Markdown()
165
+ gauge = gr.Plot()
166
+ space3d = gr.Plot()
167
 
168
+ gr.Button("Verify").click(
169
+ verify,
170
+ [cam3, emb_state, threshold],
171
+ [out3, msg3, gauge, space3d]
 
 
 
 
 
 
 
172
  )
173
 
174
+ back.click(prev_tab, tab_state, tab_state).then(
175
+ lambda i: i, tab_state, tabs
 
 
 
 
 
 
 
 
 
 
176
  )
177
+ nextb.click(next_tab, tab_state, tab_state).then(
178
+ lambda i: i, tab_state, tabs
 
 
 
 
 
 
 
179
  )
180
 
181
  demo.launch()