Opções de classificação de poses

Com a API ML Kit Pose Detection, é possível derivar interpretações significativas de uma pose verificando as posições relativas de várias partes do corpo. Nesta página, demonstramos alguns exemplos.

Posições de classificação e contagem de repetições com o algoritmo k-NN

Uma das aplicações mais comuns da detecção de poses é o monitoramento de condicionamento físico. Criar um classificador de poses que reconheça poses específicas de condicionamento físico e conta repetições pode ser um desafio para os desenvolvedores.

Nesta seção, descrevemos como criamos um classificador de poses personalizado usando o MediaPipe Colab e demonstramos um classificador funcional no nosso app de exemplo do Kit de ML.

Se você não conhece o Google Colaboratory, confira o guia de introdução.

Para reconhecer poses, usamos o algoritmo de vizinhos mais próximos (k-NN), porque ele é simples e fácil de começar. O algoritmo determina a classe do objeto com base nas amostras mais próximas no conjunto de treinamento.

Siga estas etapas para criar e treinar o reconhecedor:

1. Coletar amostras de imagem

Coletamos amostras de imagens dos exercícios-alvo de várias fontes. Escolhemos algumas centenas de imagens para cada exercício, como as posições para cima e para baixo. É importante coletar amostras que cubram diferentes ângulos de câmera, condições do ambiente, formas do corpo e variações de exercícios.

Figura 1. posições de flexão para cima e para baixo

2. Executar a detecção de pose nas imagens de amostra

Isso produz um conjunto de pontos de referência de poses a ser usado para treinamento. Não temos interesse na detecção de poses em si, já que vamos treinar nosso próprio modelo na próxima etapa.

O algoritmo k-NN que escolhemos para classificação de poses personalizada requer uma representação de vetor de atributo para cada amostra e uma métrica para calcular a distância entre dois vetores e encontrar o alvo mais próximo da amostra de poses. Isso significa que precisamos converter os pontos de referência de poses que acabamos de obter.

Para converter pontos de referência de poses em um vetor de atributo, usamos as distâncias em pares entre listas predefinidas de articulações de poses, como a distância entre pulso e ombro, tornozelo e quadril, e pulsos esquerdo e direito. Como a escala das imagens pode variar, normalizamos as poses para que tenham o mesmo tamanho e orientação vertical do tronco antes de converter os pontos de referência.

3. Treine o modelo e conte as repetições

Usamos o MediaPipe Colab para acessar o código do classificador e treinar o modelo.

Para contar repetições, usamos outro algoritmo do Colab para monitorar o limite de probabilidade de uma posição desejada. Exemplo:

  • Quando a probabilidade da classe de poses "para baixo" passar de um determinado limite pela primeira vez, o algoritmo marca que essa classe foi inserida.
  • Quando a probabilidade fica abaixo do limite, o algoritmo marca que a classe de posição "para baixo" foi removida e aumenta o contador.
Figura 2. exemplo de contagem de repetições

4. Integrar com o app de início rápido do Kit de ML

O Colab acima produz um arquivo CSV que você pode preencher com todas as suas amostras de poses. Nesta seção, você vai aprender a integrar seu arquivo CSV ao app de início rápido do Kit de ML para Android e conferir a classificação personalizada de poses em tempo real.

Teste a classificação de poses com amostras incluídas no app de início rápido

  • Acesse o projeto do app de início rápido do Kit de ML para Android (em inglês) no GitHub e verifique se ele é criado e executado corretamente.
  • Acesse LivePreviewActivity e ative a detecção de poses Run classification na página "Configurações". Agora você deve saber classificar flexões e agachamentos.

Adicionar seu CSV

  • Adicione o arquivo CSV à pasta de recursos do app.
  • Em PoseClassifierProcessor, atualize as variáveis POSE_SAMPLES_FILE e POSE_CLASSES para corresponder ao seu arquivo CSV e amostras de poses.
  • Compile e execute o aplicativo.

A classificação pode não funcionar bem se não houver amostras suficientes. Geralmente, você precisa de cerca de 100 amostras por classe de poses.

Para saber mais e testar isso, confira o MediaPipe Colab e o guia de classificação do MediaPipe.

Reconhecimento de gestos simples pelo cálculo da distância do ponto de referência

Quando dois ou mais pontos de referência estão próximos um do outro, eles podem ser usados para reconhecer gestos. Por exemplo, quando o ponto de referência de um ou mais dedos em uma mão está perto do ponto de referência do nariz, é possível inferir que o usuário está mais propenso a tocar o rosto.

Figura 3. Como interpretar uma pose

Reconhecer uma postura de ioga com heurística de ângulos

Você pode identificar uma postura de ioga calculando os ângulos de várias articulações. Por exemplo, a Figura 2 abaixo mostra a postura de ioga do Guerreiro II. Os ângulos aproximados que identificam essa postura são gravados em:

Figura 4. Divisão da pose em ângulos

