Стаття · · 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» з машиночитною причиною. На корпусі свіжих реальних кліпів вона жодного разу не видала число там, де сигналу не було. Для тренера відмова корисна, а впевнене неправильне число — ні.
Що я сказав би кожному, хто будує на моделях пози
- Виміряйте, що модель повертає на найважчому випадку, перш ніж будувати поверх неї.
- Шукайте величину, яку модель дає правильно, навіть якщо це не та, яку ви хотіли.
- Перевіряйте на еталоні, а не на своїх очікуваннях, і робіть відмову повноцінним результатом.