ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

VideoPose3D实战:从零搭建环境到跑通自己的视频,实现3D人体姿态估计

VideoPose3D实战:从零搭建环境到跑通自己的视频,实现3D人体姿态估计 写这篇东西之前我先说句大实话第一次跑通 VideoPose3D、在屏幕里看到自己随便拍的视频被自动转成一套会动的3D骨架时那种感觉跟当年第一次让程序输出“Hello World”完全不一样——前者是“程序活了”后者是“视觉技术真的能读懂人”。这个项目我前前后后折腾了小一周中间踩过不少坑有些是环境层面的有些是模型理解层面的。今天把整个从零搭建环境到跑通自己视频的流程完整梳理一遍希望能让你绕开我走岔的那些路。VideoPose3D 是 Facebook AI Research 发布的一个 3D 人体姿态估计模型核心思路很有意思它不做端到端的视频直接回归而是先靠 2D 姿态检测器从画面里提取每个关节的二维坐标再送入一个基于时序卷积网络的模型利用连续多帧的时序信息把这些 2D 坐标“抬升”成 3D 坐标。它的优势在于不需要昂贵的动捕设备只要一段普通 RGB 视频就能得到相对稳定的3D姿态序列。这篇文章适合有 PyTorch 基础、想跑通完整流程、并且想让模型处理自己拍摄视频的读者参考。1. 先搞清楚 VideoPose3D 在做什么2D检测 时序卷积的抬升逻辑我第一次接触这个项目时有个误区以为 VideoPose3D 会直接吃视频帧、吐出3D骨架。其实它的完整推理链路是分阶段的先是 2D 关键点检测然后才是 VideoPose3D 模型负责的 3D 抬升部分。理解这条链路比瞎跑脚本重要得多因为后边所有参数调优、报错排查都建立在这个理解之上。1.1 为什么要拆成“2D检测”和“3D抬升”两段3D姿态估计大体上分两条路线一种是端到端模型直接从图像回归3D坐标代表如 VIBE、MEVA 这类另一种就是 VideoPose3D 这种两段式——先用成熟的 2D 检测器拿到足够准的关节点再用时序模型预测深度维度。两段式的核心逻辑是2D关键点检测已经被 Detectron2、HRNet 这些做得非常成熟了在有足够数据支撑下精度相当高而“从2D坐标推测3D坐标”本质上是一个深度模糊问题单张图像信息不够但一旦引入连续多帧人体运动的时序一致性就为深度估计提供了强约束。VideoPose3D 用的时序卷积网络TCN正是干这个的它沿时间维度滑动卷积捕捉关节轨迹的时空特征从而把每帧的 2D 位置映射成稳定的 3D 坐标。1.2 模型理解反卷积结构与时序感受野VideoPose3D 的骨干不是 Transformer也不是 LSTM而是带残差连接的一维时序卷积网络。它把同一个关节在不同帧上的坐标变化看作一个时间序列使用多层空洞卷积dilated convolution扩大感受野。简单说一帧里的深度信息可能置信度低但把它前后的 2030 帧连起来看这个关节是往前走还是往后走、是做弧线还是直线就能猜得很准。这里有一个关键参数叫 receptive field感受野在推理脚本里体现在--num-poses或模型配置中的causal设置上。非因果卷积能看到未来帧精度高但有延迟因果卷积只用过去帧推断当前帧适合实时场景。做离线视频制作时推荐用非因果模式3D抖动会小很多。1.3 这套方案能做什么不能做什么能做的单人出镜的视频、健身动作分析、舞蹈姿态提取、步态动画数据生成甚至可以直接输出带有深度的骨骼动画导入 Blender 这类三维软件。不能做的多人互相遮挡严重的场景、快速运动导致运动模糊严重的镜头、视角过于刁钻比如正头顶俯拍的画面。这本质上受限于 2D 检测器的能力上限和时序模型的物理约束别指望它是万能的。2. 环境搭建的具体步骤与版本细节从零开始跑通官方代码这个项目的环境搭建算中等难度比纯 PyTorch 图像分类稍麻烦一点难点在于 Detectron2 的编译依赖比较多。我按“基础环境 - 项目依赖 - 验证安装”三步走尽量把每个环节的版本选择原因说清楚避免你只能抄命令却不知道在装什么。2.1 创建独立的 Python 虚拟环境不管你是 Ubuntu 还是 Windows都建议用虚拟环境隔离项目依赖避免把系统的 Python 环境搞乱。我用的是 conda你也可以用 venv原理一样conda create -n vp3d python3.8 conda activate vp3dPython 版本我推荐 3.8。这个项目官方 README 的年代比较早PyTorch 当时还是 1.x 时代虽然新版 Python 理论上也能跑但部分依赖包尤其是 Detectron2在 3.10 上编译容易碰到 OpenCV 和 numpy 的接口兼容问题。为了省时间直接用 3.8 最稳。2.2 安装 PyTorch 与 CUDA 版的匹配问题这一步是环境搭建里最容易出错的地方我相信你也经历过“pip install torch 成功但 import 报错或者GPU 用不上默默跑 CPU”的情况。建议确认你机器的显卡驱动支持的最高 CUDA 版本再装对应的 PyTorch。我的机器是 RTX 3060驱动支持 CUDA 11.8所以我装的是pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu118为什么不用更新的 PyTorch 2.x因为 VideoPose3D 的官方推理代码依赖了torch.utils.bottleneck之类的旧模块新版本虽然也能跑但更稳妥的选择是 PyTorch 1.x。实测下来 1.13.1 配合 CUDA 11.8 没有任何问题。验证方式python -c import torch; print(torch.__version__, torch.cuda.is_available())输出应该是1.13.1 True。这一步如果显示 False说明 PyTorch 装成了 CPU 版需要重新安装对应 CUDA 的 wheel。2.3 拉取 VideoPose3D 项目源码并安装依赖官方仓库有两个重要分支主分支和master早期版。推荐直接拉主分支git clone https://github.com/facebookresearch/VideoPose3D.git cd VideoPose3D项目依赖的核心库有这些numpy、opencv-python、tqdm、scipy、matplotlib以及ffmpeg用于视频抽帧。安装命令pip install numpy opencv-python tqdm scipy matplotlib ffmpeg-python2.4 安装 Detectron22D关键点的执行引擎前边说了VideoPose3D 自己不负责 2D 检测需要借助 Detectron2 或 HRNet 从视频帧里提取 2D 关节坐标。我选择的是 Detectron2因为它和 Facebook 生态集成度最高官方也提供了配套的检测配置。Detectron2 的安装方式有官方预编译 wheel但和 PyTorch 版本强绑定老老实实从源码编译最保险pip install -e githttps://github.com/facebookresearch/detectron2.git这个过程会编译一些 C/CUDA 扩展耗时大概十分钟。期间最常遇到的问题是缺依赖比如ninjapip install ninja如果编译过程中报gcc版本过旧装上 build-essential 就好。2.5 下载预训练权重和测试样例VideoPose3D 官方提供了多个预训练模型最常用的是在 Human3.6M 数据集上训练的mkdir -p checkpoints wget https://dl.fbaipublicfiles.com/video-pose-3d/pretrained_h36m_detectron_coco.bin -O checkpoints/pretrained_h36m_detectron_coco.bin下载完可以先用单张图片测试推理链路是否通畅。官方仓库的inference.py支持--video-file参数直接用官方示例视频验证最方便。如果没有样例视频自己用手机拍一段也行但分辨率别太大1080P 以下即可原因待会在坑位部分详细说。3. 用自己的视频生成3D姿态完整数据链路拆解环境跑通之后紧接着就是最激动人心的部分把镜头对准自己随便做点动作让模型把你“翻译”成3D骨架。但这里有几个容易被忽略的细节我按数据流动顺序拆给你看。3.1 视频预处理分辨率、帧率与内容的取舍VideoPose3D 推理时内部会调用ffmpeg抽帧但它对输入视频的分辨率和时长比较敏感。官方推荐的输入帧宽在 1000 像素左右。太大的话会导致 2D 检测阶段显存溢出太小则关键点检测精度下降。我的处理习惯是先做一次预处理把视频压缩到合理范围ffmpeg -i input.mp4 -vf scale960:-1,fps25 temp/video_960.mp4帧率目标 25fps 即可太高反而会让相邻帧之间的动作变化太小时序卷积学不到有效增量太低会让动作卡顿3D轨迹连续性变差。内容上注意两点一是人体尽量在画面中间占画面高度三分之一以上二是背景不要太杂乱尤其不要有和肤色相近的物体。Detectron2 的检测框如果漂移后续所有 3D 坐标都会跟着抖。3.2 运行推理核心命令与参数解释VideoPose3D 的推理入口是inference.py官方给了现成的 YAML 配置但需要自己建一个适配视频的配置。我用的命令python scripts/inference.py \ --cfg configs/inference/video_inference.yaml \ --video-file temp/video_960.mp4 \ --output output/output.mp4 \ --checkpoint checkpoints/pretrained_h36m_detectron_coco.bin \ --detector detectron2 \ --renderer cmu \ --num-poses 27这里解释几个关键参数--num-poses时序感受野大小决定要用多少帧的上下文来预测当前帧。官方预训练模型对应的配置是 27这个值不是随便填的必须和 checkpoint 训练时的配置一致否则模型加载后会因为输入窗口尺寸不匹配报错。--renderer cmu输出骨架渲染风格CMU 风格连线和 COCO 关键点定义更贴近视觉效果清晰。--detector detectron2指定2D检测后端。跑起来后你会看到终端逐帧打印检测进度一般 10 秒的视频在 RTX 3060 上要一两分钟能跑完。瓶颈主要卡在2D检测阶段VideoPose3D 本身的时序卷积很快。3.3 推理输出和目录结构运行完output/下会多出两个文件一个带 3D 骨架叠加的视频直接把骨架投影回原画面上一个可能是.npz格式的姿态坐标文件。我建议你重点看.npz因为它是“金数据”视频只是可视化结果。加载.npz文件的方式import numpy as np data np.load(output/keypoints.npz, allow_pickleTrue) print(data.files)里面通常包含positions_3d每个关节的3D坐标、positions_2d、metadata等字段。到这里整套流水线已经全部打通。3.4 关于坐标系和动作尺度的一个直觉性认知有基础但不熟悉姿态估计算法的读者可能会困惑输出的3D坐标到底是什么单位答案是 Human3.6M 数据集的“归一化空间”单位。模型在训练时把所有骨架长度缩放到统一尺度所以输出坐标的绝对数值不是米或厘米而是相对于骨架尺寸的比例。如果你想得到真实世界的尺度需要用人体身高去缩放把某一段骨骼比如脊柱在输出空间的长度记为units然后按真实身高中对应骨骼的长度缩放。这个技巧在后续做生物力学分析或动画关键是必备的。4. 可视化与视频导出的进阶操作官方自带的可视化简单粗暴——把3D骨架直接画在原视频上。说实话效果一般但如果你要做更专业的内容比如进 Blender 做动画或者做带轨迹线的科学可视化官方输出就显得不够用了。这里说几个我实测过的扩展方向。4.1 把官方输出视频调成可发布的效果如果你只想快速拿到一个能发朋友圈的“3D骨架和真人同框”视频官方渲染其实也能用但有几个值得调的点--renderer换成opengl能做出更平滑的骨架线条输出分辨率默认跟随输入但建议在--output-size上设成 720P避免视频文件过大骨架颜色在 YAML 配置里可以改 RGB 值不一定是默认绿色。4.2 用 matplotlib 绘制独立3D骨架轨迹我试过直接把 3D 坐标序列扔给matplotlib画一个独立旋转的 3D 骨架比官方视频更容易看动作轨迹。核心代码思路from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt # 假设 joints 是 (T, J, 3) 的ndarrayframes 是帧索引 for t in frames: ax.clear() # 按骨骼连接关系画线段 for (i, j) in SKELETON_CONNECTIONS: ax.plot([joints[t, i, 0], joints[t, j, 0]], [joints[t, i, 1], joints[t, j, 1]], [joints[t, i, 2], joints[t, j, 2]], b) # 设置固定视角 ax.view_init(elev15, azim-60) plt.pause(1/30)注意要手动固定视角否则 axes 的自动缩放会让骨架在旋转时看起来忽大忽小。4.3 联动手臂与脚步运动轨迹的附加可视化我自己的项目在跑完姿态提取后会把左右手腕、左右脚踝四根轨迹线单独画在3D坐标空间里这样能非常直观地看出动作的弧线轨迹这对跑步姿势分析、舞蹈动作对称性检查极其有用。做法很简单从positions_3d里把对应关节索引的坐标取出来画散点或连续曲线就行。关键点是保持可视化和数据在同一个坐标系下别因为缩放而改变骨骼相对位置。5. 实测中绕不开的坑与调优经验这一章我根据自己的实操经历把容易卡住人的问题列成清单每个都说下根源和解决办法方便你按图索骥。5.1 视频时长一旦超过30秒显存直接溢出我第一次直接拿一段 90 秒的完整舞蹈视频跑推理结果在2D检测阶段就 OOM 了。原因是 Detectron2 会一次性把一批视频帧的 Feature Map 存在显存里帧数越多显存压力越大。解决办法很直接先把视频按动作段落剪成 10 秒左右的小段逐个跑完再拼接结果。如果不想剪视频也可以把video_inference.yaml中的frame_batch_size调低强制减少单批处理的帧数官方默认值偏高。5.2 “检测框漂移”导致骨架抖动这是影响最终3D效果最致命的问题。2D检测器每帧独立检测人体框遇到侧面转身、遮挡或出画面再回来时检测框的中心会发生跳跃这个跳跃会传导到3D坐标表现为骨架突然“闪一下”。调优方向有两个先裁剪出人体区域再做2D检测降低背景干扰对输出的3D坐标做平滑后处理滑动窗口平均是最简单有效的窗口大小取 35 帧即可。注意别平滑过头否则会抹掉真实动作的细节。5.3 官方预训练模型的动作类别偏见VideoPose3D 的预训练权重来自 Human3.6M这个数据集的内容以“日常室内动作”为主坐、站、走、打招呼这类。如果你拿来跑剧烈运动比如空翻、武术效果会明显变差因为训练数据里基本没有这种动作样本。两个可行思路换用在其他数据集上微调的 checkpoint比如 MPI-INF-3DHP 版覆盖面更广在自己的动作数据上做微调。这需要你有带标注的3D数据门槛较高但从实验角度看确实能明显提升特定动作的精度。5.4 相机视角对3D重建结果的影响非常大这是我后期做多视角实验时领悟最深的一点。VideoPose3D 在 Human3.6M 上训练时用的是固定相机视角前侧方约 45 度如果你的拍摄机位正好也是这个角度效果最好一旦换成侧方 90 度或正后方深度信息丢失严重3D坐标会变得不稳定。拍摄建议手机固定镜头正对孩子身体前侧略偏 30~45 度不要跟着人物移动镜头不要频繁变焦。如果必须用不同机位可以用--camera-parameters传入相机内参但牵扯到单位换算与畸变矫正非必要不建议新手碰。5.5 重建结果和原视频叠加时的时间偏移有一个小坑3D 可视化视频和原视频画面之间偶尔会对不上看起来骨架动作比真人慢半拍。原因是时序卷积的因果/非因果模式对帧的依赖不同非因果卷积会引入一个固定的感受野延迟这个延迟在渲染时如果没有补偿就会造成时间错位。解决办法是在配置文件里开启flip_augmentation或让inference.py在渲染时做帧对齐实在不行就手动把渲染视频剪掉前几帧再拼接。6. 从跑通到进阶我的一些后续扩展思路流程跑通后这个项目能玩的方向非常多。我自己在它上面做了几个小的二次开发这里挑两个比较值得讲的说给你一些继续深入的方向。一个是把关节坐标转成 CSV 时序数据导入 Excel 或 Python 做角度曲线分析。比如测深蹲膝盖角、硬拉时腰背角度只需要知道对应关节索引按向量夹角公式逐帧计算然后画曲线能看到非常清晰的角度变化模式。time series 的好处是能定量评估动作标准度而不是只看“像不像”。另一个是把3D姿态序列导出为 FBX 或 BVH 文件。VideoPose3D 本身不直接输出动画文件但拿到positions_3d后可以自己写一个 BVH 转换器把骨骼节点的旋转值导出来。网上有现成的bvh_writer工具配合模型输出的节拍基本能一键入 Blender。这个方向适合想做虚拟主播或动画短片的读者。还有一点关于模型训练如果你手头有带 3D 标注的数据集可以对 VideoPose3D 做微调。核心操作是准备自定义数据集格式对齐 Human3.6M 的data_3d_h36m.npz然后改训练脚本里的数据集路径。微调的好处是能让模型适应你自己的画面风格比如低光照、特殊服饰、特定机位等。相比重新训练一个网络微调的时间开销小很多一个下午能完成一个 batch。不过自己录数据做微调的过程中要事先规划好关节点的标注格式并确保2D关键点和3D关键点在数量与顺序上完全对齐否则模型会直接无法训练。这一步容易让人烦躁但坚持下来整个技术栈就彻底变成你自己的工具了。
返回列表