https://a.storyblok.com/f/270183/38659/cf17c86eef/attention-detection_videoapi.png

Detecção de atenção com a Video API da Vonage

Publicado em November 30, 2022

Tempo de leitura: 6 minutos

Este artigo foi escrito em colaboração com Talha Ahsan

Introdução

No mundo atual, cada vez mais nossas interações ocorrem online. Nos últimos anos, aulas e reuniões online se tornaram parte integrante do nosso dia a dia. Embora essa transição tenha trazido inúmeros benefícios, ela também gerou questões interessantes que precisam ser abordadas. Uma dessas questões é garantir a atenção do usuário.

O uso da tecnologia de detecção de atenção pode ter um grande impacto em áreas como a educação ou reuniões online. Ela permite que os apresentadores compreendam como o interesse dos participantes varia ao longo de determinadas partes de suas reuniões ou palestras. Também pode ser usada para ajudar os professores a garantir que os alunos estejam prestando atenção.

Hoje vamos desenvolver um aplicativo de videoconferência com a Video API da Vonage, que utiliza a detecção de pontos de referência faciais para calcular o índice de atenção de um participante.

Pré-requisitos

  • Chave e segredo da API da Vonage

  • 8.6.2+

  • Node Package Manager (npm)

Para configurar o aplicativo no seu computador, primeiro clone o repositório:

git clone https://github.com/hamzanasir/attention-detection.git

Ótimo! Agora acesse o repositório e instale os pacotes associados da seguinte forma:

npm install

Agora precisamos configurar nossa chave e nosso segredo da API da Vonage. Vamos começar copiando o modelo de variáveis de ambiente:

cp .envcopy .env

Agora, basta substituir o TOKBOX_API_KEY e TOKBOX_SECRET no arquivo .env pelas suas credenciais. Você pode encontrar sua chave de API e seu segredo na página do projeto da sua Video API da Vonage Account.

# enter your TokBox api key after the '=' sign below TOKBOX_API_KEY=your_api_key # enter your TokBox api secret after the '=' sign below TOKBOX_SECRET=your_project_secret

Você pode iniciar o aplicativo com:

npm start

Todo o código sobre o qual falamos neste blog pode ser encontrado no arquivo `public/js/app.js`.

Como funciona a detecção de atenção

Para calcular a atenção do usuário, primeiro precisaremos obter os pontos de referência faciais do usuário no espaço tridimensional. Depois de obtê-los, podemos calcular a pose do rosto do usuário em três dimensões; mais especificamente, podemos calcular a guinada, a inclinação e o rolamento (veja o diagrama abaixo) do rosto do usuário usando um pouco de trigonometria. Para simplificar, vamos nos concentrar apenas na guinada e na inclinação.

The yaw, pitch and roll angles in the human head motion.The yaw, pitch and roll angles in the human head motion

Com base nesses dois aspectos, podemos fornecer aos usuários uma pontuação geral de atenção.

Obtenção dos pontos de referência faciais

Vamos usar o MediaPipe do TensorFlow modo de detecção de rostopara obter os pontos de referência faciais. A razão pela qual usamos o MediaPipe é que ele fornece pontos de referência tridimensionais prontos para uso, utilizando aprendizado de máquina para inferir a profundidade da superfície facial sem a necessidade de um sensor de profundidade.

Face landmarks visualization from MediaPipeFace landmarks visualization from MediaPipe

Você pode saber mais sobre o MediaPipe aqui

Cálculo do ângulo de inclinação e do ângulo de guinada

Para calcular o pitch, utilizamos os 468 pontos de referência faciais (fornecidos pela biblioteca de malha facial) correspondentes à parte superior e inferior do rosto do usuário nos planos y e z. Da mesma forma, para a guinada, utilizamos pontos de referência correspondentes aos cantos externos dos olhos do usuário nos planos x e z.

Para ambos os casos, calculamos então o ponto médio entre esses dois pontos e calculamos o ângulo em relação à câmera do usuário utilizando o atan2 (tangente inversa), que calcula o ângulo no sentido anti-horário entre o eixo x e o ponto de nosso interesse. Veja o código de exemplo abaixo:

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])
};

Avaliação da atenção do usuário

Agora precisamos usar os ângulos de inclinação e guinada que calculamos para atribuir algum tipo de pontuação de atenção ao usuário. A abordagem que usaremos neste caso é inspirada em “Previsão da Capacidade de Atenção por meio da Estimativa da Posição da Cabeça com Redes Neurais Profundas”, publicado na revista IEEE Access.

