☰
ViTPose 仓库中的 VoxelPose:基于多相机体素投影的两阶段 3D 人体姿态估计实战指南
2026/10/14 8:20:20 网站建设 项目流程
  • 人工智能
  • 计算机视觉
  • 深度学习

【免费下载链接】ViTPose

The official repo for [NeurIPS'22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [TPAMI'23] "ViTPose++: Vision Transformer for Generic Body Pose Estimation"

项目地址:https://gitcode.com/gh_mirrors/vi/ViTPose
点击查看免费下载

本文以 configs/body/3d_kpt_mview_rgb_img/voxelpose/README.md 为骨架,结合本仓库mmpose目录下的检测器、骨干网络、头部与数据集源码,系统讲解 VoxelPose(ECCV 2020)多相机 3D 人体姿态估计算法在本仓库中的完整实现:从"立方体提议网络 + 姿态回归网络"两阶段设计、体素投影的底层原理,到 Panoptic 数据集上的可运行配置、数据管线、训练/测试命令与评估指标。读完本文,你将能够看懂并复现该模型在 CMU Panoptic 数据集上的完整流程,理解DetectAndRegress、VoxelCenterDetector、VoxelSinglePose、V2VNet等模块的调用关系,并掌握如何修改空间尺寸、体素分辨率、相机数量等关键超参。

一、算法背景:从单目 2D 到多相机 3D 的两阶段框架

VoxelPose 论文提出的核心思路是:将多相机 3D 人体姿态估计拆解为两个阶段——

  1. 人体中心检测(Cuboid Proposal Network):在 3D 空间中检测每个人的中心位置,为每个人生成一个"人体立方体提议(cuboid proposal)";
  2. 人体姿态回归(Pose Regression Network):以每个提议立方体为输入,回归出其中人体的 3D 关节点坐标。

原文的关键技术特征是:

  • 两个阶段的网络全部基于 3D 卷积(本仓库中均使用V2VNet,见 v2v_net.py);
  • 3D 卷积的输入特征体积(feature volume)并非直接由图像卷积得到,而是通过将每个体素(voxel)投影到多视角图像上、在对应相机的 2D heatmap 投影位置处采样来生成的。

这一设计避开了显式的人体匹配(person association)问题:多视角的 2D 姿态热图经由相机内外参被"拧"成一个统一的 3D 特征体,后续的检测与回归都在该 3D 空间内进行,天然对齐了各视角的信息。

本仓库将该算法以DetectAndRegress检测器(multiview_pose.py)的形式集成到 mmpose 框架中,对应配置目录为configs/body/3d_kpt_mview_rgb_img/voxelpose/,并在 CMU Panoptic 数据集(ICCV 2015)上提供了完整的训练、验证配置与已发布指标。

二、源码级架构:体素投影层与两个 3D 网络

2.1 ProjectLayer:体素 → 多视角 2D 热图的投影采样

整个模型的"体素化"核心在ProjectLayer(multiview_pose.py)中实现。其工作流程如下:

  1. 构建 3D 网格:compute_grid依据box_size(空间范围)、box_center(空间中心)与num_bins(体素分辨率),用torch.linspace在 x/y/z 三个维度生成均匀网格,得到所有体素中心的 3D 坐标grid;
  2. 世界坐标 → 像素坐标:对每个相机,利用相机参数构造SimpleCameraTorch(single_camera_torch.py),通过world_to_pixel(grid)(camera_base.py)把体素网格投影到该相机的图像平面;
  3. 有效性掩码(bounding):判断投影点是否落在图像范围内(xy坐标非负且小于图像宽高),生成一个 0/1 掩码,用于屏蔽"看不到"该体素的相机视角;
  4. 仿射变换与归一化采样:将投影坐标经affine_transform_torch对齐到 heatmap 坐标系,归一化到[-1, 1]后作为F.grid_sample的采样网格,在对应相机的 2D 特征图feature_maps[c]上采样出该体素的特征;
  5. 多视角平均聚合:对每个体素,把所有可见相机采样到的特征加权求和并归一化(除以可见相机数,+1e-6防除零),最终得到形状为(N, C, cubeL, cubeW, cubeH)的 3D 特征体积。

从代码可以看到,grid_size、grid_center、cube_size三个参数即决定了 3D 空间的物理范围(毫米)与体素分辨率,它们是后文配置文件中space_size/space_center/cube_size等字段的直接映射。

2.2 阶段一:VoxelCenterDetector 人体中心检测

