Pose Estimation no Browser: utilizando TensorFlow.js para medir seus exercícios físicos

Hugo Zanini
Data Hackers
Published in
7 min readMay 10, 2020

Essa semana faz um mês que estou em regime de home office devido à quarentena do covid-19. Dentre os muitos desafios de trabalhar em casa, o maior deles tem sido encontrar uma forma divertida e eficiente de me exercitar. Após várias tentativas, acabei me adaptando bem aos exercícios e planos de treino do aplicativo Nike Training Club. Para cada atividade, ele apresenta um pequeno vídeo de exemplo e determina o tempo de execução do movimento.

Telas do aplicativo Nike Training Club (Fonte)

Gostei muito do app, mas senti falta de métricas que indicassem meu desempenho nos exercícios. Nos últimos tempos, venho trabalhando bastante com algoritmos de identificação de poses e resolvi testar algum método que possibilitasse medir os treinos em tempo real.

O que é a identificação de poses?

A identificação de poses baseia-se na localização de juntas humanas (também conhecidas como keypoints) em imagens ou videos. Essa informação é muito útil em aplicações de realidade aumentada, animações e reconhecimento de atividades. O primeiro, e mais conhecido, método para a identificação de poses 2D em tempo real é o OpenPose. Ele apresenta uma alta precisão para diversos cenários, independentemente do número de pessoas na cena.

Identificação de poses 2D em tempo real com o OpenPose

O OpenPose, e grande parte dos métodos da mesma categoria, são treinados em um conjunto de dados conhecido como COCO (Objetos Comuns em Contexto) com mais de 250000 pessoas com keypoints. O esqueleto humano definido por esse dataset é composto por 18 pontos.

Embora o OpenPose e outros projetos apresentem bons resultados em tempo real, eles necessitam de hardware ou câmeras especializadas para isso, além de bibliotecas com instalações que podem ser trabalhosas. Para esse projeto de medição de treinos, o ideal seria algo mais leve e simples de trabalhar, a solução foi a utilização de uma biblioteca chamada TensorFlow.js.

TensorFlow.js

O TensorFlow é uma biblioteca open-source muito utilizada na criação de modelos de Machine Learning (ML), principalmente em projetos Python. A chegada do Tensorflow.js possibilitou que os mesmos processos de desenvolvimento, treino e execução dos modelos pudessem ser feitos a partir de um navegador web utilizando Javascript. Apesar de familiar com o TensorFlow, nunca havia trabalhado com Javascript e achei esse projeto uma boa forma de aprender mais sobre Machine Learning in-browser.

Ao rodar uma aplicação diretamente no navegador, não há a necessidade de instalação de nenhuma biblioteca ou driver — abrir uma página web já é o suficiente. Além disso, o TensorFlow.js oferece suporte ao processamento de gráficos web (WebGL) e acelera o processo de execução quando existem GPUs disponíveis. Os usuários também podem usar a aplicação no celular, o que abre ainda mais possibilidades, permitindo com que os modelos extraiam dados de sensores como giroscópio ou acelerômetro, por exemplo. Nesses casos, todos os dados permanecem no cliente, fornecendo uma solução de baixa latência e preservando a privacidade das informações [1].

Detecção de poses no navegador: Posenet

Posenet é uma biblioteca para a estimação de poses a partir de pesos pré-treinados. Ela foi desenvolvida pelo Google Creative Lab e construída em TensorFlow.js, o que faz com que a aplicação rode em tempo real em navegadores web. O link a seguir explica de forma detalhada toda a arquitetura do modelo.

Apesar do processamento rápido e leve, o PoseNet possui uma precisão inferior ao OpenPose. Se confunde bastante quando existem muitas pessoas na cena e falha na identificação de algumas juntas. O vídeo abaixo apresenta uma comparação entre os dois modelos.

Comparação entre OpenPose e PoseNet

Para a nossa aplicação, no entanto, o PoseNet será suficiente pois trata-se um ambiente controlado e sem muitas obstruções.

“Quem vê close não vê pose”

Após estabelecer o modelo e ferramentas que serão utilizadas, é hora de definir as atividades a serem medidas e como os keypoints podem ajudar nisso. Optou-se por dois exercícios básicos e com movimentos distintos: levantamento de pesos e polichinelos.

Atividades que serão medidas: Levantamento de pesos e polichinelos (Fonte)

A ideia é utilizar os keypoints de saída da PoseNet para identificar essas duas atividades. O esqueleto gerado pelo modelo é indexado para cada uma das partes do corpo humano, conforme a imagem a seguir:

Partes do corpo humano detectadas pela PoseNet (Fonte)

Com essas informações é possível simplificar o problema e considerar as pessoas como uma relação entre pontos e retas. Dessa forma, medir os exercícios passa a ser a tarefa de identificar tais relações entre cada parte do corpo humano. Para fazer isso, serão utilizadas álgebra linear e geometria.

Representação do corpo humano por keypoints

Levantamento de pesos

