Ultralytics YOLO27: Trag dich in die Warteliste ein.
Get Started
LektionFortgeschrittene

Pose-Modelle kennzeichnen und trainieren

Erstelle Keypoint-Labels mit Sichtbarkeit, setze kpt_shape und flip_idx korrekt, trainiere mit COCO8-pose und wandle Keypoints in Konfidenzschwellen unterliegende Gelenkwinkel um.

Die Posenschätzung bildet jede Person durch 17 nummerierte Punkte ab. Aus diesen Punkten lassen sich Kennzahlen ableiten, die sich für Produkte nutzen lassen: Ellbogenwinkel für Ergonomie, Kniebeugewinkel für die Rehabilitation und Hüfthöhe zur Sturzerkennung. Zwei Schlüssel im Datensatz entscheiden darüber, ob du diesen Punkten vertrauen kannst. Fehler bei einem der beiden verursachen keine Fehlermeldung – das Modell verwechselt lediglich links und rechts oder trainiert unbemerkt ohne die kostengünstigste Augmentierung.

Lernergebnis

Trainiere yolo26n-pose.pt mit coco8-pose.yaml und berechne anhand von result.keypoints die linken und rechten Ellbogenwinkel jeder Person. Überspringe dabei Gelenke, bei denen sich das Modell nicht sicher ist.

Schnellkurs
Wenn du dich bereits auskennst, findest du hier die Kurzfassung.
  1. Labelzeile: Klasse, Box (4 Werte), dann x y v pro Keypoint, alles normalisiert; v ist 0 (nicht gelabelt), 1 (verdeckt) oder 2 (sichtbar).

  2. Setze kpt_shape: [K, 3] und ein flip_idx, das alle linken und rechten Gegenstücke vertauscht.

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

  4. Lies result.keypoints.xy und .conf aus. Überspringe alle Berechnungen, bei denen die Gelenke unter einem Konfidenzgrenzwert liegen.

Praxisnah

Die Keypoint-Labelzeile#

Ultralytics YOLO-Posenschätzung von drei Läufern, jeweils mit einer Personenbox und einem Skelett aus 17 Keypoints

Eine Pose-Labelzeile ist eine Erkennungszeile mit angehängten Keypoints. Jede Koordinate ist auf 0–1 normalisiert, und die Keypoints stehen in jeder Zeile in derselben festen Reihenfolge. Eine echte COCO8-pose-Zeile, gekürzt nach vier Keypoints:

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 ...
WerteBedeutung
0Klassenindex (Person)
0.671279 0.617945 0.645759 0.726859Mittelpunkt x, Mittelpunkt y, Breite, Höhe der Box
0.519751 0.381250 2Keypoint 0 (Nase): x, y, Sichtbarkeit
…16 weitere Keypoints im selben Format: 5 + 17 × 3 = 56 Werte pro Zeile

Die Sichtbarkeitskennzeichnung folgt der COCO-Konvention: 2 sichtbar, 1 gelabelt, aber verdeckt, 0 nicht gelabelt. Ultralytics blendet Keypoints mit v = 0 in der Verlustfunktion aus. So lernt das Modell bei einem fehlenden Handgelenk nicht, Handgelenke an der Position (0, 0) vorherzusagen.

Ultralytics-Plattform, Annotationseditor für ein COCO8-pose-Bild mit 17-Keypoint-Skeletten über den Personen, die einen Kuchen schneiden

Verdeckte Gelenkpunkte beschriften, die du lokalisieren kannst

Verwende 1 für einen verdeckten Gelenkpunkt, den du zuverlässig lokalisieren kannst – etwa eine Hüfte hinter einem Tisch oder ein Handgelenk hinter dem Rücken; er kann trotzdem zum Training beitragen. Verwende 0 nur für Gelenkpunkte, die niemand lokalisieren kann. Jeden verdeckten Gelenkpunkt mit 0 zu beschriften, verwirft genau die schwierigen Fälle, die das Modell braucht.

Die Anleitung zu Posendatensätzen behandelt auch die Variante mit zwei Werten (x y allein, kpt_shape: [K, 2]) für Datensätze ohne Sichtbarkeitsangaben.

kpt_shape und flip_idx#

Die YAML-Datei des Datensatzes ergänzt die beiden üblichen Schlüssel path, train, val und names um zwei weitere:

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]

Reihenfolge der 17 COCO-Keypoints an einer stehenden Person, nummeriert von 0 für die Nase bis 16 für den rechten Knöchel

flip_idx gibt der Augmentierung durch horizontales Spiegeln an, welchem Keypoint jeder Punkt im Spiegelbild entspricht. Wird eine Person gespiegelt, landet ihr linkes Handgelenk (9) dort, wo zuvor das rechte Handgelenk (10) war. Deshalb steht an Position 9 von flip_idx der Wert 10 und an Position 10 der Wert 9; die Nase (0) wird sich selbst zugeordnet. Jede Augmentierung verschiebt das Skelett zusammen mit den Pixeln. Nur beim Spiegeln wird zusätzlich die Indexzuordnung benötigt:

