René Cano
Todos los proyectos

Núm. 11

NeuroFocusAI

Monitor de atención por webcam

Mi rol
Autor único
Periodo
Mar 2026

El problema

Quería medir la atención durante una sesión de estudio sin hardware extra: con la pura webcam, detectar si la persona mira la pantalla, si parpadea de más o si cierra los ojos, y al final darle un resumen de cómo le fue.

Qué construí

Lo hice solo, en marzo de 2026.

  • La detección del rostro con MediaPipe Face Landmarker: 478 puntos faciales por cuadro.
  • El parpadeo con el Eye Aspect Ratio (EAR) de cada ojo: tasa de parpadeo por minuto y tiempo con los ojos cerrados.
  • La orientación aproximada de la cabeza, con yaw y pitch calculados a partir de la nariz, las orejas, la frente y el mentón.
  • Un clasificador por reglas: parte de 100 puntos y resta por fatiga ocular, ojos cerrados, cabeza fuera de rango (25° de yaw, 20° de pitch) y más de 25 parpadeos por minuto. Con el puntaje suavizado asigna 4 estados: atención alta (70 o más), atención media (40 o más), distracción y fatiga.
  • Dos vistas: una ventana de OpenCV con panel de métricas y un panel web que recibe los datos por WebSocket.
  • Un resumen de la sesión con Gemini. Si la llamada falla o no hay API key, genera un resumen con una plantilla.

Arquitectura

Diagrama del flujo: la webcam entrega cuadros a MediaPipe Face Landmarker, que detecta 478 puntos faciales; de ahí salen las señales de los ojos (EAR y parpadeos por minuto) y de la cabeza (yaw y pitch); un clasificador por reglas calcula un score sobre 100 y uno de 4 estados, que se muestran en una ventana de OpenCV y en un panel web por WebSocket; al final, Gemini o una plantilla generan el resumen de la sesión.

Resultados

No hay una evaluación medida. Los umbrales son fijos y no los validé con usuarios, así que los estados son una aproximación por reglas, no una medida de atención.

Límites conocidos

  • La orientación usa solo yaw y pitch, sin roll, calculados con geometría 2D de los puntos y no con un modelo 3D de la cabeza.
  • El README describe cosas que el código no hace: un estado de estrés, 468 puntos, roll e instrucciones para correr el panel como un servidor aparte en el puerto 5000, cuando en realidad lo arranca main.py. Hay que corregirlo.
  • No hay tests.

Links