
Compartir:
Hamza es ingeniero de software y vive en Chicago. Trabaja con Webrtc.ventures, una empresa líder en soluciones WebRTC. También trabaja como Full Stack Developer en Vonage ayudando con la Plataforma de Video para servir mejor a las necesidades de sus clientes. Como orgulloso introvertido, le gusta pasar su tiempo libre jugando con sus gatos.
Detección de atención con Video API de Vonage
Tiempo de lectura: 6 minutos
Este artículo ha sido escrito en colaboración con Talha Ahsan
Introducción
En el mundo actual cada vez interactuamos más en línea. En los últimos años, las clases y reuniones en línea se han convertido en una parte normal de la vida. Aunque esta transición ha tenido numerosas ventajas, también ha creado problemas interesantes que hay que abordar. Uno de ellos es garantizar la atención del usuario.
El uso de la tecnología de detección de la atención puede tener un gran impacto en ámbitos como la educación o las reuniones en línea. Puede permitir a los presentadores comprender cómo fluctúa el interés de los participantes en determinadas partes de sus reuniones o conferencias. También puede utilizarse para ayudar a los profesores a asegurarse de que los alumnos prestan atención.
Hoy crearemos una aplicación de videoconferencia con la Video API de Vonage que aprovecha la detección de puntos de referencia faciales para calcular la puntuación de atención de un participante.
Requisitos previos
Para configurar la aplicación en tu máquina, primero clona el repositorio:
git clone https://github.com/hamzanasir/attention-detection.git
Estupendo. Ahora entra en el repositorio e instala los paquetes asociados mediante:
npm install
Ahora necesitamos configurar nuestra clave y secreto de API de Vonage. Comencemos copiando la plantilla env:
cp .envcopy .env
Ahora todo lo que tienes que hacer es sustituir los TOKBOX_API_KEY y TOKBOX_SECRET en el archivo .env por tus credenciales. Puedes encontrar tu clave y secreto de API en la página del proyecto de tu Video API de Vonage de Vonage Video.
Puedes iniciar la aplicación con:
npm start
Todo el código del que hablamos en este blog se encuentra en el archivo `public/js/app.js`.
Cómo funciona la detección de la atención
Para calcular la atención del usuario, primero tendremos que obtener los puntos de referencia de la cara del usuario en el espacio tridimensional. Una vez obtenidos, podemos calcular la pose de la cara del usuario en 3 dimensiones, en concreto, podemos calcular la guiñada, el cabeceo y el balanceo (véase el diagrama siguiente) de la cara del usuario utilizando un poco de trigonometría. Para simplificar, sólo nos interesarán la guiñada y el cabeceo.
The yaw, pitch and roll angles in the human head motion
Basándonos en estos dos ángulos, podemos proporcionar a los usuarios una puntuación global de atención.
Obtención de los puntos de referencia de la cara
Usaremos MediaPipe de TensorFlow de TensorFlowl para obtener los puntos de referencia de la cara. La razón por la que utilizamos MediaPipe es que proporciona puntos de referencia tridimensionales de forma inmediata, utilizando el aprendizaje automático para inferir la profundidad de la superficie facial sin necesidad de un sensor de profundidad.
Face landmarks visualization from MediaPipe
Más información sobre MediaPipe aquí
Cálculo del cabeceo y la guiñada
Para calcular la inclinación, utilizamos los 468 puntos de referencia faciales (proporcionados por la biblioteca de mallas faciales) correspondientes a la parte superior e inferior de la cara del usuario en los planos y y z. Del mismo modo, para la guiñada, utilizamos puntos de referencia correspondientes a las esquinas exteriores de los ojos del usuario en los planos x y z.
Para ambos, calculamos el punto medio entre estos dos puntos y calculamos el ángulo relativo a la cámara del usuario utilizando la función atan2 (tangente inversa) que calcula el ángulo contrario entre el eje x y el punto que nos interesa. Puedes ver el código de ejemplo a continuación:
const radians = (a1, a2, b1, b2) => Math.atan2(y: b2-a2, x: b1-a1);
const angle = {
yaw: radians(mesh[33][0], mesh[33][2], mesh[263][0], mesh[263][2]),
pitch: radians(mesh[10][1], mesh[10][2], mesh[152][1], mesh[152][2])
};
Marcar la atención del usuario
Ahora tenemos que utilizar el cabeceo y la guiñada que hemos calculado para asignar algún tipo de puntuación de atención al usuario. El enfoque que utilizaremos en nuestro caso está influenciado por "Attention Span Prediction Using Head-Pose Estimation With Deep Neural Networks"publicado en IEEE Access.
Básicamente, asignaremos una puntuación de 0 a 2 (siendo 0 una puntuación de atención baja y 2 una puntuación de atención alta) basada en el valor calculado para cada uno de los ángulos. Asignaremos una puntuación con la siguiente getScore basada en el documento IEEE Access:
const getScore = (degree) => {
degree = Math.abs(radiansToDegrees(degree));
if (degree < 10) {
return 2;
}
if (degree < 30) {
const adjust = (degree - 10) * 0.05;
return 2.0 - adjust;
}
return 0;
};
A continuación, tomamos el producto de las dos puntuaciones para obtener la puntuación final de atención del usuario. Una vez obtenida la puntuación global de la atención, la categorizamos para que los usuarios puedan visualizar fácilmente su nivel de atención. Desglosamos esta categorización en 4 categorías diferentes que van desde la falta de concentración a la alta concentración. Puedes ver el procedimiento para calcular el nivel de atención global:
Pseudocode for our function to evaluate concentration level.
Y las categorías de atención son las siguientes:
Attention score categorization
Es importante tener en cuenta que estos diagramas representan un algoritmo teórico para calcular la puntuación de atención. En realidad, es posible que desee ajustar algunas cosas, como las categorías de puntuación de la capacidad de atención. Uno de los cambios que hemos hecho en nuestra aplicación es que en lugar de añadir los botones yaw_score y el pitch_score decidimos multiplicarlos para obtener una progresión lineal de la puntuación de atención.
Integración con Video API de Vonage
Para ahorrar CPU/GPU de cada participante, en lugar de que cada participante ejecute el análisis de la malla facial para cada participante en su máquina, hagamos que cada uno en la convocatoria sea responsable de su propia métrica de puntuación de atención. Así que vamos a inicializar el algoritmo en el session.publish punto final:
session.publish(publisher, async (err) => {
if (err) {
console.log('Error', err);
} else {
const publisherElement = document.getElementById('publisher');
streamId = publisher.stream.id;
const webcam = publisherElement.querySelector('video');
await runFacemesh(webcam);
}
});
Echemos un vistazo más de cerca al runFacemesh método:
const runFacemesh = async (webcamRef) => {
const net = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedPackages.mediapipeFacemesh, { maxFaces: 1 });
setInterval(() => {
detect(net, webcamRef);
}, 500);
};
Utilizamos la función de detección, que tendremos que construir, pero esencialmente el número de veces que ejecutamos esta función vamos a obtener una métrica de puntuación de atención para el marco que se representa por la cámara. Así que el número de veces que ejecutamos esto por segundo determina los fotogramas por segundo de nuestro análisis métrico de atención. En la actualidad, está configurado para ejecutarse cada 500 milisegundos, lo que significa que estamos efectivamente mirando a un modelo FPS (Fotogramas Por Segundo) de 2. Esto puede ser jugado en función de su caso de uso.
Veamos ahora la parte sustanciosa de nuestro algoritmo, que es la responsable de generar una puntuación y señalarla a todos los demás participantes:
// This runs face landmark model
const face = await net.estimateFaces({ input: video, predictIrises: true });
// Getting points from the model
const { mesh } = face[0];
const radians = (a1, a2, b1, b2) => Math.atan2(b2 - a2, b1 - a1);
// Generating angles between points and axis
const angle = {
yaw: radians(mesh[33][0], mesh[33][2], mesh[263][0], mesh[263][2]),
pitch: radians(mesh[10][1], mesh[10][2], mesh[152][1], mesh[152][2]),
};
// Calculating attention score
const score = getScore(angle.yaw) * getScore(angle.pitch);
const signalScore = { attention: score, streamId };
// Sending attention score to all other participants in call
session.signal(
{
type: 'attentionScore',
data: JSON.stringify(signalScore)
},
function(error) {
if (error) {
console.log("signal error ("+ error.name+ "): " + error.message);
}
}
);
Este fragmento de código puede parecer intimidante, pero en realidad todo lo que estamos haciendo es ejecutar la biblioteca de puntos de referencia faciales en el fotograma actual del editor, ejecutar nuestro algoritmo en los ángulos entre determinados puntos de la cara detectada y, a continuación, transmitir la puntuación de atención a todos los participantes. getScore algoritmo en los ángulos entre ciertos puntos de la cara detectada, y luego la difusión de la puntuación de la atención a todos los participantes.
Una vez que la puntuación de atención es señalada necesitamos asegurarnos de que la estamos manejando en el extremo receptor y hacer con ella lo que nos plazca. Podrías mostrarlo como una interfaz de usuario en tiempo real (como hicimos en este proyecto) o almacenarlo en un almacén de datos que se puede utilizar para mapear las métricas de atención a lo largo de la duración de la llamada. Las posibilidades son infinitas.
Conclusión
La atención es un factor clave para calibrar conversaciones, discursos, conferencias y casi cualquier interacción entre personas. Ahora hemos aprendido a estimarla mediante el análisis de la malla facial y a integrarla en nuestras videollamadas. Esta estimación puede mejorarse aún más mediante más fuentes de datos, como la obtención del movimiento del iris, el reconocimiento de múltiples rostros, etc.
Encontrará una versión completa de esta aplicación en GitHub
Cuéntanos si lograste que funcione la detección de atención. Únete a nosotros en la de Vonage o envíanos un tweet a VonageDev.
Compartir:
Hamza es ingeniero de software y vive en Chicago. Trabaja con Webrtc.ventures, una empresa líder en soluciones WebRTC. También trabaja como Full Stack Developer en Vonage ayudando con la Plataforma de Video para servir mejor a las necesidades de sus clientes. Como orgulloso introvertido, le gusta pasar su tiempo libre jugando con sus gatos.