Ultralytics YOLO27: Встать в лист ожидания.
Get Started
Уроксредний

Разметка и обучение моделей поз

Создавай разметку ключевых точек с указанием видимости, правильно задавай kpt_shape и flip_idx, обучайся на COCO8-pose и преобразуй ключевые точки в углы суставов с порогом уверенности.

Оценка позы представляет каждого человека как 17 пронумерованных точек. По этим точкам вычисляются показатели, на которых строятся продукты: углы локтя для эргономики, углы колена для реабилитации, высота таза для обнаружения падений. Два ключа набора данных определяют, можно ли доверять этим точкам. Ошибка в любом из них не вызовет сбой — просто модель будет путать левую и правую стороны или незаметно обучится без самой дешёвой аугментации.

Результат

Обучи yolo26n-pose.pt на coco8-pose.yaml и вычисли углы левого и правого локтя каждого человека по result.keypoints, пропуская суставы, в которых модель не уверена.

Ускоренное прохождение
Если ты уже освоился, вот краткая версия.
  1. Строка разметки: класс, рамка (4 значения), затем x y v для каждой ключевой точки; все значения нормализованы. v — это 0 (не размечена), 1 (закрыта) или 2 (видна).

  2. Задай kpt_shape: [K, 3] и flip_idx, который меняет местами все пары левых и правых точек.

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

  4. Считывай result.keypoints.xy и .conf; пропускай вычисления, если уверенность в суставах ниже порогового значения.

Практические занятия

Строка разметки ключевых точек#

Оценка позы Ultralytics YOLO для трёх бегунов: у каждого человека есть рамка и скелет тела из 17 ключевых точек

Строка разметки позы — это строка обнаружения с добавленными ключевыми точками. Каждая координата нормализована в диапазоне 0–1, а ключевые точки в каждой строке идут в одном и том же фиксированном порядке. Пример реальной строки COCO8-pose, сокращённой после четвёртой ключевой точки:

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 ...
ЗначенияЗначение
0индекс класса (человек)
0.671279 0.617945 0.645759 0.726859центр рамки по x, центр по y, ширина, высота
0.519751 0.381250 2ключевая точка 0 (нос): x, y, видимость
…ещё 16 ключевых точек в том же формате: 5 + 17 × 3 = 56 значений в каждой строке

Флаг видимости соответствует соглашению COCO: 2 — видна, 1 — размечена, но закрыта, 0 — не размечена. Ultralytics маскирует ключевые точки со значением v = 0 при вычислении функции потерь, поэтому отсутствующее запястье не учит модель предсказывать запястья в точке (0, 0).

Редактор аннотаций Ultralytics Platform на изображении COCO8-pose: на людях, разрезающих торт, нарисованы скелеты из 17 ключевых точек

Размечай скрытые суставы, положение которых можно определить

Используй 1 для скрытого сустава, положение которого можно уверенно определить: например, бедра за столом или запястья за спиной; такая точка всё равно участвует в обучении. Оставляй 0 для суставов, положение которых невозможно определить. Если присваивать 0 каждой скрытой точке, модель лишится именно тех сложных примеров, которые ей нужны.

В руководстве по наборам данных поз также описан вариант с двумя значениями (x y only, kpt_shape: [K, 2]) для наборов данных без информации о видимости.

kpt_shape и flip_idx#

В YAML набора данных к обычным path, train, val и 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]

Порядок 17 ключевых точек COCO на стоящем человеке: номера от 0 (нос) до 16 (правая лодыжка)

flip_idx указывает аугментации с горизонтальным отражением, в какую ключевую точку переходит каждая точка в зеркальном изображении. При отражении человека его левое запястье (9) оказывается там, где было правое запястье (10), поэтому в позиции 9 массива flip_idx хранится 10, а в позиции 10 — 9; нос (0) соответствует самому себе. При каждой аугментации скелет перемещается вместе с пикселями, а отражение — единственная аугментация, для которой также нужна таблица соответствия индексов:

