vid2model конвертирует движение человека из видео в скелетную анимацию и помогает ретаргетить её на VRM-модели.
Проект состоит из двух частей:
- Python CLI-пайплайн для извлечения motion из видео и экспорта в
BVH,JSON,CSV,NPZ,TRC - локальный browser viewer для просмотра
BVH, ретаргета наVRM/.glbи калибровки rig profiles
- извлекать pose sequence из видео через MediaPipe
- чинить пропуски, side-swaps и шумные участки motion
- стабилизировать foot contact, pelvis/root motion и leg IK
- адаптивно сглаживать motion без потери резких акцентов
- анализировать loopability и при необходимости выделять loop
- ретаргетить результат на VRM в viewer
- сохранять, валидировать, экспортировать и переиспользовать rig profiles
- писать diagnostic JSON с quality summary и before/after cleanup metrics
MediaPipe (быстро, без GPU):
cd /Users/fedor/projects/personal/videoToModel/vid2model
./convert.sh think.mp4 output/think.bvh
python3 -m http.server 80804D-Humans / HMR2.0 (нейронка, точнее):
./setup_smpl_backend.sh # первый раз: ~2GB, только один раз
./convert_video_smpl.sh think.mp4 output/think.bvh
python3 -m http.server 8080После этого открой:
http://localhost:8080/viewer/index.html
- Сконвертировать видео в
BVHи diagnostic JSON. - Проверить quality summary и cleanup evaluation.
- Открыть
viewer/index.html. - Загрузить
BVH. - Загрузить
VRMилиGLBмодель. - Запустить retarget.
- Если результат хороший, нажать
Validate Profile. - При необходимости экспортировать и зарегистрировать rig profile в репозитории.
Более точный результат за счёт SMPL body model и нейронного pose estimator.
Первый раз — настройка (нужен Python 3.10, скачает ~2GB):
./setup_smpl_backend.shЗапуск:
./convert_video_smpl.sh think.mp4 output/think.bvhС ретаргетом на VRM сразу:
./convert_video_smpl.sh think.mp4 output/think.bvh --vrm viewer/models/MoonGirl.vrm output/think.vrmСхема: Video → SMPL params (нейронка) → BVH → (опционально VRM)
4D-Humans не устанавливается (ошибка chumpy в pip):
setup_smpl_backend.sh пытается поставить chumpy из git, но он сломан на Python 3.10+. Скрипт обрабатывает эту ошибку, но fallback не устанавливает сам hmr2. Фикс:
git clone --filter=blob:none https://github.com/shubham-goel/4D-Humans.git /tmp/4d-humans
sed -i '' "/'chumpy/d" /tmp/4d-humans/setup.py
.venv-smpl/bin/pip install /tmp/4d-humansomegaconf не установлен — ставим вручную:
.venv-smpl/bin/pip install omegaconfPyTorch 2.6+ ломает загрузку чекпоинта (weights_only=True по умолчанию) — уже пропатчено в extract_smpl_from_video.py, ничего делать не нужно.
./image_to_bvh.sh poklon.jpg output/poklon.bvh 2Скрипт:
- Конвертирует JPG в видео (ffmpeg)
- Запускает pose detection
- Генерирует BVH со статической позой
Результат: 2-секундная анимация с одной повторяющейся позой.
./extract_bvh_frame.sh ted.bvh poklon.bvh -1 2Аргументы:
ted.bvh— исходная анимацияpoklon.bvh— выходной файл-1— последний кадр (или номер кадра: 0, 1, 120, etc.)2— длительность в секундах
Пример: извлечь финальную фазу поклона из видео, где он начинается на кадре 1000:
# Сначала посмотрите сколько кадров: grep "^Frames:" ted.bvh
# Извлеките финальный кадр
./extract_bvh_frame.sh ted.bvh poklon_final.bvh -1 3Простой запуск:
./convert.sh think.mp4 output/think.bvhВсе основные форматы сразу:
./convert.sh \
think.mp4 \
output/think.bvh \
output/think.json \
output/think.csv \
output/think.npz \
output/think.trcconvert.sh автоматически:
- создаёт
.venv, если её ещё нет - обновляет
pip - ставит зависимости из
requirements.txt
Если OpenCV неправильно определяет frame rate (например, видео 60fps генерирует BVH в 2x медленнее), используйте convert_auto_fps.sh:
./convert_auto_fps.sh think.mp4 output/think.bvhСкрипт автоматически:
- детектирует FPS из метаданных видео (ffprobe)
- передаёт его в
convert.sh - генерирует BVH с правильной длительностью
Дополнительные форматы:
./convert_auto_fps.sh think.mp4 output/think.bvh --all --fbxИли вручную через флаг:
OVERRIDE_FPS=60 ./convert.sh think.mp4 output/think.bvhПолезно если автодетекция не сработала:
# Проверить FPS видео
ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 video.mp4
# Использовать явно
OVERRIDE_FPS=60 ./convert.sh video.mp4 output/video.bvhПример с quality diagnostics:
python3 convert_video_to_bvh.py \
--preset walk \
--input think.mp4 \
--output-bvh output/think.bvh \
--output-diag-json output/think.diag.jsonПример для более сложного движения:
python3 convert_video_to_bvh.py \
--preset dance \
--input think.mp4 \
--output-bvh output/think.bvh \
--output-diag-json output/think.diag.jsonПолный пример:
python3 convert_video_to_bvh.py \
--input think.mp4 \
--output-bvh output/think.bvh \
--output-json output/think.json \
--output-csv output/think.csv \
--output-npz output/think.npz \
--output-trc output/think.trc \
--output-diag-json output/think.diag.jsonПолезные флаги:
--preset {idle,walk,run,dance}: baseline-настройки под тип движения--output-diag-json: расширенный diagnostic JSON--loop-mode {off,auto,force}: loop detection/extraction--opencv-enhance {off,light,strong}: preprocessing перед pose detection--roi-crop {off,auto}: adaptive crop вокруг человека--max-gap-interpolate: сколько кадров подряд можно интерполировать--skeleton-profile-json: override rest offsets под конкретную модель--hand-tracking {off,auto}: real finger landmark tracking (21 points per hand instead of synthetic)
По умолчанию пайплайн захватывает пальцы синтетически — из 3 кончиков пальцев (index, middle, pinky). Это быстро, но поверхностно.
С флагом --hand-tracking auto используется полный 21-point MediaPipe Hand для каждой руки, что даёт реальные суставы всех пальцев:
# С реальным захватом пальцев
./convert.sh think.mp4 output/think.bvh --hand-tracking auto
# Или через CLI напрямую
python3 convert_video_to_bvh.py \
--input think.mp4 \
--output-bvh output/think.bvh \
--hand-tracking autoРезультат: пальцы двигаются так, как в видео. BVH включает все 32 палец-кости (16 на руку) с реальными ротациями, не синтезированными.
Компромисс: --hand-tracking auto примерно в 1.5x медленнее, чем по умолчанию, так как запускает дополнительный MediaPipe детектор. Синтетический режим остаётся default.
В проекте есть motion presets:
idlewalkrundance
Они меняют baseline для detection и cleanup. Практически:
idleполезен для спокойной речи, жестов, стоячих позwalkподходит для обычной циклической ходьбыrunдаёт более жёсткие параметры под быстрые ногиdanceменьше давит выразительное движение и отключает auto-loop по умолчанию
См. пример конфига: config.example.yaml
Для разнообразия жестов рук доступен датасет Slovo — 20,400 видеороликов русских жестов (20 samples × 1000 жестов, в том числе приветствия).
Что скачать из Slovo:
-
Metadata (нужно всегда):
annotations.csv— таблица с gesture labels, frame ranges, train/test split, размерами видео
-
Видео (для Phase 2 — Slovo ingestion):
- Trimmed videos (~16GB) — видео уже обрезаны по жестам (рекомендуется для начала)
- ИЛИ 360p resized (~13GB) — более компактная версия
- Ссылка: Slovo GitHub
-
Hand landmarks (для Phase 3 — оптимизация):
- ~1.2GB pickle-файлов с pre-computed MediaPipe Hand landmarks
- Избегает пере-запуска MediaPipe на каждое видео
Путь использования (Phase 2):
# Скачать и распаковать
mkdir -p data/slovo
# Распаковать annotations.csv и видео в data/slovo/
# Обработать приветствия с real finger tracking
python3 tools/slovo_ingest.py \
--annotations data/slovo/annotations.csv \
--videos-dir data/slovo/videos \
--gesture "Привет" \
--output-dir output/slovo_greetings/ \
--hand-tracking autoResult: BVH-клипы с живой анимацией рук из настоящих жестов, готовые к ретаргету на VRM.
--output-diag-json пишет расширенный JSON с несколькими блоками:
input: сколько кадров найдено, сколько интерполировано, какой backend использовалсяcleanup: что именно делал cleanupevaluation: before/after метрики после cleanuproot_yaw: нормализация yaw и дополнительные rotation transformsloop: pre-cleanup loopability, итоговое loop detection и extractionquality: итоговый score и пользовательские флаги качества
Сейчас в quality есть:
scoreratingtracking_okfoot_contact_okloop_candidateretarget_riskreasons
Сейчас в evaluation есть before/after сравнение по:
root_position_jitterroot_height_jitterleft_foot_contact_spreadright_foot_contact_spreadleft_wrist_motion_energyright_wrist_motion_energy
Это удобно для регрессионного контроля: видно не только итоговую оценку, но и что именно cleanup улучшил или ухудшил.
Viewer живёт в viewer/index.html.
Запуск:
python3 -m http.server 8080Открыть:
http://localhost:8080/viewer/index.html
Что умеет viewer:
- загрузка локального
BVH - загрузка
VRMиGLBмоделей Auto Setupдля обычного сценария: взять лучший доступный profile/seed и сразу наложить анимацию на модельSave Model Setupдля обычного сценария: сохранить удачную настройку модели локально без ручного разбора rig-profile flow- retarget source animation на модель
Export Model Analysisдля выгрузки параметров модели без исходной анимации- локальное сохранение
draftrig profile после удачного retarget Validate Profileдля фиксации проверенного профиляExport Profile/Import Profile- автозагрузка repo-backed rig profiles
- базовые viewer controls: play/pause/stop, zoom, scrub, reset camera
Подробности по retarget path и runtime helpers: viewer/RETARGET_NOTES.md
Python-side карта стадий до viewer-retarget: docs/python-source-pipeline-analysis.md
Viewer-side карта retarget, rig-profile priority и model-fit hooks: docs/viewer-retarget-analysis.md
Сводка гипотез и следующих шагов по skeleton-to-model mismatch: docs/mismatch-hypotheses-and-next-steps.md
План рефакторинга viewer/js/modules без изменения поведения: docs/viewer-modules-refactor-plan.md
Для автоматической проверки BVH + GLB/VRM без браузера есть headless runner:
- reusable runtime: viewer/js/modules/headless-retarget-validation.js
- CLI entrypoint: tools/headless_retarget_validation.mjs
Он переиспользует viewer-side retarget path, rig-profile resolution, calibration и runtime diagnostics, но запускается в Node. Для bare imports используются тонкие локальные ESM bridge-пакеты в node_modules, которые просто реэкспортируют bundled vendor-копии three и @pixiv/three-vrm из viewer/vendor.
Пример:
node tools/headless_retarget_validation.mjs \
--model viewer/models/low_poly_humanoid_robot.glb \
--bvh output/think.bvh \
--stage body \
--prettyС записью результата в файл:
node tools/headless_retarget_validation.mjs \
--model viewer/models/MoonGirl.vrm \
--bvh output/think.bvh \
--stage full \
--out output/headless-retarget.json \
--prettyCLI печатает machine-readable JSON со стабильным верхнеуровневым контрактом:
input: stage и исходные путиmodel: fingerprint, VRM metadata и список костей skinned meshsource: summary поBVHrigProfile: какой profile реально был выбранmapping: matched pairs, topology fallback и mirrored-side decisionsselection: выбранный retarget attempt, mode, root yaw и pose-error probediagnostics: viewer-like events, debug state и calibration summary
Это удобно для CI/regression-проверок, когда нужно сравнить headless retarget decisions с браузерным viewer flow без ручного открытия viewer/index.html.
Для повторяемой проверки проблемных сценариев есть единый runner:
python3 tools/run_regression_checks.pyЧто он покрывает сейчас:
source_pipeline_diagnostics: source-stage diagnostics иquality.retarget_riskдля проблем в cleanup/finalize pathroot_yaw_contract: viewer-политику вокругretarget-root-yaw, чтобы clip, уже центрированный Python-экспортом, не получал лишний large flipatypical_model_mapping: выбор canonical bone для нетипичных rig'ов, где helper/socket/end кости не должны выигрывать у основной костиheadless_retarget_validation: machine-readable headless retarget contract дляBVH + GLB/VRMвне browser viewer
Полезные режимы:
python3 tools/run_regression_checks.py --list
python3 tools/run_regression_checks.py --scenario root_yaw_contract
python3 tools/run_regression_checks.py --scenario atypical_model_mapping --dry-runRig profile описывает, как конкретная модель лучше ретаргетится:
- mapping target bone -> source bone
- preferred retarget mode
- limb calibration flags
- yaw / scale / rotation adjustments
- cached calibration data
Внутри viewer есть несколько состояний профиля:
draft: автосохранён после удачного retarget, но ещё не подтверждёнvalidated: профиль проверен вручную и должен использоваться приоритетно
Приоритет загрузки:
- local validated
- repo validated
- local draft
- built-in fallback
Если анимации ещё нет, но нужно собрать параметры модели, viewer теперь умеет экспортировать model-analysis.json.
Он содержит:
modelFingerprint- humanoid mapping
- иерархию костей
- local bind pose
- primary child directions
- segment lengths
- torso/arm/leg proportions
- foot hints
Это не готовый rig profile, но хороший seed для будущей автоматической калибровки.
Если для модели ещё нет сохранённого profile, viewer теперь может использовать такой seed автоматически как in-memory fallback по modelFingerprint.
Для большинства случаев теперь достаточно такого порядка:
- Загрузить
BVH - Загрузить
VRM/GLB - Нажать
Auto Setup - Если результат хороший, нажать
Save Model Setup
Advanced-кнопки Validate Profile, Export Profile, Import Profile и Export Model Analysis остаются для отладки, обмена профилями и repo-backed workflow.
Если profile уже проверен:
- Нажми
Validate Profile - Нажми
Export Profile - Зарегистрируй JSON в репозитории:
python3 tools/register_rig_profile.py --input /path/to/exported.rig-profile.jsonСкрипт:
- копирует JSON в
viewer/rig-profiles/ - обновляет
viewer/rig-profiles/index.json - заменяет старую запись для того же
modelFingerprint + stage
После экспорта viewer ещё и печатает готовую register-команду в console log.
Отдельная документация по формату и repo manifest: viewer/rig-profiles/README.md
Repo-shared profiles лежат в:
Viewer автоматически подхватывает их по modelFingerprint.
Если нужен FBX через Blender CLI:
./bvh_to_fbx.sh output/think.bvh output/think.fbxЕсли Blender не в PATH:
BLENDER_BIN=/Applications/Blender.app/Contents/MacOS/Blender ./bvh_to_fbx.sh output/think.bvh output/think.fbxЕсли хочешь обучать auto-mode, рабочий цикл такой:
- собрать JSONL-датасет
- обучить
auto_pose_model.npz - подключить модель через config
- запускать конвертацию с
pose_corrections.mode = auto
Сборка датасета:
python3 tools/generate_auto_pose_dataset.py \
--input think.mp4 \
--label default \
--output output/auto_pose_dataset.jsonlОбучение:
python3 tools/train_auto_pose_model.py \
--input output/auto_pose_dataset.jsonl \
--output models/auto_pose_model.npzКлючевые модули в vid2model_lib:
pipeline.py: публичный orchestration facadepipeline_video_scan.py: чтение видео и detector/ROI logicpipeline_gap_fill.py: заполнение пропусковpipeline_cleanup.py: smoothing, foot contacts, pelvis/root stabilization, leg IKpipeline_auto_pose.py: presets, features, classifier integrationpipeline_retarget.py: canonicalization и pose correctionspipeline_channels.py: solving motion channelspipeline_motion_transforms.py: root yaw и rotation cleanuppipeline_loop.py: loop analysis / extraction / blendpipeline_rest_offsets.py: rest offsets и skeleton profile overridespipeline_mirror.py: mirror / side-swap heuristics
- Python
3.10+ pip- Blender, если нужен
FBX
Проверка toolchain:
python3 convert_video_to_bvh.py --check-tools.venv/bin/python -m unittest discover -s tests -p 'test_*.py' -v