Guru-25 commited on
Commit
a3ae3eb
·
verified ·
1 Parent(s): 8f43a66
Files changed (1) hide show
  1. app.py +113 -95
app.py CHANGED
@@ -135,6 +135,10 @@ def process_webcam(state):
135
  if not cap.isOpened():
136
  return None, "Error: Could not open webcam.", None
137
 
 
 
 
 
138
  GAZE_STABILITY_THRESHOLD = 0.5
139
  TIME_THRESHOLD = 15
140
  BLINK_RATE_THRESHOLD = 1
@@ -172,6 +176,7 @@ def process_webcam(state):
172
  "HEAD_STABILITY_THRESHOLD": HEAD_STABILITY_THRESHOLD,
173
  "log_output": log_output
174
  }
 
175
 
176
  # Extract state variables
177
  cap = state["cap"]
@@ -184,105 +189,118 @@ def process_webcam(state):
184
 
185
  # Capture frame
186
  ret, frame = cap.read()
187
- if not ret:
188
- return state, log_output + "\nError: Could not read from webcam.", None
 
 
 
 
 
 
 
 
189
 
190
  # Process frame
191
- head_pose_gaze, gaze_h, gaze_v = gaze_predictor.predict_gaze(frame)
192
- current_gaze = np.array([gaze_h, gaze_v])
193
- smoothed_gaze = smooth_values(gaze_history, current_gaze)
194
-
195
- ear, left_eye, right_eye, head_pose, left_iris, right_iris = blink_detector.detect_blinks(frame)
196
-
197
- # Update display and logs
198
- current_time = time.time()
199
- logs = []
200
-
201
- if ear is None:
202
- cv2.putText(frame, "No face detected", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
203
- smoothed_head = smooth_values(head_history, None)
204
- smoothed_ear = smooth_values(ear_history, None)
205
- logs.append("No face detected")
206
- else:
207
- smoothed_head = smooth_values(head_history, head_pose)
208
- smoothed_ear = smooth_values(ear_history, ear)
209
- if smoothed_ear >= blink_detector.EAR_THRESHOLD:
210
- cv2.drawMarker(frame, left_iris, (0, 255, 0), markerType=cv2.MARKER_CROSS, markerSize=10, thickness=2)
211
- cv2.drawMarker(frame, right_iris, (0, 255, 0), markerType=cv2.MARKER_CROSS, markerSize=10, thickness=2)
212
-
213
- # Add metrics to frame
214
- cv2.putText(frame, f"Gaze H: {smoothed_gaze[0]:.2f}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
215
- cv2.putText(frame, f"Gaze V: {smoothed_gaze[1]:.2f}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
216
- cv2.putText(frame, f"Head Pose: {smoothed_head:.2f}", (10, 120), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
217
- cv2.putText(frame, f"EAR: {smoothed_ear:.2f}", (10, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
218
-
219
- # Check for gaze stability
220
- if len(gaze_history) > 1:
221
- gaze_diff = np.sqrt(np.sum((smoothed_gaze - gaze_history[-2])**2))
222
- if gaze_diff < state["GAZE_STABILITY_THRESHOLD"]:
223
- if state["stable_gaze_time"] == 0:
224
- state["stable_gaze_time"] = current_time
225
  else:
226
- state["stable_gaze_time"] = 0
227
-
228
- # Check for head stability
229
- if len(head_history) > 1 and head_pose is not None:
230
- head_diff = abs(smoothed_head - head_history[-2])
231
- if head_diff < state["HEAD_STABILITY_THRESHOLD"]:
232
- if state["stable_head_time"] == 0:
233
- state["stable_head_time"] = current_time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  else:
235
- state["stable_head_time"] = 0
236
-
237
- # Check for eye closure
238
- if ear is not None and smoothed_ear < blink_detector.EAR_THRESHOLD:
239
- if state["eye_closed_time"] == 0:
240
- state["eye_closed_time"] = current_time
241
- elif current_time - state["eye_closed_time"] > state["EYE_CLOSURE_THRESHOLD"]:
242
- cv2.putText(frame, "Eyes Closed", (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
243
- logs.append("Eyes have been closed for an extended period")
244
- else:
245
- if state["eye_closed_time"] > 0 and current_time - state["eye_closed_time"] < 0.5:
246
- state["blink_count"] += 1
247
- logs.append("Blink detected")
248
- state["eye_closed_time"] = 0
249
-
250
- elapsed_seconds = current_time - state["start_time"]
251
- elapsed_minutes = elapsed_seconds / 60
252
- blink_rate = state["blink_count"] / elapsed_minutes if elapsed_minutes > 0 else 0
253
- cv2.putText(frame, f"Blink Rate: {blink_rate:.1f}/min", (10, 240), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
254
- logs.append(f"Blink rate: {blink_rate:.1f}/min")
255
-
256
- # Check for unconscious state
257
- unconscious_conditions = [
258
- state["stable_gaze_time"] > 0 and current_time - state["stable_gaze_time"] > state["TIME_THRESHOLD"],
259
- blink_rate < state["BLINK_RATE_THRESHOLD"] and elapsed_minutes > 1,
260
- state["eye_closed_time"] > 0 and current_time - state["eye_closed_time"] > state["EYE_CLOSURE_THRESHOLD"],
261
- state["stable_head_time"] > 0 and current_time - state["stable_head_time"] > state["TIME_THRESHOLD"]
262
- ]
263
-
264
- if sum(unconscious_conditions) >= 2:
265
- cv2.putText(frame, "Unconscious Detected", (10, 270), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
266
- state["is_unconscious"] = True
267
- logs.append("WARNING: Possible unconscious state detected!")
268
- else:
269
- state["is_unconscious"] = False
270
-
271
- # Update log output with latest information
272
- logs.append(f"Gaze: ({smoothed_gaze[0]:.2f}, {smoothed_gaze[1]:.2f}) | Head: {smoothed_head:.2f} | EAR: {smoothed_ear:.2f}")
273
- log_text = "\n".join(logs)
274
-
275
- # Keep log_output to a reasonable size
276
- log_lines = log_output.split("\n") if log_output else []
277
- log_lines.append(log_text)
278
- if len(log_lines) > 20: # Keep only last 20 entries
279
- log_lines = log_lines[-20:]
280
- state["log_output"] = "\n".join(log_lines)
281
-
282
- # Convert from BGR to RGB for Gradio
283
- frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
284
-
285
- return state, state["log_output"], frame_rgb
286
 
287
  def create_webcam_interface():
288
  log_output = gr.Textbox(label="Gaze Tracking Log", lines=10)
 
135
  if not cap.isOpened():
136
  return None, "Error: Could not open webcam.", None
137
 
138
+ # Try to set webcam properties for better performance
139
+ cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
140
+ cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
141
+
142
  GAZE_STABILITY_THRESHOLD = 0.5
143
  TIME_THRESHOLD = 15
144
  BLINK_RATE_THRESHOLD = 1
 
176
  "HEAD_STABILITY_THRESHOLD": HEAD_STABILITY_THRESHOLD,
177
  "log_output": log_output
178
  }
179
+ return state, "Initializing webcam...", None
180
 
181
  # Extract state variables
182
  cap = state["cap"]
 
189
 
190
  # Capture frame
191
  ret, frame = cap.read()
192
+ if not ret or frame is None:
193
+ # Try to reinitialize the camera if frame capture fails
194
+ cap.release()
195
+ cap = cv2.VideoCapture(0)
196
+ if not cap.isOpened():
197
+ return state, log_output + "\nError: Could not read from webcam.", None
198
+ state["cap"] = cap
199
+ ret, frame = cap.read()
200
+ if not ret or frame is None:
201
+ return state, log_output + "\nError: Failed to capture frame after reinitialization.", None
202
 
203
  # Process frame
204
+ try:
205
+ head_pose_gaze, gaze_h, gaze_v = gaze_predictor.predict_gaze(frame)
206
+ current_gaze = np.array([gaze_h, gaze_v])
207
+ smoothed_gaze = smooth_values(gaze_history, current_gaze)
208
+
209
+ ear, left_eye, right_eye, head_pose, left_iris, right_iris = blink_detector.detect_blinks(frame)
210
+
211
+ # Update display and logs
212
+ current_time = time.time()
213
+ logs = []
214
+
215
+ if ear is None:
216
+ cv2.putText(frame, "No face detected", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
217
+ smoothed_head = smooth_values(head_history, None)
218
+ smoothed_ear = smooth_values(ear_history, None)
219
+ logs.append("No face detected")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  else:
221
+ smoothed_head = smooth_values(head_history, head_pose)
222
+ smoothed_ear = smooth_values(ear_history, ear)
223
+ if smoothed_ear >= blink_detector.EAR_THRESHOLD:
224
+ cv2.drawMarker(frame, left_iris, (0, 255, 0), markerType=cv2.MARKER_CROSS, markerSize=10, thickness=2)
225
+ cv2.drawMarker(frame, right_iris, (0, 255, 0), markerType=cv2.MARKER_CROSS, markerSize=10, thickness=2)
226
+
227
+ # Add metrics to frame
228
+ cv2.putText(frame, f"Gaze H: {smoothed_gaze[0]:.2f}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
229
+ cv2.putText(frame, f"Gaze V: {smoothed_gaze[1]:.2f}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
230
+ cv2.putText(frame, f"Head Pose: {smoothed_head:.2f}", (10, 120), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
231
+ cv2.putText(frame, f"EAR: {smoothed_ear:.2f}", (10, 150), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
232
+
233
+ # Check for gaze stability
234
+ if len(gaze_history) > 1:
235
+ gaze_diff = np.sqrt(np.sum((smoothed_gaze - gaze_history[-2])**2))
236
+ if gaze_diff < state["GAZE_STABILITY_THRESHOLD"]:
237
+ if state["stable_gaze_time"] == 0:
238
+ state["stable_gaze_time"] = current_time
239
+ else:
240
+ state["stable_gaze_time"] = 0
241
+
242
+ # Check for head stability
243
+ if len(head_history) > 1 and head_pose is not None:
244
+ head_diff = abs(smoothed_head - head_history[-2])
245
+ if head_diff < state["HEAD_STABILITY_THRESHOLD"]:
246
+ if state["stable_head_time"] == 0:
247
+ state["stable_head_time"] = current_time
248
+ else:
249
+ state["stable_head_time"] = 0
250
+
251
+ # Check for eye closure
252
+ if ear is not None and smoothed_ear < blink_detector.EAR_THRESHOLD:
253
+ if state["eye_closed_time"] == 0:
254
+ state["eye_closed_time"] = current_time
255
+ elif current_time - state["eye_closed_time"] > state["EYE_CLOSURE_THRESHOLD"]:
256
+ cv2.putText(frame, "Eyes Closed", (10, 210), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
257
+ logs.append("Eyes have been closed for an extended period")
258
  else:
259
+ if state["eye_closed_time"] > 0 and current_time - state["eye_closed_time"] < 0.5:
260
+ state["blink_count"] += 1
261
+ logs.append("Blink detected")
262
+ state["eye_closed_time"] = 0
263
+
264
+ elapsed_seconds = current_time - state["start_time"]
265
+ elapsed_minutes = elapsed_seconds / 60
266
+ blink_rate = state["blink_count"] / elapsed_minutes if elapsed_minutes > 0 else 0
267
+ cv2.putText(frame, f"Blink Rate: {blink_rate:.1f}/min", (10, 240), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
268
+ logs.append(f"Blink rate: {blink_rate:.1f}/min")
269
+
270
+ # Check for unconscious state
271
+ unconscious_conditions = [
272
+ state["stable_gaze_time"] > 0 and current_time - state["stable_gaze_time"] > state["TIME_THRESHOLD"],
273
+ blink_rate < state["BLINK_RATE_THRESHOLD"] and elapsed_minutes > 1,
274
+ state["eye_closed_time"] > 0 and current_time - state["eye_closed_time"] > state["EYE_CLOSURE_THRESHOLD"],
275
+ state["stable_head_time"] > 0 and current_time - state["stable_head_time"] > state["TIME_THRESHOLD"]
276
+ ]
277
+
278
+ if sum(unconscious_conditions) >= 2:
279
+ cv2.putText(frame, "Unconscious Detected", (10, 270), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
280
+ state["is_unconscious"] = True
281
+ logs.append("WARNING: Possible unconscious state detected!")
282
+ else:
283
+ state["is_unconscious"] = False
284
+
285
+ # Update log output with latest information
286
+ logs.append(f"Gaze: ({smoothed_gaze[0]:.2f}, {smoothed_gaze[1]:.2f}) | Head: {smoothed_head:.2f} | EAR: {smoothed_ear:.2f}")
287
+ log_text = "\n".join(logs)
288
+
289
+ # Keep log_output to a reasonable size
290
+ log_lines = log_output.split("\n") if log_output else []
291
+ log_lines.append(log_text)
292
+ if len(log_lines) > 20: # Keep only last 20 entries
293
+ log_lines = log_lines[-20:]
294
+ state["log_output"] = "\n".join(log_lines)
295
+
296
+ # Convert from BGR to RGB for Gradio
297
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
298
+
299
+ return state, state["log_output"], frame_rgb
300
+
301
+ except Exception as e:
302
+ error_msg = f"Error processing frame: {str(e)}"
303
+ return state, log_output + "\n" + error_msg, None
 
 
 
 
 
 
304
 
305
  def create_webcam_interface():
306
  log_output = gr.Textbox(label="Gaze Tracking Log", lines=10)