news 2026/9/8 13:56:19

Human3.6M数据集获取与Python解析实战:3D人体姿态估计入门指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Human3.6M数据集获取与Python解析实战:3D人体姿态估计入门指南

简介:面向计算机视觉与人体姿态估计学习者的Human3.6M 3D人体姿态数据集获取资源,提供基于Python的完整下载、解压、预处理工具链,适用于需要快速获取并解析该数据集的科研人员与开发者。资源共14个文件,包含4个Python脚本(负责下载、解压、元数据处理等),以及配置文件、Dockerfile、依赖清单、说明文档等辅助文件,压缩包仅34KB,便于下载和部署。已有3624人学习浏览。通过脚本可自动获取Human3.6M数据集,并支持后续的3D关节位置提取与格式转换,帮助用户跳过繁琐的手动下载与前期处理,直接聚焦于姿态估计模型构建与训练,是入门和研究中实用的效率工具。 如果你准备用Python做3D人体姿态估计,那你迟早会被同一个数据集拦住:Human36M。这个数据集在论文里出现得实在太频繁,几乎所有姿势估计模型的评测都绕不开它;但真要把它下载下来、用Python读进内存,新手的体验往往是:官网申请要好几天,下完的MAT文件打不开,好不容易读出来坐标又对不上。这篇文章我就把申请、下载、解析、投影、可视化整条链路完整讲一遍,刚起步的同学可以直接照着做,踩过的坑也都给你标好了。

1. Human3.6M的家底:为什么它在一众数据集里地位这么高

3D人体姿态估计的任务,是从一张图或者一段视频里恢复人体各关节的三维坐标。这个任务看起来简单,其实对数据集的要求很高,因为你需要“真值”是精确的3D坐标,而不是从2D逆推出来的近似结果。Human3.6M就是在这种需求下诞生的经典基准数据集。

它由Max Planck智能系统研究所于2014年随CVPR论文《Reconstructing 3D Human Pose from 2D Detections》发布。名字里的“3.6M”指的是动作捕捉数据总共提供约360万个3D姿态标注。采集方式是让受试者在室内完成一系列日常动作,同时用Vicon动作捕捉系统记录高精度的3D关节坐标,再用4个数字摄像机从不同视角同步拍摄画面。视频帧率是50Hz,动作捕捉帧率是100Hz,也就是说每个动作序列不仅有多视角的RGB视频,还有对应的、一帧不差的3D骨架真值。

不过有个地方第一次接触的人很容易懵:数据里一共采集了多位受试者,对外公开的只有7位,分别是S1、S5、S6、S7、S8、S9、S11。编号不是从S1到S11连续排列的,没有S2、S3、S4、S10,这是正常现象,不是你下载漏了。动作类型一般是15类,像Directions、Discussion、Eating、Greeting、Jumping、Phoning、Posing、Purchases、Sitting、SittingDown、Smoking、Waiting、WalkDog、Walking、WalkTogether,每位受试者的每个动作还会录制多个重复序列。

骨架标注方面,官方原始标注的关节数量比较密,大家实际用的时候多整理成17个关键关节点这种形式,也有工程实现会重排成COCO或MPII的骨骼顺序。评测指标里见得最多的是两个:一个是MPJPE,直接计算预测关节和真值关节的平均欧氏距离,单位是毫米;另一个是PA-MPJPE,先把预测结果做一次刚性对齐再计算误差。

还有一个绕不开的概念叫Protocol。Protocol 1输入用的2D关键点来自真实标注,只评测从2D升到3D的部分;Protocol 2输入用的2D关键点来自检测器,比如CPM或者Mask R-CNN先检测出2D关键点,再交给3D模型,更贴近真实应用,但整体误差也会更大。论文里常见的训练测试划分是用S1、S5、S6、S7、S8训练,S9、S11测试。你看到“Human3.6M under Protocol 2”这类表述,指的就是这套设置。

2. 数据获取的三条路:官方申请、开源脚本、NPZ预处理版,各有各的门道

数据集这么经典,拿到手却没那么容易。我实际走过三条路,分别说下体验和适用场景。

2.1 官网申请流程与注意事项