Para contar o número de repetições de levantamento de pesos, serão analisados os ângulos entre as partes envolvidas. Foram selecionados os pontos 7, 8, 9 e 10 que correspondem aos conjuntos cotovelo-pulso do lado esquerdo e direito.

Função atan2 (Fonte)

A ideia é usar o cotovelo como referência e calcular o ângulo da reta que liga os dois pontos. Para calcular este ângulo, será utilizada a função atan2(y, x). Ela retorna o ângulo θ entre a origem e o ponto (x,y) considerando o eixo x no intervalo (-π, π].

Para completar uma repetição, o usuário precisa realizar um ciclo de levantar e abaixar os pesos com ambos os braços, portanto, é necessário reconhecer pares de ângulos positivos e negativos.

A imagem a seguir mostra um caso em que o usuário levantou um peso e o pulso encontra-se em uma posição mais elevada que o cotovelo.

Representação da elevação de um peso no plano cartesiano

Para simplificar o problema, essa reta será representada a partir da origem. É possível alterar as cordenadas de referência a partir da operação Pulso(10,12) − Cotovelo(6,7). Obtem-se então um ponto que servirá para o cálculo do ângulo a partir da função atan2. Conforme a imagem a seguir:

Representação da elevação de um peso no plano cartesiano considerando o cotovelo como origem

Para facilitar a visualização, a animação abaixo representa os movimentos do exercício. Ângulos positivos indicam subida e ângulos negativos descida.

Representação das repetições no plano cartesiano

Imagens são representadas na forma de matrizes, portanto, cada um dos pontos resultantes das predições do modelo possuem um par de coordenadas (x,y). Dessa forma, o cálculo dos ângulos é facilmente realizado em Javascript a partir das seguintes linhas de código:

Calculo dos ângulos de subida e descida em Javascript

Com essas informações em mãos, o processo de identificação de repetições deu-se pela criação de regras if-then-else em cada inferência realizada. Todo o código fonte do projeto está disponível ao final desse post, os scripts estão bem claros e irão possibilitar uma compreensão melhor dessas regras.

Polichinelos

Na identificação dos polichinelos, optou-se uma abordagem mais simples e que baseou-se apenas nas distâncias das coordenadas horizontais dos tornozelos e pulsos — foram utilizados os pontos 9, 10, 15 e 16.

Quando esses membros antingirem simultaneamente os limiares de proximidade definidos, tanto para contração ou extensão, será contabilizada uma repetição do movimento.

A definição dos limiares depende da resolução da câmera utilizada e é necessário uma calibração antes da primeira utilização da aplicação. Por enquanto, isso está sendo feito partir de tentativa e erro, simulando movimentos de contração e extensão e anotando a diferença entre os pulsos e tornozelos. Os pares de movimentos a seguir indicam uma repetição do exercício.

Exemplos de movimentos de contração e extensão durante a execução de polichinelos

No meu caso, durante a contração, o valor médio da diferença entre a coordenada horizontal dos pulsos é de 75 pixels e dos tornozelos de 15 pixels. Na extensão essas distâncias mudam para 35 e 67 pixels, respectivamente. Assim como no levantamento de pesos, as repetições foram medidas a partir de regras if-then-else, também disponíveis ao final desse post.

Demonstração

Para gerar uma aplicação que conseguisse medir os treinos, utilizou-se como base os exemplos do repositório de modelos pré-treinados do TensorFlow.js. Todos os botões de controle e interação com o usuário foram feitos com o auxílio da biblioteca dat.GUI, uma ferramenta open source desenvolvida pelo time de Data Arts do Google. O video a seguir é um exemplo do projeto rodando em tempo real no navegador:

Identificação de atividades no navegador em tempo real

Os códigos e detalhes de implementação estão disponíveis no repositório github do projeto.

Trabalhos Futuros

Essa foi a minha primeira aplicação utilizando TensorFlow.js e ainda há muito espaço para evolução. A ideia desse post foi compartilhar os meus aprendizados e mostrar a simplicidade de desenvolvimento de projetos com a biblioteca.

A utilização de poses para a obtenção de métricas de performance em atividades físicas é algo ainda pouco difundido, mas apresenta um potencial enorme. Além da contagem de repetições, o esqueleto humano pode indicar a amplitude dos movimentos executados, se o exercício foi executado corretamente e problemas como má postura ou escoliose.

Modelos leves como o PoseNet podem ser executados em celulares e aplicações como o Nike Training Club poderiam ser integradas com a câmera do dispositivo para coletar essas informações.

Caso você tenha se interessado, sinta-se a vontade para contribuir com ajustes ou novos exercícios através do github do projeto. Se ficou alguma dúvida, deixe aqui nos comentários ou me chame no Linkedin :)

Referências

[1] https://medium.com/tensorflow/introducing-tensorflow-js-machine-learning-in-javascript-bf3eab376db

--

--

Hugo Zanini
Data Hackers

GDE in Machine Learning| Electrical Engineer | Technical Product Manager