Essa postura pode ser descrita como a seguinte combinação de ângulos aproximados de partes do corpo:

  • Ângulo de 90 graus nos dois ombros
  • 180 graus nos dois cotovelos
  • Ângulo de 90 graus na perna dianteira e na cintura
  • Ângulo de 180 graus na parte de trás do joelho
  • Ângulo de 135 graus na cintura

Você pode usar os pontos de referência de poses para calcular esses ângulos. Por exemplo, o ângulo na perna direita e na cintura é o ângulo entre a linha do ombro direito ao quadril direito e a linha do quadril direito até o joelho direito.

Depois de calcular todos os ângulos necessários para identificar a pose, verifique se há uma correspondência. Nesse caso, você a reconheceu.

O snippet de código abaixo demonstra como usar as coordenadas X e Y para calcular o ângulo entre duas partes do corpo. Essa abordagem de classificação tem algumas limitações. Ao verificar apenas X e Y, os ângulos calculados variam de acordo com o ângulo entre o objeto e a câmera. Você terá os melhores resultados com uma imagem nivelada e de frente. Você também pode tentar estender esse algoritmo usando a coordenada Z e ver se o desempenho é melhor no seu caso de uso.

Como calcular ângulos importantes no Android

O método a seguir calcula o ângulo entre três pontos de referência. Isso garante que o ângulo retornado esteja entre 0 e 180 graus.

Kotlin

fun getAngle(firstPoint: PoseLandmark, midPoint: PoseLandmark, lastPoint: PoseLandmark): Double {
        var result = Math.toDegrees(atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                firstPoint.getPosition().x - midPoint.getPosition().x))
        result = Math.abs(result) // Angle should never be negative
        if (result > 180) {
            result = 360.0 - result // Always get the acute representation of the angle
        }
        return result
    }

Java

static double getAngle(PoseLandmark firstPoint, PoseLandmark midPoint, PoseLandmark lastPoint) {
  double result =
        Math.toDegrees(
            atan2(lastPoint.getPosition().y - midPoint.getPosition().y,
                      lastPoint.getPosition().x - midPoint.getPosition().x)
                - atan2(firstPoint.getPosition().y - midPoint.getPosition().y,
                      firstPoint.getPosition().x - midPoint.getPosition().x));
  result = Math.abs(result); // Angle should never be negative
  if (result > 180) {
      result = (360.0 - result); // Always get the acute representation of the angle
  }
  return result;
}

Veja como calcular o ângulo no quadril direito:

Kotlin

val rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE))

Java

double rightHipAngle = getAngle(
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_SHOULDER),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_HIP),
                pose.getPoseLandmark(PoseLandmark.Type.RIGHT_KNEE));

Como calcular ângulos de pontos de referência no iOS

O método a seguir calcula o ângulo entre três pontos de referência. Isso garante que o ângulo retornado esteja entre 0 e 180 graus.

Swift

func angle(
      firstLandmark: PoseLandmark,
      midLandmark: PoseLandmark,
      lastLandmark: PoseLandmark
  ) -> CGFloat {
      let radians: CGFloat =
          atan2(lastLandmark.position.y - midLandmark.position.y,
                    lastLandmark.position.x - midLandmark.position.x) -
            atan2(firstLandmark.position.y - midLandmark.position.y,
                    firstLandmark.position.x - midLandmark.position.x)
      var degrees = radians * 180.0 / .pi
      degrees = abs(degrees) // Angle should never be negative
      if degrees > 180.0 {
          degrees = 360.0 - degrees // Always get the acute representation of the angle
      }
      return degrees
  }

Objective-C

(CGFloat)angleFromFirstLandmark:(MLKPoseLandmark *)firstLandmark
                      midLandmark:(MLKPoseLandmark *)midLandmark
                     lastLandmark:(MLKPoseLandmark *)lastLandmark {
    CGFloat radians = atan2(lastLandmark.position.y - midLandmark.position.y,
                            lastLandmark.position.x - midLandmark.position.x) -
                      atan2(firstLandmark.position.y - midLandmark.position.y,
                            firstLandmark.position.x - midLandmark.position.x);
    CGFloat degrees = radians * 180.0 / M_PI;
    degrees = fabs(degrees); // Angle should never be negative
    if (degrees > 180.0) {
        degrees = 360.0 - degrees; // Always get the acute representation of the angle
    }
    return degrees;
}

Veja como calcular o ângulo no quadril direito:

Swift

let rightHipAngle = angle(
      firstLandmark: pose.landmark(ofType: .rightShoulder),
      midLandmark: pose.landmark(ofType: .rightHip),
      lastLandmark: pose.landmark(ofType: .rightKnee))

Objective-C

CGFloat rightHipAngle =
    [self angleFromFirstLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightShoulder]
                     midLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightHip]
                    lastLandmark:[pose landmarkOfType:MLKPoseLandmarkTypeRightKnee]];