VoxelCenterDetector(multiview_pose.py)承担第一阶段:

  • 用ProjectLayer在全空间space_size上构建cube_size分辨率的初始特征体;
  • 送入center_net(配置为V2VNet(input_channels=15, output_channels=1))得到单通道 3D 人体中心热图;
  • 由CuboidCenterHead(voxelpose_head.py)做3D NMS:通过max_pool3d(max_pool_kernel=3)找出热图局部极大值,取 Top-K(max_num)个候选点,并通过_get_real_locations把体素索引反算回世界坐标(毫米),输出(N, P, 5)的候选张量——前 3 维为 3D 坐标、第 5 维为响应分数;
  • 训练时assign2gt依据train_cfg['dist_threshold'](配置中为 500.0 毫米)把候选中心与 GT 中心做最近邻匹配;测试时依据test_cfg['center_threshold'](配置中为 0.3)过滤低分候选。

2.3 阶段二:VoxelSinglePose 姿态回归

VoxelSinglePose(multiview_pose.py)负责第二阶段:

  • 对每个检测到的人体中心,以sub_space_size(提议立方体的物理尺寸)和sub_cube_size(提议立方体的体素分辨率)为参数,再次调用ProjectLayer从多视角 2D 特征图上采样出局部特征体(这正是 README 所述"cuboid proposal"的实现);
  • 送入pose_net(配置为V2VNet(input_channels=15, output_channels=15),输出每人 15 个关节的 3D 热图);
  • 由CuboidPoseHead(voxelpose_head.py)做积分姿态回归(Integral Pose Regression):将热图经softmax(beta * x)(beta=100.0控制软最大化锐度)后与体素网格坐标加权求和,直接回归出(N, K, 3)的关节世界坐标,而不是像 2D 方法那样取热图最大值。

训练时两个阶段联合:DetectAndRegress.forward_train(multiview_pose.py)先让human_detector产出候选中心,再把候选传给pose_regressor;2D 骨干默认被冻结(freeze_2d=True,构造参数默认值见 multiview_pose.py),可改为False以联合微调 2D 热图分支。推理阶段forward_test依次得到pose_3d、human_detection_3d与sample_id。

2.4 V2VNet:全 3D 卷积的编码-解码骨干

两个阶段共用的 3D 骨干是V2VNet(v2v_net.py),其结构为:

  • front_layers:7×7×7 的Basic3DBlock+Res3DBlock,把输入通道数映射到mid_channels(默认 32);
  • EncoderDecorder:两次 2×2×2 下采样 + 残差块的编码器、瓶颈残差块、两次转置卷积上采样 + 跳跃连接的解码器;
  • output_layer:1×1×1 卷积把通道数映射到output_channels。

该结构保证了特征体在保持空间分辨率的前提下获得足够大的感受野,是两阶段 3D 推理的共同基础。

三、配置文件深度解析:panoptic 5 相机配置

本仓库为 CMU Panoptic 数据集提供了完整的可运行配置 voxelpose_prn64x64x64_cpn80x80x20_panoptic_cam5.py(文件名中的prn64x64x64表示姿态回归网络输入 64³ 体素,cpn80x80x20表示中心检测网络输入 80×80×20 体素,cam5表示使用 5 个相机视角)。

3.1 3D 空间与体素分辨率

space_size = [8000, 8000, 2000] # 3D 空间物理范围(毫米):长 8m × 宽 8m × 高 2m space_center = [0, -500, 800] # 空间中心坐标(毫米) cube_size = [80, 80, 20] # 中心检测阶段的体素分辨率 sub_space_size = [2000, 2000, 2000] # 姿态回归阶段"人体提议立方体"的物理尺寸(2m³) sub_cube_size = [64, 64, 64] # 姿态回归阶段的体素分辨率 image_size = [960, 512] # 2D 骨干输入图像尺寸 heatmap_size = [240, 128] # 2D 热图尺寸(输入的 1/4) num_joints = 15 # Panoptic 数据集使用的关节数(前 15 个 COCO 关节)

这些数值直接决定了内存占用与精度:体素分辨率越高、空间范围越大,3D 卷积的计算量越大;sub_space_size若小于人体实际活动范围,则中心检测误差可能导致关节截断。修改时需要同时保持space_size与cube_size的比例关系与相机标定覆盖范围一致。

3.2 两阶段模型结构