最正统的途径是去Human3.6M官网提交申请。流程大概是:

  1. 打开官网,找到数据申请入口。
  2. 填写一张表单,内容包括姓名、所属单位、邮箱、研究用途。
  3. 提交后等待人工审核,快的话一两天,慢的话可能要一周。
  4. 审核通过后会收到一封激活邮件,里面包含下载链接和简单的使用说明。
  5. 进入下载页面,按subject、action组织好的文件夹就在那,可以用浏览器直接点,也可以用支持断点续传的工具批量拉取。

有几个坑一定要提前知道。第一,申请邮箱尽量用机构邮箱,个人邮箱被拒的概率很大;第二,下载链接通常有时效性,我遇到过48小时内必须下载完的情况,文件还没下完链接就先失效了,最后只好重新申请;第三,完整数据集非常大,视频部分占大头,动辄几十GB到上百GB,下载前千万先检查磁盘空间和网络稳定性。

2.2 开源项目里附带的下载脚本

第二种途径是直接找开源项目里已经写好的下载脚本。GitHub上做3D姿态估计的项目不少,VideoPose3D、ST-GCN这类经典仓库里都带了数据处理相关的脚本,有些项目甚至会直接在release里挂好预处理后的数据文件。走这条路的好处是省心,不用自己写申请理由,也不用去跟原始目录结构较劲。坏处是版本比较杂,有的脚本是针对老版文件命名的,有的预处理环节已经做了自己项目的自定义修改,用之前得把处理流程看清楚。

2.3 NPZ预处理版本才是最省心的选择

如果只是想快速跑通一个baseline,或者验证一个想法,我强烈建议直接找NPZ预处理版本。最典型的是Martinez等人在ICCV 2017工作里发布的data_3d_h36a.npz,这个文件把官方MAT和XML里的核心信息抽出来,统一整理成一个numpy压缩包:2D关键点、3D关键点、相机参数、训练测试划分、动作名称全都排好,np.load一下就能用。很多后来的开源项目都基于这个文件二次fork。

但用预处理版也有前提,你得搞清楚它的关节顺序是什么、坐标单位是什么、2D坐标到底是GT投影还是检测器输出。我见过有人拿到的数据姿态画出来是倒的,就是因为关节索引没对齐。

三条路径对比下来,大致是这样:

获取途径适合场景主要风险
官网申请做数据pipeline、多视角任务、视频输入审核周期长、下载链接会过期、总量大
开源项目脚本快速复现某个论文版本混杂、可能被二次裁剪
NPZ预处理版快速实验、对比SOTA缺少原始视频、动作序列可能被精简

3. 从文件到Python数组:MAT/XML/NPZ格式与加载代码

数据下载完,真正的考验才开始。不同途径拿到的文件格式差别很大,你得先搞清楚里面装的是什么。

3.1 官网完整包的目录结构

以官网下载并解压后的常见结构为例,大致是这样:

human3.6m/ ├── S1/ │ ├── Directions_1/ │ │ ├── video.mp4 │ │ └── ... │ ├── Discussion_1/ │ └── ... ├── S5/ ├── metadata.xml └── ...

每个subject下面按“动作名_重复序号”建文件夹,里面放对应动作的视频和动作捕捉原始数据。如果是做视频输入的模型,这套目录就是你的数据源。

3.2 MAT文件命名:新老版本差别很大

动作捕捉数据通常会整理成MAT文件保存,但文件命名有两种常见风格,老版本长这样:

S_01_act_01_sub_01_ca_01.mat

新版本长这样:

subject_01_act_01_rr_01_ca_01.mat

含义都是:subject编号、动作编号、重复序号、相机编号。很多网上流传的解析脚本只认老版本命名,换到新下载的文件上直接报错。如果你下载的是新命名,务必先看脚本里怎么拼文件名,或者统一用glob匹配。

3.3 用scipy.io.loadmat读原始MAT

MAT文件用scipy.io.loadmat读取。但H36M的MAT文件不是简单一个矩阵,通常是多层struct嵌套,字段名也因为来源不同而千差万别。我的习惯是先打印keys,再逐层往下看,绝不猜字段名:

import scipy.io as sio mat = sio.loadmat("subject_01_act_01_rr_01_ca_01.mat", squeeze_me=True) print(mat.keys()) # 常见字段名有 pose_3d、points3d、pose_xyz 之类 # 如果遇到 1x1 的 struct array,先调用 .item() 解包 data = mat["pose_3d"] # 具体字段名以实际打印为准 print(data.shape)

