Options de classification des postures

L'API Pose Detection de ML Kit vous permet d'obtenir des interprétations pertinentes d'une posture en vérifiant les positions relatives de différentes parties du corps. Cette page présente quelques exemples.

Classification des postures et comptabilisation des répétitions avec l'algorithme k-NN

Le suivi de l'activité physique est l'une des applications les plus courantes de la détection des postures. Créer un classificateur de postures qui reconnaît des postures de fitness spécifiques et comptabilise le nombre de répétitions peut s'avérer difficile pour les développeurs.

Dans cette section, nous décrivons comment nous avons créé un classificateur de pose personnalisé à l'aide de MediaPipe Colab et comment nous avons présenté un classificateur fonctionnel dans notre application exemple ML Kit.

Si vous ne connaissez pas Google Colaboratory, consultez le guide d'introduction.

Pour reconnaître les postures, nous utilisons l'algorithme des k-plus proches (k-NN), car il est simple et facile à utiliser. L'algorithme détermine la classe de l'objet en fonction des échantillons les plus proches de l'ensemble d'entraînement.

Pour créer et entraîner le programme de reconnaissance:

1. Collecter des échantillons d'images

Nous avons recueilli des images des exercices ciblés à partir de différentes sources. Nous avons choisi quelques centaines d'images pour chaque exercice, telles que les positions "haut" et "bas" pour les pompes. Il est important de collecter des échantillons couvrant différents angles de prise de vue, conditions environnementales, formes de corps et variantes d'exercices.

Figure 1 : Positions de pompes haut et bas

2. Exécuter la détection des postures sur les exemples d'images

Vous obtenez ainsi un ensemble de points de repère de posture à utiliser pour l'entraînement. La détection des postures ne nous intéresse pas, car nous allons entraîner notre propre modèle à l'étape suivante.

L'algorithme k-NN que nous avons choisi pour la classification des postures personnalisée nécessite une représentation d'un vecteur de caractéristiques pour chaque échantillon et une métrique pour calculer la distance entre deux vecteurs et trouver la cible la plus proche de l'échantillon de pose. Cela signifie que nous devons convertir les points de repère de position que nous venons d'obtenir.

Pour convertir les points de repère de pose en vecteur de caractéristiques, nous utilisons les distances par paire entre les listes prédéfinies d'articulations des poses, telles que la distance entre les poignets et les épaules, la cheville et la hanche, et les poignets gauche et droit. Étant donné que l'échelle des images peut varier, nous avons normalisé les postures afin qu'elles aient la même taille de torse et la même orientation verticale du torse avant de convertir les points de repère.

3. Entraîner le modèle et compter les répétitions

Nous avons utilisé MediaPipe Colab pour accéder au code du classificateur et entraîner le modèle.

Pour comptabiliser les répétitions, nous avons utilisé un autre algorithme Colab afin de surveiller le seuil de probabilité d'une position cible. Exemple :

  • Lorsque la probabilité de la classe de pose "vers le bas" dépasse un seuil donné pour la première fois, l'algorithme indique que la classe de pose "bas" est saisie.
  • Lorsque la probabilité passe en dessous du seuil, l'algorithme indique que la classe de pose "down" a été quittée et augmente le compteur.
Figure 2 : Exemple de comptabilisation des répétitions

4. Intégrer à l'application de démarrage rapide ML Kit

Le Colab ci-dessus génère un fichier CSV que vous pouvez remplir avec tous vos exemples de postures. Dans cette section, vous allez apprendre à intégrer votre fichier CSV à l'application de démarrage rapide ML Kit pour Android afin d'afficher la classification des postures personnalisées en temps réel.

Essayez la classification des postures avec des exemples regroupés dans l'application de démarrage rapide

  • Obtenez le projet d'application de démarrage rapide de ML Kit pour Android à partir de GitHub, et assurez-vous qu'il compile et s'exécute correctement.
  • Accédez à LivePreviewActivity et activez la détection des postures Run classification sur la page des paramètres. Vous devriez maintenant pouvoir classer les pompes et les squats.

Ajouter votre propre fichier CSV

  • Ajoutez le fichier CSV au dossier des composants de l'application.
  • Dans PoseClassifierProcessor, mettez à jour les variables POSE_SAMPLES_FILE et POSE_CLASSES pour qu'elles correspondent à votre fichier CSV et à vos exemples de pose.
  • Créez et exécutez l'application.

Notez que la classification peut ne pas fonctionner correctement si le nombre d'échantillons est insuffisant. En règle générale, vous avez besoin d'environ 100 échantillons par classe de pose.

Pour en savoir plus et essayer par vous-même, consultez le Colab MediaPipe et le guide de classification MediaPipe.

Reconnaître des gestes simples en calculant la distance d'un point de repère

Lorsque deux points de repère ou plus sont proches l'un de l'autre, ils peuvent être utilisés pour reconnaître des gestes. Par exemple, lorsque le point de repère d'un ou plusieurs doigts sur une main est proche de celui du nez, vous pouvez en déduire que l'utilisateur touche très probablement son visage.

Figure 3 : Interpréter une posture

Reconnaître une posture de yoga avec la méthode heuristique d'angle

Vous pouvez identifier une posture de yoga en calculant les angles des différentes articulations. Par exemple, la figure 2 ci-dessous illustre la posture de yoga Warrior II. Les angles approximatifs qui identifient cette position sont écrits de la manière suivante:

Figure 4 : Présenter un angle de prise de vue

Cette posture peut être décrite comme la combinaison suivante d'angles approximatifs de la partie du corps:

  • Angle de 90° au niveau des deux épaules
  • 180 degrés au niveau des deux coudes
  • Angle de 90 degrés au niveau de la jambe avant et de la taille
  • Angle de 180° au niveau du genou arrière
  • Angle de 135 degrés au niveau de la taille

Vous pouvez utiliser les points de repère de pose pour calculer ces angles. Par exemple, l'angle au niveau de la jambe avant droite et de la taille correspond à l'angle entre la ligne entre l'épaule droite et la hanche droite, et la ligne entre la hanche droite et le genou droit.

Une fois que vous avez calculé tous les angles nécessaires pour identifier la posture, vous pouvez vérifier s'il existe une correspondance. Dans ce cas, vous avez reconnu la pose.

L'extrait de code ci-dessous montre comment utiliser les coordonnées X et Y pour calculer l'angle entre deux parties du corps. Cette approche de la classification présente certaines limites. En ne vérifiant que les valeurs X et Y, les angles calculés varient en fonction de l'angle entre le sujet et l'appareil photo. Vous obtiendrez les meilleurs résultats avec une image de niveau direct. Vous pouvez également essayer d'étendre cet algorithme en utilisant la coordonnée Z et voir s'il fonctionne mieux pour votre cas d'utilisation.

Calculer des angles de points de repère sur Android

La méthode suivante calcule l'angle entre trois repères. Elle garantit que l'angle renvoyé est compris entre 0 et 180 degrés.

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

Voici comment calculer l'angle pour le bassin droit:

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

Calculer des angles de points de repère sur iOS

La méthode suivante calcule l'angle entre trois repères. Elle garantit que l'angle renvoyé est compris entre 0 et 180 degrés.

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

Voici comment calculer l'angle pour le bassin droit:

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