model = dict( type='DetectAndRegress', backbone=backbone, # 2D 阶段:AssociativeEmbedding + ResNet-50 + DeconvHead pretrained='checkpoints/resnet_50_deconv.pth.tar', # 2D 骨干预训练权重 human_detector=dict( type='VoxelCenterDetector', image_size=image_size, heatmap_size=heatmap_size, space_size=space_size, cube_size=cube_size, space_center=space_center, center_net=dict(type='V2VNet', input_channels=15, output_channels=1), center_head=dict( type='CuboidCenterHead', space_size=space_size, space_center=space_center, cube_size=cube_size, max_num=10, max_pool_kernel=3), train_cfg=dict(dist_threshold=500.0), # 候选中心与 GT 的匹配距离阈值(毫米) test_cfg=dict(center_threshold=0.3), # 中心响应置信度阈值 ), pose_regressor=dict( type='VoxelSinglePose', image_size=image_size, heatmap_size=heatmap_size, sub_space_size=sub_space_size, sub_cube_size=sub_cube_size, num_joints=15, pose_net=dict(type='V2VNet', input_channels=15, output_channels=15), pose_head=dict(type='CuboidPoseHead', beta=100.0))) # softmax 放大系数

其中 2D 阶段的backbone使用AssociativeEmbedding(bottom-up 2D 姿态检测器)+ ResNet-50 +DeconvHead,输出 15 通道 2D 热图;MultiLossFactory配置了heatmaps_loss_factor=1.0、with_heatmaps_loss=[True]等损失权重。center_head的max_num=10限制每帧最多检测 10 人,max_pool_kernel=3为 3D NMS 池化核大小。

3.3 训练超参

optimizer = dict(type='Adam', lr=0.0001) lr_config = dict(policy='step', warmup='linear', warmup_iters=500, warmup_ratio=0.001, step=[8, 9]) total_epochs = 15 evaluation = dict(interval=1, metric='mAP', save_best='mAP')

优化器为 Adam,学习率 1e-4;训练 15 个 epoch,在第 8、9 个 epoch 进行阶梯式衰减,前 500 次迭代线性 warmup;每个 epoch 结束后在验证集上评估 mAP 并保存最优权重。

3.4 数据划分:序列与相机视角

train_data_cfg定义训练集为 9 个 Panoptic 序列(如160422_ultimatum1、160906_ian1等),选用 5 个相机视角cam_list=[(0, 12), (0, 6), (0, 23), (0, 13), (0, 3)](格式为(panel, node)),seq_frame_interval=3表示每 3 帧取 1 帧;验证集换用160906_pizza1、160422_haggling1、160906_ian5、160906_band4四个序列,取帧间隔 12。root_id=2指定以mid_hip作为人体中心关节,max_num=10限制每帧人数。

四、数据集与数据管线:从 Panoptic 原始数据到体素目标

4.1 Body3DMviewDirectPanopticDataset

数据集实现位于 body3d_mview_direct_panoptic_dataset.py,类名为Body3DMviewDirectPanopticDataset,继承自Kpt3dMviewRgbImgDirectDataset,同时加载 2D/3D 标注与相机参数。其要点包括:

  • load_config从data_cfg解析seq_list、cam_list、num_cameras、seq_frame_interval、root_id、max_num等字段;
  • _get_cam读取每个序列的calibration_{seq}.json标定文件,把相机外参旋转矩阵乘以坐标变换矩阵M,并将平移从厘米换算为毫米(* 10.0),统一到世界坐标系;
  • _get_db遍历序列中的hdPose3d_stage1_coco19/*.json3D 标注,把joints19截取为前num_joints个关节,对每个身体做 3D 坐标变换(乘以M与 10 倍缩放),并用SimpleCamera.world_to_pixel反投影出 2D 坐标作为 2D 标注;
  • 预处理结果会缓存为data/panoptic/group_{subset}_cam{num_cameras}.pkl,若缓存存在则直接加载,db_file的缓存命中校验要求sequence_list、interval、cam_list与当前配置一致。

配置中data_root = 'data/panoptic/',train/val/test 均使用该数据集类,samples_per_gpu=1、workers_per_gpu=4(val/test 的samples_per_gpu=2)。

4.2 关键数据变换

  • MultiItemProcess(shared_transform.py):对每个相机视角的样本分别执行子管线(LoadImageFromFile→BottomUpRandomAffine→ToTensor→NormalizeTensor),再按 key 合并成多视角 batch;
  • DiscardDuplicatedItems(shared_transform.py):对joints_3d、roots_3d、num_persons等跨视角共享的 key 去重,只保留一份;
  • GenerateVoxel3DHeatmapTarget(pose3d_transform.py):训练时生成 3D 人体中心热图目标,sigma=200.0(毫米)决定高斯核宽度,joint_indices=[2]指定只对mid_hip(根关节)生成中心热图;代码先用np.linspace建立空间网格,再对每个可见人体的根关节写入三维高斯分布并np.clip(target, 0, 1);
  • Collect负责把img、targets_3d与相机、中心、尺度等 meta 信息聚合给模型。

五、模型注册与测试验证

  • 检测器DetectAndRegress、VoxelCenterDetector、VoxelSinglePose均通过@POSENETS.register_module()注册(multiview_pose.py),骨干V2VNet通过@BACKBONES.register_module()注册(v2v_net.py),头部CuboidCenterHead、CuboidPoseHead通过@HEADS.register_module()注册(voxelpose_head.py),因此可在配置中按字符串直接引用;
  • 单测 test_multiview_pose.py 中的test_voxelpose_forward构建了DetectAndRegress(backbone=None,直接输入 2D 热图input_heatmaps)配合VoxelCenterDetector与VoxelSinglePose的最小闭环,覆盖forward_train与forward_test两个分支,可作为理解模型接口的参考用例。

六、训练、测试与评估指标

6.1 训练与测试命令

依据 getting_started.md 的通用用法,在配置与数据就绪后:

# 单卡训练 python tools/train.py configs/body/3d_kpt_mview_rgb_img/voxelpose/panoptic/voxelpose_prn64x64x64_cpn80x80x20_panoptic_cam5.py # 多卡分布式训练(如 8 卡) ./tools/dist_train.sh configs/body/3d_kpt_mview_rgb_img/voxelpose/panoptic/voxelpose_prn64x64x64_cpn80x80x20_panoptic_cam5.py 8 # 测试并评估(metric 可选 mAP / mpjpe) python tools/test.py configs/body/3d_kpt_mview_rgb_img/voxelpose/panoptic/voxelpose_prn64x64x64_cpn80x80x20_panoptic_cam5.py \ ${CHECKPOINT_FILE} --eval mAP

2D 骨干的预训练权重路径checkpoints/resnet_50_deconv.pth.tar需按配置放置。数据集准备方面,docs/en/tasks/3d_body_keypoint.md 提示需要参照 voxelpose-pytorch 项目下载 CMU Panoptic 数据,只需下载配置中使用的序列与相机视角(HD_Video_Number与相机顺序可调整),并注意序列160906_band3可能因 CMU 服务器问题不可用。

6.2 评估指标与已发布结果

配置中evaluation = dict(interval=1, metric='mAP', save_best='mAP'),数据集类ALLOWED_METRICS = {'mpjpe', 'mAP'}(body3d_mview_direct_panoptic_dataset.py)。其evaluate方法把每个预测姿态与各 GT 计算 MPJPE 后取最近 GT 匹配,并以该误差作为 AP/AR 判定依据:

  • mAP指标:在 25/50/75/100/125/150 mm 六个 MPJPE 阈值下分别计算 AP 与 AR,取平均得到 mAP 与 mAR;
  • mpjpe指标:输出RECALL 500mm与MPJPE 500mm(500 mm 阈值内的平均关节误差与召回)。

对应 panoptic 子目录 README 与本仓库 model-index.yml 中登记的 CMU Panoptic 验证集结果如下:

ArchmAPmARMPJPERecall@500mm
prn64_cpn80_res50(5 相机)97.3197.9917.5799.85

其中mpjpe_threshold = np.arange(25, 155, 25)定义了 mAP 的六个判定阈值(body3d_mview_direct_panoptic_dataset.py)。该结果表明在 5 个同步相机、2m³ 提议立方体(64³ 体素)的配置下,VoxelPose 能够在 CMU Panoptic 的"野性"多交互场景中取得很高的关节定位精度与召回率。

七、实践要点小结

  1. 内存与分辨率权衡:cube_size=[80,80,20]与sub_cube_size=[64,64,64]决定两个 3D 网络的输入体积;减小分辨率可显著降低显存,但会损失中心定位与关节回归精度;
  2. 相机同步与标定是前提:ProjectLayer依赖每个相机的内参K、畸变系数与外参R/T完成世界坐标到像素的投影,标定误差会直接传导到体素采样位置;
  3. 2D 热图质量决定上限:体素特征完全来自多视角 2D 热图的网格采样,因此backbone(ResNet-50 + DeconvHead)的 2D 检测精度至关重要,freeze_2d=True时 2D 分支仅作特征提取器;
  4. 根关节选择:root_id=2(mid_hip)作为人体中心用于生成中心热图,GenerateVoxel3DHeatmapTarget的joint_indices=[2]与其保持一致;
  5. 调参入口:中心检测的dist_threshold、center_threshold、max_num,以及姿态回归的beta,分别控制训练匹配、测试过滤、最大人数与积分回归的锐度,是最常需要调节的四个超参。

通过以上配置、源码与数据管线的对照阅读,你可以把 VoxelPose 的两阶段多相机 3D 姿态估计流程完整复现到自己的多视角数据上,并将本文涉及的空间体素化、多视角投影采样与 3D 积分回归思路迁移到其他多相机任务中。

  • 人工智能
  • 计算机视觉
  • 深度学习

【免费下载链接】ViTPose

The official repo for [NeurIPS'22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [TPAMI'23] "ViTPose++: Vision Transformer for Generic Body Pose Estimation"

项目地址:https://gitcode.com/gh_mirrors/vi/ViTPose
点击查看免费下载

相关推荐

上一篇:TDengine 容错与灾备实战:WAL 数据可靠性机制与双集群异地同步方案
下一篇:Teleport MWI Terraform Provider 本地构建与联调指南:dev_overrides 配置实战

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询