3.4 NPZ预处理版怎么读

如果你用的是data_3d_h36a.npz这种预处理文件,读起来就痛快多了:

import numpy as np data = np.load("data_3d_h36a.npz", allow_pickle=True) train = data["train"].item() test = data["test"].item() print(train.keys()) # 受试者列表 print(train["S1"].keys()) # 动作序列列表 seq = train["S1"]["Walking 1"] print(seq.keys()) # 输出里会有 positions_3d、positions_2d、cameras 等 print(seq["positions_3d"].shape) # (帧数, 17, 3) print(seq["positions_2d"].shape) # (帧数, 17, 2)

第一次读的时候容易漏掉allow_pickle=True,不写的话numpy会直接报错。这个参数就是为了解包里面的Python dict,属于这个数据集的标准操作。

3.5 动作名字符串里的隐形地雷

NPZ里动作名的键通常是“动作名+空格+重复序号”的形式,比如Walking 1Walking 2,中间是有空格的。很多人写成Walking_1,一查就报KeyError。先print(train["S1"].keys())看清楚原始字符串,再写索引。

另外一个容易忽略的点是帧率对齐。动作捕捉本身是100Hz,视频是50Hz,所以官方原始数据里每秒有100个骨架帧,但视频每秒只有50帧。直接用原始MAT做训练时,一定要明确自己到底取哪个基准;NPZ预处理版在制作时已经把2D和3D统一对齐成了50Hz,这也是我推荐你从NPZ入门的重要原因。

4. 坐标投影与可视化验证:确认数据真的读对了

数据读进来了,不代表它是对的。H36M的坐标系、单位、相机参数这堆东西,初学者稍不注意就全乱了。

4.1 单位:毫米还是米

先记住结论:H36M的3D坐标单位是毫米。有些库训练时习惯把坐标除以1000转成米,有些直接拿毫米算MPJPE,这都行,但你别混着用。我见过有人直接从某个开源项目里拉数据,后来又换了另一个预处理版本,两个版本单位不一致,训练半天loss下不去,查了两天才发现是这问题。

4.2 相机参数长什么样

在NPZ里,每个动作序列的cameras字段是一个长度为4的数组,对应4个摄像机视角。每个相机的dict包含:

  • f:焦距,2维向量,对应(fx, fy)
  • c:主点坐标,2维向量,对应(cx, cy)
  • R:3x3旋转矩阵
  • t:3x1平移向量
  • dist:畸变系数

4.3 3D到2D的投影公式

世界坐标系下的3D点,先经旋转和平移变换到相机坐标系,再做透视投影,公式如下:

x_cam = R @ X_world + t x_pixel = f[0] * x_cam[0] / x_cam[2] + c[0] y_pixel = f[1] * x_cam[1] / x_cam[2] + c[1]

写成Python函数:

import numpy as np def project_3d_to_2d(points_3d, camera): R = camera["R"] t = camera["t"] f = camera["f"] c = camera["c"] points_cam = (R @ points_3d.T).T + t.reshape(1, 3) points_2d = np.zeros((points_cam.shape[0], 2)) points_2d[:, 0] = f[0] * points_cam[:, 0] / points_cam[:, 2] + c[0] points_2d[:, 1] = f[1] * points_cam[:, 1] / points_cam[:, 2] + c[1] return points_2d

这里特别提醒:不同解析包对R和t的定义可能反着写,有的是R @ X_world + t,有的是R @ (X_world - t)。你自己推断公式的时候,最有效的验证方法就是拿已知的3D点和2D标注做对比,如果投影结果和官方给的2D坐标位置对不上,第一怀疑R和t的符号形式,第二怀疑单位。

4.4 把骨架画出来,一眼看出对错

判断数据是否正确的黄金标准是可视化。画3D骨架其实不复杂:

