Ultralytics YOLO27 : Inscris-toi sur la liste d’attente.
Get Started
Leçonintermédiaire

Étiqueter et entraîner des modèles de pose

Rédige des étiquettes de points clés avec visibilité, définis correctement kpt_shape et flip_idx, entraîne le modèle sur COCO8-pose et convertis les points clés en angles articulaires soumis à un seuil de confiance.

L’estimation de pose représente chaque personne par 17 points numérotés. Ces points permettent de calculer les valeurs que les produits proposent : angles des coudes pour l’ergonomie, angles des genoux pour la rééducation, hauteur des hanches pour la détection des chutes. Deux clés du jeu de données déterminent si ces points sont fiables ; une erreur sur l’une ou l’autre ne génère aucune erreur — seulement un modèle qui confond la gauche et la droite, ou qui s’entraîne discrètement sans utiliser son augmentation la moins coûteuse.

Résultat

Entraîne yolo26n-pose.pt sur coco8-pose.yaml et calcule les angles des coudes gauche et droit de chaque personne à partir de result.keypoints, en ignorant les articulations dont le niveau de confiance du modèle est insuffisant.

Parcours accéléré
Si tu connais déjà les bases, voici la version courte.
  1. Ligne d’étiquette : classe, boîte (4 valeurs), puis x y v pour chaque point clé, le tout normalisé ; v vaut 0 (non étiqueté), 1 (occulté) ou 2 (visible).

  2. Définis kpt_shape: [K, 3] et un flip_idx qui échange chaque paire gauche-droite.

  3. yolo pose train data=coco8-pose.yaml model=yolo26n-pose.pt epochs=1 imgsz=320.

  4. Lis result.keypoints.xy et .conf ; ignore tout calcul dont les articulations passent sous un seuil de confiance.

Pratique

La ligne d’étiquette des points clés#

Estimation de pose Ultralytics YOLO de trois coureurs, chacun avec une boîte de personne et un squelette corporel à 17 points clés

Une ligne d’étiquette de pose est une ligne de détection à laquelle on ajoute des points clés. Chaque coordonnée est normalisée entre 0 et 1, et les points clés suivent le même ordre fixe dans chaque ligne. Voici une vraie ligne COCO8-pose, tronquée après quatre points clés :

0 0.671279 0.617945 0.645759 0.726859 0.519751 0.381250 2.000000 0.550936 0.348438 2.000000 0.488565 0.367188 2.000000 0.642412 0.354687 2.000000 ...
ValeursSignification
0indice de classe (personne)
0.671279 0.617945 0.645759 0.726859centre x de la boîte, centre y, largeur, hauteur
0.519751 0.381250 2point clé 0 (nez) : x, y, visibilité
…16 points clés supplémentaires selon le même format : 5 + 17 × 3 = 56 valeurs par ligne

L’indicateur de visibilité suit la convention COCO : 2 visible, 1 étiqueté mais occulté, 0 non étiqueté. Ultralytics masque les points clés dont la valeur est v = 0 dans la fonction de perte, afin que l’absence d’un poignet n’apprenne pas au modèle à prédire les poignets en (0, 0).

Éditeur d’annotations Ultralytics Platform sur une image COCO8-pose, avec des squelettes à 17 points clés dessinés sur les personnes qui découpent un gâteau

Étiqueter les articulations occultées que tu peux localiser

Utilise 1 pour une articulation occultée que tu peux localiser avec assurance — une hanche derrière une table, un poignet derrière le dos ; elle contribue toujours à l'entraînement. Réserve 0 aux articulations que personne ne pourrait localiser. Étiqueter chaque articulation cachée avec 0 élimine précisément les cas difficiles dont le modèle a besoin.

Le guide sur les jeux de données de pose couvre également la variante à deux valeurs (x y uniquement, kpt_shape: [K, 2]) destinée aux jeux de données sans visibilité.

kpt_shape et flip_idx#

Le YAML du jeu de données ajoute deux clés aux clés habituelles path, train, val et names :

kpt_shape: [17, 3] # 17 keypoints, each x, y, visibility
flip_idx: [0, 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15]

Ordre des 17 points clés COCO sur une personne debout, numérotés de 0 (nez) à 16 (cheville droite)

flip_idx indique à l’augmentation par retournement horizontal quel point clé correspond à chacun dans l’image miroir. Quand on retourne une personne, son poignet gauche (9) se retrouve à la place de son poignet droit (10) ; la position 9 de flip_idx contient donc 10, et la position 10 contient 9. Le nez (0) correspond à lui-même. Chaque augmentation déplace le squelette avec les pixels, et le retournement est la seule qui nécessite aussi la table de correspondance des indices :

Augmentations de pose d’un coureur : original, retournement horizontal, rotation, mise à l’échelle, couleur HSV et mosaïque, avec le squelette des points clés suivant chaque transformation

Que se passe-t-il lorsque flip_idx est incorrect, comme le confirme le code source installé :

  • Manquant : l’entraînement affiche un avertissement et définit fliplr et flipud sur 0. Tu perds ainsi ta augmentation la moins coûteuse.
  • Longueur incorrecte : l’entraînement s’arrête avec un ValueError qui signale l’incompatibilité — le seul échec explicite.
  • Longueur correcte, paires incorrectes : aucun avertissement. La moitié des exemples retournés apprend au modèle que la gauche est la droite, et les images de validation montrent des inversions gauche-droite sur les poses symétriques.

Entraîner sur COCO8-pose#

Mosaïque d’entraînement COCO8-pose : des personnes à moto, sous un parapluie rose, dans un skatepark et à cheval, chacune avec une boîte de personne et un squelette de points clés colorés

from ultralytics import YOLO

