CoMotion(Concurrent Multi-person 3D Motion) 是 Apple 于 2025 年发表在 ICLR 上的一种多人3D运动估计方法,能够从单目摄像头视频流中检测并追踪多人的详细3D姿态。该系统在拥挤场景中保持时间一致的预测,能够处理复杂姿态和遮挡情况。模型同时执行强逐帧检测和学习的姿态更新来逐帧追踪人物,而非跨时间匹配检测结果,从而实现在遮挡情况下的在线追踪。
论文:CoMotion: Concurrent Multi-person 3D Motion
作者:Alejandro Newell, Peiyun Hu, Lahav Lipson, Stephan R. Richter, Vladlen Koltun
主要能力:
依赖组件:
| 组件 | 说明 | 许可证 |
|---|---|---|
| ml-comotion | 主模型代码 | Apple Software License |
| chumpy | 自动微分库 | MIT License |
| aitviewer | 3D可视化渲染库 | MIT License |
本项目基于以下开源项目进行 NPU 适配修改:
ml-comotion — 主模型代码
chumpy — 自动微分库
aitviewer — 3D可视化渲染库
修改说明:适配华为昇腾 NPU 运行环境,定制适配代码下载后覆盖源码。
本项目基于原始开源代码进行了 NPU 适配修改,修改内容分为以下几类:
| 文件 | 修改类型 | 说明 |
|---|---|---|
demo.py | 修改 | 1) 设备选择从 CUDA 切换到 NPU(torch.device("npu:0"));2) 导入路径加 src. 前缀;3) 相机位置调整至原点;4) Billboard 距离从 100.0 调整为 10.0 |
src/comotion_demo/utils/dataloading.py | 修改 | 默认相机内参矩阵焦距从 2*max_res 调整为 1.05*max_res,适配 NPU 渲染场景 |
demo.sh | 新增 | 无头渲染启动脚本,使用 Xvfb + Mesa/swrast 软件渲染,支持无物理显示器的容器化/NPU 环境 |
requirements.txt | 新增 | 固定依赖版本列表,包含 torch-npu==2.5.1 等华为昇腾 NPU 依赖 |
| 文件 | 修改类型 | 说明 |
|---|---|---|
chumpy/api_compatibility.py | 修改 | 修复 global 变量 which_passed 的作用域声明问题,将 global 从 __main__ 块移到模块级别,解决 Python 兼容性问题 |
| 文件 | 修改类型 | 说明 |
|---|---|---|
setup.py | 修改 | 移除 usd-core 依赖;硬编码 PyQt6 替代 PyQt5;移除 Python < 3.11 版本上限 |
viewer.py | 修改 | 移除 USD 导出功能;PyQt5Window → PyQt6Window |
pyqt5_window.py | 修改 | PyQt5 → PyQt6 导入迁移 |
imgui_integration.py | 修改 | PyQt5 → PyQt6 导入迁移 |
smpl.py | 修改 | 使手部姿态参数可选,兼容基础 SMPL 模型(无手部参数时不报错) |
billboard.py | 修改 | 注释所有 USD(pxr)导入和调用 |
meshes.py | 修改 | 注释所有 USD(pxr)导入和调用 |
plane.py | 修改 | 注释所有 USD(pxr)导入和调用 |
light.py | 修改 | 注释所有 USD(pxr)导入和调用 |
node.py | 修改 | 注释所有 USD(pxr)导入和调用 |
usd.py | 修改 | 注释所有 USD(pxr)导入和调用 |
| 类别 | 解决的问题 |
|---|---|
| NPU 适配 | 将 PyTorch 后端从 CUDA 切换到华为昇腾 NPU |
| 无头渲染 | 使用 Xvfb + Mesa 软件渲染,支持无显示器的服务器环境 |
| 依赖精简 | 移除 usd-core(目标环境不可用),迁移 PyQt5 → PyQt6 |
| 模型兼容 | 修复 SMPL 基础模型(无手部参数)兼容性问题 |
| Python 版本 | 移除 Python < 3.11 限制,支持 Python 3.11.6 |
| Bug 修复 | 修复 chumpy 中 global 变量作用域问题 |
| 配套 | 版本 | 说明 |
|---|---|---|
| CANN | 8.2.0 | 华为昇腾计算框架 |
| Python | 3.11.6 | - |
| torch | 2.5.1 | PyTorch |
| torch_npu | 2.5.1 | 华为 NPU PyTorch 适配层 |
2.1.RC2-800I-A2-py311-openeuler24.03-lts(ARM 架构)git clone https://github.com/apple/ml-comotion.git
git clone https://github.com/mattloper/chumpy.git
git clone https://github.com/eth-ait/aitviewer.gitgit clone https://gitcode.com/Ascend-SACT/ml-comotion-npu.git将定制代码覆盖到对应的原始源码目录:
# 假设原始源码和 ml-comotion-npu 在同一父目录下
cp -rf ml-comotion-npu/ml-comotion/* ml-comotion/
cp -rf ml-comotion-npu/chumpy/* chumpy/
cp -rf ml-comotion-npu/aitviewer/* aitviewer/yum install qt6-qtbase-devel qt6-qttools-devel qt6-qtdeclarative-devel \
ffmpeg ffmpeg-devel xorg-x11-server-Xvfb mesa-dri-drivers mesa-vulkan-driverscd ml-comotion
pip install -r requirements.txt
cd ..cd chumpy
pip install -r requirements.txt
pip3 install .
cd ..PyQt6-6.7.1-1-cp38-abi3-manylinux_2_28_aarch64.whlpip install PyQt6-6.7.1-1-cp38-abi3-manylinux_2_28_aarch64.whlcd aitviewer
pip3 install .
cd ..| 文件名 | 下载地址 | 解压后存放路径 | 说明 |
|---|---|---|---|
demo_checkpoints.tar.gz | demo_checkpoints | ml-comotion/src/comotion_demo/data | 预训练权重(含检测和更新阶段) |
SMPL_python_v.1.1.0.zip | SMPL_python | ml-comotion/src/comotion_demo/data/smpl | 选择“Download version 1.1.0 for Python 2.7 (female/male/neutral, 300 shape PCs)”,将 basicmodel_neutral_lbs_10_207_0_v1.1.0.pkl 重命名为 SMPL_NEUTRAL.pkl 拷贝到存放路径 |
cd ml-comotion
bash demo.sh -i path/to/teaser_5s.mp4 -o results可选参数:
--start-frame:指定起始帧--num-frames:指定处理帧数--skip-visualization:跳过可视化渲染[root@pm-d12e0109 ml-comotion]# bash demo.sh -i path/to/teaser_5s.mp4 -o results
Running CoMotion: 0it [00:00, ?it/s]2026-03-21 14:51:51 - INFO - yield_image_from_video - Yielding 1000000000 frames from path/to/teaser_5s.mp4 (121.0 in total).
2026-03-21 14:51:51 - INFO - yield_image_from_video - Starting from frame 0
Running CoMotion: 121it [00:27, 4.44it/s]
2026-03-21 14:52:19 - INFO - visualize_poses - Rendering SMPL video: path/to/teaser_5s.mp4
2026-03-21 14:52:19 - INFO - yield_image_from_video - Yielding 1000000000 frames from path/to/teaser_5s.mp4 (121.0 in total).
2026-03-21 14:52:19 - INFO - yield_image_from_video - Starting from frame 0
2026-03-21 14:52:20 - INFO - get_window_cls - Attempting to load window class: moderngl_window.context.headless.Window
2026-03-21 14:52:20 - INFO - print_context_info - Context Version:
2026-03-21 14:52:20 - INFO - print_context_info - ModernGL: 5.12.0
2026-03-21 14:52:20 - INFO - print_context_info - vendor: Mesa
2026-03-21 14:52:20 - INFO - print_context_info - renderer: llvmpipe (LLVM 17.0.6, 128 bits)
2026-03-21 14:52:20 - INFO - print_context_info - version: 4.5 (Core Profile) Mesa 24.0.3
2026-03-21 14:52:20 - INFO - print_context_info - python: 3.11.6 (main, Feb 19 2025, 18:13:39) [GCC 12.3.1 (openEuler 12.3.1-38.oe2403)]
2026-03-21 14:52:20 - INFO - print_context_info - platform: linux
2026-03-21 14:52:20 - INFO - print_context_info - code: 450
2026-03-21 14:52:20 - INFO - _load_source - Loading: fragment_picking/frag_pick.glsl
2026-03-21 14:52:20 - INFO - _load_source - Loading: outline/outline_draw.glsl
2026-03-21 14:52:20 - INFO - _load_source - Loading: visualize.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/sphere_instanced.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/sphere_instanced_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/outline/outline_prepare.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/sphere_instanced_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/shadow_mapping/depth_only.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/sphere_instanced_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/fragment_picking/frag_map.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lines_instanced.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lines_instanced_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/outline/outline_prepare.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lines_instanced_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/shadow_mapping/depth_only.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lines_instanced_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/fragment_picking/frag_map.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: chessboard.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: simple_unlit.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/lit_with_edges.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: directional_lights.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/mesh_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/shadow_mapping/depth_only.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/mesh_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/outline/outline_prepare.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/mesh_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/fragment_picking/frag_map.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: screen_texture.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/mesh_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/outline/outline_prepare.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/mesh_positions.vs.glsl
2026-03-21 14:52:22 - INFO - _load_shader - Loading: /usr/local/lib/python3.11/site-packages/aitviewer/shaders/fragment_picking/frag_map.fs.glsl
2026-03-21 14:52:22 - INFO - _load_source - Loading: clipping.glsl
Rendering frames: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 121/121 [00:27<00:00, 4.47it/s]
Video saved to /data01/ml/ml-comotion/results/teaser_5s.mp4
[INFO] Total time: 95 seconds.
[root@pm-d12e0109 ml-comotion]#results/teaser_5s.mp4results/*.ptresults/*.txt修改 demo.sh 的 -i 参数:
bash demo.sh -i path/to/your_video.mp4 -o resultsbash demo.sh -i path/to/image.jpg -o resultsbash demo.sh -i path/to/video.mp4 -o results --skip-visualization本项目基于以下开源项目开发:
如果本工作对您有帮助,请引用原始论文:
@inproceedings{newell2025comotion,
title = {CoMotion: Concurrent Multi-person 3D Motion},
author = {Alejandro Newell and Peiyun Hu and Lahav Lipson and Stephan R. Richter and Vladlen Koltun},
booktitle = {International Conference on Learning Representations},
year = {2025},
url = {https://openreview.net/forum?id=qKu6KWPgxt},
}本项目的代码和模型受多个许可证约束,使用前请仔细阅读:
Apple Machine Learning Research Model is licensed under the Apple Machine Learning Research Model License Agreement.