import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D edges = [ (0, 1), (1, 2), (2, 3), (0, 4), (4, 5), (5, 6), (0, 7), (7, 8), (8, 9), (8, 10), (10, 11), (11, 12), (8, 13), (13, 14), (14, 15), ] def draw_skeleton(ax, pts3d, edges, color="b"): ax.scatter(pts3d[:, 0], pts3d[:, 1], pts3d[:, 2], s=20, c=color) for a, b in edges: ax.plot(pts3d[[a, b], 0], pts3d[[a, b], 1], pts3d[[a, b], 2], c=color, lw=2) seq = train["S1"]["Walking 1"] points_3d = seq["positions_3d"][0] fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot(111, projection="3d") draw_skeleton(ax, points_3d, edges) ax.set_box_aspect((1, 1, 1)) plt.show()

画出来的姿态如果站立方向合理、四肢位置符合人体结构,说明数据基本没问题。我每次换一个新数据集,第一件事永远是画骨架,不画到正常绝不往下走。这一步看着简单,实际能省下大量的debug时间。

5. 我踩过的坑,和你可能也会遇到的坑

最后把这些年实际踩过的坑集中写出来,基本都是血泪教训。

现象原因对策
申请邮件一直不回复用了个人邮箱换机构邮箱重新提交
下载到一半链接失效下载链接有时效失效后重新走申请流程,用支持断点续传的工具
loadmat后print出来全是1x1 structMAT内部存在多层嵌套逐层.item()展开,先看清楚结构
np.load报Object arrays错误没开allow_pickleallow_pickle=True
动作名查不到字符串里多了空格或下划线先打印keys再复制原始字符串
训练时MPJPE数值离谱单位、关节顺序或坐标定义不统一先画骨架,再做投影对比
Protocol 2实验的2D输入对不上把GT 2D当成了检测器2D确认输入来自检测器输出,不是GT投影

还有一个细节值得单独拎出来说。H36M数据里,同一个动作序列在不同相机视角下,视频帧和动作捕捉帧的对应关系是固定的,但你如果从原始MAT直接解析,必须自己处理“100Hz动捕帧到50Hz视频帧”的抽取。NPZ版本已经帮你做了这层对齐,所以很多人推荐新手先用NPZ。我自己在踩过一次“2D视频帧和3D骨架错位”的坑之后,就养成了一个习惯:无论是自己做pipeline还是用开源代码,第一件事永远是随机抽一帧,把2D关键点画到原始视频画面上,确认3D骨架投影后和2D标注完全重合,再放心进入训练环节。

如果让我重新入坑一次,我的顺序会是这样:先下载NPZ预处理版,把整个读取、可视化、训练流程跑通,等真要做视频输入或者多视角任务,再回官方源申请完整数据。数据集获取只是万里长征第一步,但这一步走稳了,后面能省掉大量查错时间。希望这份H36M获取与解析的实战记录,能帮你在入门3D人体姿态估计时少走些弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 13:56:08

开源AI编码代理opencode实战:从终端安装到Skills与Playwright集成

最近终端圈子里最热闹的一件事,就是那个用 Go 写的开源 AI 编码代理 opencode 突然爆火。如果你一直在用 Claude Code、Codex 或者 Aider 这类工具,那你大概率已经在各种仓库、X 时间线或者 V2EX 讨论帖里看到过它的名字。我花了一周时间把它从安装、配置…

作者头像 李华
网站建设 2026/9/8 13:55:34

Android BaseActivity封装:整合ViewBinding、权限申请与加载弹窗

1. 为什么要写这份BaseActivity:一个被重复代码逼出来的决定今年接手一个维护了大半年的项目,里里外外跑了一遍代码,最让我难受的不是业务逻辑多复杂,也不是第三方SDK接得多乱,而是那9个Activity里几乎都躺着一份一模一…

作者头像 李华
网站建设 2026/9/8 13:55:31

软硬件一体化开发团队组建实战:从接口契约到联调协作的避坑指南

最近我一直在忙一件事:为手头一个软硬件一体化的新项目组队。产品方向已经定了,硬件要带传感器阵列,软件要跑实时控制逻辑,软件这边还得分出一半精力做上位机数据可视化——这种项目靠一个人从头扛到尾,基本不现实。所…

作者头像 李华
网站建设 2026/9/8 13:55:29

华为交换机Hybrid端口实战:实现VLAN 10与20互通,隔离VLAN 30

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 13:53:57

Java Socket实现文件传输:从协议设计到粘包处理实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 13:52:01

INAV Configurator 2.2.1 安装指南:从解压到连接飞控的完整实操

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华