model = YOLO("yolo26n-pose.pt")
model.train(data="coco8-pose.yaml", epochs=1, imgsz=320, device="cpu")
metrics = model.val()
print(f"box  mAP50-95: {metrics.box.map:.3f}")
print(f"pose mAP50-95: {metrics.pose.map:.3f}")
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95)     Pose(P          R      mAP50  mAP50-95)
                   all          4         14          1      0.783      0.893      0.643      0.966      0.571      0.575      0.326
box  mAP50-95: 0.643
pose mAP50-95: 0.326

Comme pour la segmentation, le tableau comporte deux blocs. Box évalue les boîtes des personnes ; Pose évalue le placement des points clés à l’aide de la similarité des points clés d’objet (OKS), dans le même mécanisme de mAP. La mAP50-95 de pose est le critère de validation d’un produit de pose — la prochaine leçon montre comment l’OKS détermine si un point clé est correct.

Des points clés aux angles des articulations#

result.keypoints contient xy (N × K × 2, en pixels), xyn (normalisés) et conf (N × K), dans l’ordre COCO indiqué ci-dessus. L’angle d’une articulation est l’angle entre les deux vecteurs des membres qui s’y rejoignent — un produit scalaire :

import numpy as np

from ultralytics import YOLO

model = YOLO("yolo26n-pose.pt")
result = model("https://ultralytics.com/images/bus.jpg")[0]
kpts = result.keypoints.cpu().numpy()  # people x 17 x (x, y, conf)

SHOULDER, ELBOW, WRIST = 5, 7, 9  # left arm, COCO keypoint order
for person, (xy, conf) in enumerate(zip(kpts.xy, kpts.conf)):
    if conf[[SHOULDER, ELBOW, WRIST]].min() < 0.5:
        print(f"person {person}: left arm not visible enough")
        continue
    a, b, c = xy[SHOULDER], xy[ELBOW], xy[WRIST]
    cos = np.dot(a - b, c - b) / (np.linalg.norm(a - b) * np.linalg.norm(c - b))
    print(f"person {person}: left elbow angle {np.degrees(np.arccos(cos)):.0f} deg")
person 0: left elbow angle 71 deg
person 1: left elbow angle 96 deg
person 2: left elbow angle 59 deg
person 3: left arm not visible enough
person 4: left arm not visible enough

Ligne par ligne : kpts.xy[p] correspond aux 17 points en pixels de la personne p ; a - b et c - b sont les vecteurs du bras et de l’avant-bras partant du coude ; leur produit scalaire normalisé est le cosinus de l’angle qui les sépare. Un bras tendu donne une valeur proche de 180°, un bras complètement plié une valeur proche de 30°. Les personnes 3 et 4 ont au moins une articulation du bras gauche sous le seuil de confiance de 0.5, donc le script refuse de les mesurer.

Appliquer un seuil de confiance à chaque articulation

Symptôme : des angles qui semblent fiables pour des personnes dont les bras sont hors champ. Cause : le modèle renvoie des coordonnées pour chaque point clé, qu'il soit occulté ou non. Solution : ignore tout calcul dont les articulations se trouvent sous un seuil de confiance (0.5 ici) et consigne la fréquence de ces omissions — une hausse de ce taux est un signe précoce de changement de caméra ou d'éclairage.

Essayer

Entraîne une époque sur coco8-pose.yaml et note la mAP50-95 des boîtes et des poses. Étends ensuite pose.py pour qu’il indique aussi l’angle du coude droit (points clés 6, 8, 10), puis liste les personnes de l’image du bus dont les deux bras peuvent être mesurés.

Terminé lorsque
Tu as terminé la leçon lorsque tous les éléments suivants sont réunis.
  • L’entraînement est terminé et tu as noté la mAP50-95 des boîtes et des poses.

  • Ton script affiche les deux angles de coude pour chaque personne, en ignorant tout bras sous le seuil de confiance.

  • Tu peux expliquer ce qui se passe lorsque flip_idx est manquant, a une longueur incorrecte ou contient des paires incorrectes.

Afficher la solution
import numpy as np

from ultralytics import YOLO

ARMS = {"left": (5, 7, 9), "right": (6, 8, 10)}  # shoulder, elbow, wrist
kpts = YOLO("yolo26n-pose.pt")("https://ultralytics.com/images/bus.jpg")[0].keypoints.cpu().numpy()

for person, (xy, conf) in enumerate(zip(kpts.xy, kpts.conf)):
    for side, (s, e, w) in ARMS.items():
        if conf[[s, e, w]].min() < 0.5:
            continue
        a, b, c = xy[s], xy[e], xy[w]
        cos = np.dot(a - b, c - b) / (np.linalg.norm(a - b) * np.linalg.norm(c - b))
        print(f"person {person}: {side} elbow {np.degrees(np.arccos(cos)):.0f} deg")
person 0: left elbow 71 deg
person 0: right elbow 94 deg
person 1: left elbow 96 deg
person 2: left elbow 59 deg
person 2: right elbow 135 deg

Les personnes 0 et 2 ont les deux bras mesurables. Le bras droit de la personne 1 et les deux bras des personnes 3 et 4 sont sous le seuil de confiance de 0.5 ; le script les ignore donc au lieu de faire des suppositions.

Un flip_idx manquant désactive l’augmentation par retournement avec un avertissement ; une longueur incorrecte arrête l’entraînement avec un ValueError ; un flip_idx d’apparence valide mais contenant des paires incorrectes entraîne silencieusement le modèle sur des étiquettes inversées et provoque des inversions gauche-droite lors de la validation.

Et ensuite ?

Ensuite, nous concevons des points clés pour des objets autres que des personnes et découvrons comment l’OKS détermine si un point clé est correct.