Стаття · · 7 хв читання

Як порахувати оберти стрибка у фігурному катанні з одного відео з телефона

Чому моделі пози ламаються на швидкому обертанні і як ширина плечей та стегон у кадрі дає кількість обертів, що збіглася з людським рахунком у 93,3% кліпів із мокапом.

Тренер знімає стрибок на телефон і хоче одне число: скільки обертів. Звучить як найпростіша частина задачі. Насправді виявилось найскладнішою, і рішення прийшло з даних, а не з моделі.

Що насправді є у відео

Стрибок триває близько пів секунди. На 30 кадрах за секунду це приблизно 15 кадрів у повітрі, а при п'яти обертах на секунду один оберт — це близько шести кадрів. Телефони пишуть зі змінною частотою кадрів, сильно стискають відео, а кліп часто ще й переслали через Telegram. Кожне число — на межі того, що є в пікселях.

Чому очевидний підхід не працює

Очевидний підхід — запустити модель пози, взяти лінію між плечима й порахувати, скільки разів вона повернулась. Я виміряв, що модель пози насправді повертає на швидкому обертанні: справжній поворот плечей — близько 69° за кадр, а поза каже близько 2° за кадр. Модель «галюцинує» тіло анфас, бо саме таке найчастіше бачила під час навчання. Тому не працює ні розгортання азимута, ні модель, навчена передбачати орієнтацію: обидва стартують з неправильних кутів.

Сигнал, що виживає

Кути неправильні, а відстані — ні. Ширина тіла в кадрі, відстань у пікселях між плечима й між стегнами, чесно пульсує, коли фігурист обертається: широка, коли тіло дивиться в камеру, вузька, коли боком. В одному кліпі вона йшла 32 → 8 → 32 пікселі. Ширина пульсує з подвоєною частотою обертання, бо тіло виглядає вузьким двічі за оберт.

  • Підібрати гармонічну модель ширини на сітці можливих швидкостей обертання.
  • Обрати швидкість, яка найкраще пояснює пульсацію.
  • Запустити пермутаційний тест: перемішати кадри й перевірити, що підгонка значно краща за випадкову. Якщо ні — сигналу обертання немає, і система так і каже.
# спрощено: оцінюємо кожну швидкість тим, наскільки гармоніка пояснює ширину
for speed in speeds:                 # обертів за секунду
    phase = 2 * pi * 2 * speed * t   # ширина пульсує двічі за оберт
    fit = least_squares(width, [cos(phase), sin(phase), 1])
    score[speed] = explained_variance(fit)
best = argmax(score)
p_value = permutation_test(width, best)  # перемішані кадри як нульова гіпотеза

Як я знаю, що це працює

Я перевірив метод на 3D-мокапі з дослідницького датасету FS-Jump3D, де справжні оберти беруться з розгортання лінії стегон у 3D. На всіх 216 кліпах у режимі 30 fps метод виміряв 189 з медіанною похибкою 0,04 оберту; 180 із 189 — у межах чверті оберту, а округлений рахунок збігся з людським у 93,3% випадків. Де сигналу не було, він нічого не повертав замість вигадки.

Говорити «не знаю» навмисно

Кожне значення у звіті має інтервал 68%, рівень і статус. Коли система не може щось виміряти — наприклад, сім обертів на секунду при 30 fps роблять рахунок неоднозначним — вона повертає «absent» з машиночитною причиною. На корпусі свіжих реальних кліпів вона жодного разу не видала число там, де сигналу не було. Для тренера відмова корисна, а впевнене неправильне число — ні.

Що я сказав би кожному, хто будує на моделях пози

  • Виміряйте, що модель повертає на найважчому випадку, перш ніж будувати поверх неї.
  • Шукайте величину, яку модель дає правильно, навіть якщо це не та, яку ви хотіли.
  • Перевіряйте на еталоні, а не на своїх очікуваннях, і робіть відмову повноцінним результатом.

Проєкт, з якого ця стаття: jumpsight →

Схожа задача?

Напишіть, що ви будуєте і які дані маєте. Я відповім, як би це вирішував.

Обговорити проєкт →