Basicamente, atribuiremos uma pontuação de 0 a 2 (sendo 0 uma pontuação baixa de atenção e 2 uma pontuação mais alta de atenção) com base no valor calculado para cada um dos ângulos. Atribuiremos uma pontuação por meio da seguinte getScore função, com base no artigo da 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;
};

Em seguida, calculamos o produto das duas pontuações para obter a pontuação final de atenção do usuário. Depois de obtermos a pontuação geral de atenção, classificamos essa atenção para permitir que os usuários visualizem facilmente seu nível de atenção. Dividimos essa classificação em quatro categorias diferentes, que vão desde “sem concentração” até “alta concentração”. Você pode ver o procedimento para calcular o nível geral de atenção:

Pseudocode for our function to evaluate concentration level.Pseudocode for our function to evaluate concentration level.

E as categorias de atenção são as seguintes:

Attention score categorization.Attention score categorization

É importante observar que esses diagramas representam um algoritmo teórico para calcular a pontuação de atenção. Na prática, talvez você queira ajustar alguns detalhes, como as categorias de pontuação do tempo de atenção. Uma dessas alterações que fizemos em nosso aplicativo foi que, em vez de adicionar o yaw_score e pitch_score , optamos por multiplicá-los para obter uma boa progressão linear da pontuação de atenção.

Integração com a Video API da Vonage

Para economizar recursos da CPU/GPU de cada participante, em vez de cada um executar a análise da malha facial dos demais participantes em seu próprio computador, vamos fazer com que todos os participantes da chamada sejam responsáveis por suas próprias métricas de pontuação de atenção. Assim, vamos inicializar o algoritmo no session.publish ponto de extremidade:

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);
  }
});

Vamos examinar mais de perto o runFacemesh método:

const runFacemesh = async (webcamRef) => {
  const net = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedPackages.mediapipeFacemesh, { maxFaces: 1 });

  setInterval(() => {
    detect(net, webcamRef);
  }, 500);
};

Usamos a função `detect`, que precisaremos criar, mas, essencialmente, cada vez que executarmos essa função, obteremos uma métrica de pontuação de atenção para o quadro renderizado pela sua câmera. Portanto, o número de vezes que executamos essa função por segundo determina os quadros por segundo da nossa análise da métrica de atenção. Atualmente, ela está configurada para ser executada a cada 500 milissegundos, o que significa que, na prática, estamos analisando um modelo com FPS (quadros por segundo) de 2. Esse valor pode ser ajustado de acordo com o seu caso de uso.

Agora, vamos examinar a parte principal do nosso algoritmo, responsável por gerar uma pontuação e comunicá-la a todos os outros 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);
    }
  }
);

Esse trecho de código pode parecer intimidador, mas, na verdade, tudo o que estamos fazendo é executar a biblioteca de pontos de referência faciais no quadro atual do publisher, aplicar nosso getScore algoritmo nos ângulos entre determinados pontos do rosto detectado e, em seguida, transmitir a pontuação de atenção a todos os participantes.

Assim que o índice de atenção for sinalizado, precisamos garantir que estamos processando-o no lado receptor e fazendo o que quisermos com ele. Você pode exibi-lo em uma interface de usuário em tempo real (como fizemos neste projeto) ou armazená-lo em um banco de dados que possa ser usado para mapear métricas de atenção ao longo da duração da chamada. As possibilidades são infinitas!

Conclusão

A atenção é um fator fundamental para avaliar conversas, discursos, palestras e praticamente qualquer interação entre pessoas. Já aprendemos a estimá-la por meio da análise da malha facial e a integrá-la às nossas videochamadas. Essa estimativa pode ser aprimorada ainda mais com o uso de outras fontes de dados, como o monitoramento do movimento da íris, o reconhecimento de múltiplos rostos, etc.

Encontre uma versão totalmente funcional deste aplicativo no GitHub

Conte para a gente se você conseguiu fazer a detecção de atenção funcionar! Junte-se a nós na Comunidade de Desenvolvedores da Vonage no Slack ou envie um tweet para nós em VonageDev.

Compartilhar:

https://a.storyblok.com/f/270183/400x390/09555431c6/hamza-nasir.png
Hamza NasirDesenvolvedor Full Stack

Hamza é engenheiro de software e mora em Chicago. Ele trabalha na Webrtc.ventures, uma empresa líder no fornecimento de soluções WebRTC. Ele também atua como desenvolvedor full stack na Vonage, colaborando com a plataforma de Video para atender melhor às necessidades dos clientes. Como um introvertido que se orgulha disso, ele gosta de passar seu tempo livre brincando com seus gatos.