Posen-Augmentierungen eines Läufers: Original, horizontale Spiegelung, Drehung, Skalierung, HSV-Farbe und Mosaik, wobei das Keypoint-Skelett jeder Transformation folgt

Was passiert, wenn flip_idx falsch ist, überprüft im installierten Quellcode:

  • Fehlt: Beim Training wird eine Warnung ausgegeben und fliplr sowie flipud werden auf 0 gesetzt. Dadurch geht deine kostengünstigste Augmentierung verloren.
  • Falsche Länge: Das Training wird mit einem ValueError abgebrochen, das auf die Abweichung hinweist – der einzige Fehler, der deutlich gemeldet wird.
  • Richtige Länge, falsche Paare: Es gibt keine Warnung. Bei der Hälfte der gespiegelten Beispiele lernt das Modell, dass links rechts ist, und Validierungsbilder zeigen bei symmetrischen Posen vertauschte Seiten.

Mit COCO8-pose trainieren#

COCO8-pose-Trainingsmosaik: Personen auf einem Motorrad, unter einem pinken Regenschirm, in einem Skatepark und auf einem Pferd, jeweils mit einer Personen-Bounding-Box und einem farbigen Keypoint-Skelett

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

Wie bei der Segmentierung besteht die Tabelle aus zwei Blöcken. Box bewertet die Personen-Bounding-Boxes; Pose bewertet die Platzierung der Keypoints mit Object-Keypoint-Ähnlichkeit (OKS) innerhalb derselben mAP-Berechnung. Pose mAP50-95 ist die Freigabeschwelle für ein Pose-Produkt – die nächste Lektion zeigt, wie OKS entscheidet, ob ein Keypoint richtig platziert ist.

Von Keypoints zu Gelenkwinkeln#

result.keypoints enthält xy (N × K × 2, Pixel), xyn (normalisiert) und conf (N × K) in der oben gezeigten COCO-Reihenfolge. Der Winkel an einem Gelenk ist der Winkel zwischen den beiden dort zusammentreffenden Gliedmaßenvektoren – berechnet mit einem Skalarprodukt:

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

Zeile für Zeile: kpts.xy[p] sind die 17 Punkte von Person p in Pixeln; a - b und c - b sind Oberarm und Unterarm als Vektoren vom Ellbogen aus; ihr normalisiertes Skalarprodukt ist der Kosinus des Winkels zwischen ihnen. Ein gestreckter Arm ergibt einen Wert nahe 180°, ein vollständig angewinkelter einen Wert nahe 30°. Bei Personen 3 und 4 liegt mindestens ein Gelenk des linken Arms unter einer Konfidenz von 0,5, daher misst das Skript diese Personen nicht.

Für jeden Gelenkpunkt die Konfidenz berücksichtigen

Symptom: Winkel, die zuverlässig wirken, obwohl die Arme der Personen außerhalb des Bildes liegen. Ursache: Das Modell gibt für jeden Schlüsselpunkts eine Koordinate zurück, unabhängig davon, ob er verdeckt ist. Lösung: Überspringe jede Berechnung, deren Gelenkpunkte unter einem Konfidenzschwellenwert liegen (hier 0.5), und protokolliere, wie oft du sie überspringst – eine steigende Überspringrate ist ein frühes Anzeichen für veränderte Kamera- oder Lichtverhältnisse.

Ausprobieren

Trainiere eine Epoche mit coco8-pose.yaml und notiere die Box- und Pose-mAP50-95-Werte. Erweitere dann pose.py, sodass auch der Winkel des rechten Ellbogens ausgegeben wird (Keypoints 6, 8, 10), und liste auf, bei welchen Personen im Busbild beide Arme messbar sind.

Abgeschlossen, wenn
Du hast die Lektion abgeschlossen, wenn alle folgenden Punkte zutreffen.
  • Das Training wurde abgeschlossen und du hast die Box- und Pose-mAP50-95-Werte notiert.

  • Dein Skript gibt für jede Person beide Ellbogenwinkel aus und überspringt jeden Arm, der unter dem Konfidenzgrenzwert liegt.

  • Du kannst erklären, was passiert, wenn flip_idx fehlt, die falsche Länge hat oder falsche Paare enthält.

Lösung anzeigen
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

Bei Personen 0 und 2 sind beide Arme messbar. Der rechte Arm von Person 1 und beide Arme von Personen 3 und 4 liegen unter dem Konfidenzgrenzwert von 0,5. Daher überspringt das Skript diese Arme, statt Werte zu schätzen.

Ein fehlendes flip_idx deaktiviert mit einer Warnung die Spiegelungsaugmentierung; eine falsche Länge bricht das Training mit einem ValueError ab; ein plausibel wirkendes flip_idx mit falschen Paaren führt dazu, dass stillschweigend mit gespiegelten Labels trainiert wird und bei der Validierung vertauschte Seiten auftreten.

Wie es weitergeht

Als Nächstes entwerfen wir Keypoints für Objekte, die keine Personen sind, und lernen, wie OKS entscheidet, ob ein Keypoint richtig platziert ist.