Аугментации позы одного бегуна: исходное изображение, отражение по горизонтали, поворот, масштабирование, цвет HSV и мозаика; скелет ключевых точек следует за каждым преобразованием

Что происходит, если flip_idx задан неверно, как подтверждает проверка установленного исходного кода:

  • Отсутствует: во время обучения выводится предупреждение, а fliplr и flipud устанавливаются в 0, поэтому ты теряешь самую дешёвую аугментацию.
  • Неверная длина: обучение останавливается с ValueError, указывающим на несоответствие, — это единственный случай с явной ошибкой.
  • Длина верная, пары неверные: предупреждений нет. На половине отражённых примеров модель усваивает, что левая сторона — это правая, а на изображениях для валидации появляются перестановки левой и правой сторон симметричных поз.

Обучи модель на COCO8-pose#

Мозаика обучения COCO8-pose: люди на мотоцикле, под розовым зонтом, в скейт-парке и верхом на лошади; у каждого есть рамка человека и цветной скелет ключевых точек

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

Как и в сегментации, таблица состоит из двух блоков. Box оценивает рамки людей, а Pose — расположение ключевых точек с помощью сходства ключевых точек объекта (OKS) в рамках того же механизма mAP. Pose mAP50-95 — критерий выпуска продукта для оценки позы: в следующем уроке показано, как OKS определяет, верно ли расположена ключевая точка.

От ключевых точек к углам суставов#

result.keypoints содержит xy (N × K × 2, пиксели), xyn (нормализованные координаты) и conf (N × K) в указанном выше порядке COCO. Угол в суставе — это угол между двумя векторами конечностей, которые в нём сходятся, — его можно вычислить через скалярное произведение:

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

Разберём по строкам: kpts.xy[p] — это 17 точек человека p в пикселях; a - b и c - b — векторы плеча и предплечья, направленные от локтя; их нормализованное скалярное произведение — косинус угла между ними. У прямой руки угол близок к 180°, у полностью согнутой — к 30°. У людей 3 и 4 как минимум один сустав левой руки имеет уверенность ниже 0.5, поэтому скрипт не измеряет их.

Проверяй уверенность для каждого сустава

Симптом: кажущиеся надёжными углы для людей, чьи руки находятся за пределами кадра. Причина: модель возвращает координаты каждой ключевой точки вне зависимости от того, видна ли она. Решение: пропускай расчёты, для которых уверенность по суставам ниже минимального порога (здесь это 0.5), и записывай количество пропусков в журнал: его рост — ранний признак изменения положения камеры или освещения.

Попробовать

Обучи модель одну эпоху на coco8-pose.yaml и запиши mAP50-95 для рамок и позы. Затем дополни pose.py, чтобы также выводить угол правого локтя (ключевые точки 6, 8, 10), и перечисли людей на изображении автобуса, у которых можно измерить обе руки.

Критерии готовности
Урок считается завершённым, если выполнены все условия ниже.
  • Обучение завершено, показатели mAP50-95 для рамок и позы записаны.

  • Твой скрипт выводит углы обоих локтей для каждого человека, пропуская руки, уверенность для которых ниже установленного порога.

  • Ты можешь объяснить, что происходит, если flip_idx отсутствует, имеет неверную длину или содержит неверные пары.

Показать решение
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

У людей 0 и 2 можно измерить обе руки. Уверенность для правой руки человека 1 и обеих рук людей 3 и 4 ниже порога 0.5, поэтому скрипт пропускает их, а не пытается угадать.

Если flip_idx отсутствует, аугментация отражением отключается с предупреждением; неверная длина останавливает обучение с ValueError; корректно выглядящий flip_idx с неверными парами приводит к тому, что обучение без предупреждений использует отражённые метки, а на валидации проявляются перестановки левой и правой сторон.

Что дальше

Далее мы спроектируем ключевые точки для объектов, которые не являются людьми, и узнаем, как OKS определяет, верно ли расположена ключевая точка.

Войди, чтобы сохранять прогресс