人体动作捕捉格式BVH及其与三维坐标的转换

BVH简介

BVH是BioVision公司推出的一种人体动作捕捉文件格式。这种文件以节点为核心元素,记录连续数帧内人体骨架的运动。

BVH=?

研究一个东西的时候我比较喜欢先研究它的名字。BVH可以认为是BioVision Hierarchy的缩写,因为这类文件对节点的组织是按照树形结构来的,也就是层次化(hierarchical)的。关于这个名字还有另一种可能的解释:如果你去查询Blender的文档,对BVH的介绍则将其等同于BioVision Motion Capture. 我倾向于前者,因为hierarchy这个词其实揭示了BVH的本质。

把这类文件叫做BVH有一个最单纯最直接的原因,那就是.bvh是所有这类文件的统一后缀|·ω·)

文件结构

文件分为两大部分,层级结构运动信息。下面是BVH的一个示例:

HIERARCHY
ROOT Hips
{
    OFFSET  0.00    0.00    0.00
    CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
    JOINT Chest
    {
        OFFSET   0.00    5.21    0.00
        CHANNELS 3 Zrotation Xrotation Yrotation
        JOINT Neck
        {
            OFFSET   0.00    18.65   0.00
            CHANNELS 3 Zrotation Xrotation Yrotation
            JOINT Head
            {
                OFFSET   0.00    5.45    0.00
                CHANNELS 3 Zrotation Xrotation Yrotation
                End Site 
                {
                    OFFSET   0.00    3.87    0.00
                }
            }
        }
        JOINT LeftCollar
        {
            ...
        }
	...
}

MOTION
Frames:    2
Frame Time: 0.033333
 8.03    35.01   88.36  -3.41    14.78  -164.35  13.09   40.30  -24.60   7.88    43.80   0.00   -3.61   -41.45   5.82    10.08   0.00    10.21   97.95  -23.53  -2.14   -101.86 -80.77  -98.91   0.69    0.03    0.00   -14.04   0.00   -10.50  -85.52  -13.72  -102.93  61.91  -61.18   65.18  -1.57    0.69    0.02    15.00   22.78  -5.92    14.93   49.99   6.60    0.00   -1.14    0.00   -16.58  -10.51  -3.11    15.38   52.66  -21.80   0.00   -23.95   0.00   
 7.81    35.10   86.47  -3.78    12.94  -166.97  12.64   42.57  -22.34   7.67    43.61   0.00   -4.23   -41.41   4.89    19.10   0.00    4.16    93.12  -9.69   -9.43    132.67 -81.86   136.80  0.70    0.37    0.00   -8.62    0.00   -21.82  -87.31  -27.57  -100.09  56.17  -61.56   58.72  -1.63    0.95    0.03    13.16   15.44  -3.56    7.97    59.29   4.97    0.00    1.64    0.00   -17.18  -10.02  -3.08    13.56   53.38  -18.07   0.00   -25.93   0.00  

该文件是删减过的,为了显示清楚格式。>点我< 看源文件。

层级结构

首先HIERARCHY标记了层级结构部分的开始。

可以跟着编译器的思路来理解这一部分:

  • 现在开始读这个文件啦,首先读到的是ROOT,这表示第一个节点是根节点。第一个节点总是根节点;
  • 往下读,读到了Hips这个词,结合上一条的信息,我们就知道了,根节点的名字是’Hips’。对于人体骨架来说,根节点一般都取在Hips也就是臀部。
  • 接着,出现了{,左括号开始了,必然有右括号}与之闭合,而括号之间的部分,既有节点,也有信息。我们可以理解为括号括起来的部分从属于刚刚读到的节点,这里是根节点Hips
  • 下面读到一个关键字OFFSET。接下来会有三个数字,这里是0.00 0.00 0.00这表示该节点相对于父节点的偏移,也可以理解为从父节点到该节点连线所表征的向量。根节点没有父节点,所以这里是0.
  • 再读,读到CHANNELS这个关键词,那么这一行剩下的部分就是几个表示自由度的关键字,Xrotation Yrotation Zrotation表示了三个旋转自由度,Xposition Yposition Zposition 表示三个平移自由度。这一行表示刚才的根节点的自由度信息。
    • 一般来说,根节点有全部的6个自由度,而其余节点只有3个旋转自由度。
    • 这些自由度的具体含义会放在后一节说明。
  • 接着往下,读到了JOINT 这个关键字,这意味着这一行表示的是一个节点,后面的一个词Chest则是这个节点的名字。这个节点和根节点唯一的区别就是标记是JOINT而不是ROOT
  • 下面又出现了{,同样的,括号内的信息和子节点都从属于该节点。
  • 直到End Site出现前的部分都不需要赘述。End Site是一个无名节点,表示树形结构到这里就是叶节点啦,后面再也没有子节点了。End Site没有子节点,所有也就没有自由度信息,只有相对父节点的偏移信息。
  • 接下来读到了本文件第一个},表示一个节点的所有范围终结。
  • 下面再出现JOINT标记的节点时,我们回去找它在谁的括号内,它就是谁的子节点,以此类推,直到MOTION结束,因为这是下一部分开始的标志。

运动信息

紧承前节,看到了MOTION这个关键字,就代表着运动信息的部分开始了。

这一部分的结构要简单的多,就不像上一节那样介绍了:

  • 第二行Frames: 2表示帧数,这里是2帧;
    • 这里的帧数必须与后面的帧数据行数相等,因为这个数字决定了要读取多少行,如果少了会造成数据浪费,多了就会出bug
  • 第三行Frame Time: 0.033333 表示每一帧的持续时间,这里是 1 30 s \frac{1}{30}\text{s} 301s,也就是这个文件是30FPS
  • 后面有n行运动数据,每行为一帧。这些信息按照HIERARCHY部分的自由度出现的顺序一一对应。其中角度的单位是度(°)

运动计算

这一部分主要解决的问题是:如何通过BVH复现运动情况。这种旋转还是很抽象,要转化就要转化成人最方便理解的形式,那就是三维坐标。

自由度理解

首先要明确的是,这些参数的含义究竟是什么。

如果在根节点ROOT建立全局坐标系,把OFFSET都作为相对这个全局坐标系的向量,那么仅凭HIERARCHY的信息是可以画出一个基本的骨架的。把这个骨架图起个名字叫 G 0 G_0 G0,后面还要再提到它。这种生成 G 0 G_0 G0的方法理论上没有问题,但是不能这么理解。BVH中每个节点都有自己的局部坐标系,所有的变换都是在局部坐标系完成的。只不过在 G 0 G_0 G0中,这些坐标系全部平行,局部坐标就等于全局坐标。

注意,虽然这里我们画出了 G 0 G_0 G0,但这并不是初始的那一帧,只是一个基本的参考。运动信息部分中的每一帧都可以由这一帧的信息和 G 0 G_0 G0唯一地生成,没有记忆性,也就是说每一帧都是独立的。

BVH的每个节点都有3个或6个自由度,这些自由度都是相对于初始坐标系(暨全局坐标系)而言的。平移自由度很好理解,就是沿着三个轴的偏移量;而旋转自由度则需要牵扯到3个点:当前节点O、子节点C、父节点P。如下图

在这里插入图片描述

这里要第一次强调hierarchy的含义了:每个节点的旋转,在自己的坐标系旋转的同时,带动所有子节点和相关骨骼的旋转。可以理解为按照层级从根到叶先后执行旋转,一个节点的局部坐标在旋转之前,始终和其父节点的局部坐标保持平行。

按照这样一个过程,我们来理解一下旋转自由度的含义。在节点 O O O旋转前,其局部坐标系 O x y z Oxyz Oxyz是和 P x y z Pxyz Pxyz完全平行的。三个自由度的含义是先后绕局部的 O z Oz Oz, O x Ox Ox, O y Oy Oy旋转的角度(这里以ZXY顺序为例)。注意,这里的单位是度(°).

旋转的结果不会体现在节点 O O O上,而是体现在 C C C及其后续节点的位移,即向量 O C ⃗ \vec{OC} OC 的旋转。

递归计算

这一部分主要讨论如何利用BVH中给出的信息,计算出每一帧所有节点的三维坐标序列。其核心是坐标变换的递归。

这里要再一次强调hierarchy这个词。递归计算的核心就是对层级结构的利用。

我们知道,如果一个坐标系 p p p旋转之后得到了坐标系 q q q,这一旋转过程的旋转矩阵可以表示为 R p q R_{pq} Rpq,而在这个空间内有一定点 A A A,它在两个坐标系下的坐标分别是 A p A_p Ap A q A_q Aq,那么有如下关系成立:
A p = R p q A q A_p = R_{pq}A_q Ap=RpqAq
这就是坐标变换公式

这里就有问题了。BVH中的旋转是向量在旋转,这个公式中 A A A点根本就是一个定点,怎么能用来计算呢?

其实在前一节,我们赋予了每个点一个单独的局部坐标系,并规定这个坐标系内,直接后继的坐标是不变的。这就是为了将坐标变换和向量旋转等同。可以分几步来理解这个计算过程(以父节点的坐标系为基准):

  1. 转之前的橙色坐标系( O C ⃗ \vec{OC} OC 所在的坐标系)记为 p p p, 转之后的红色坐标系( O C ′ ⃗ \vec{OC^\prime} OC )记为 q q q

  2. 旋转前,所有坐标系都与全局坐标系等同,这就使得 O C p ′ ⃗ \vec{OC^\prime_p} OCp 实质上是 O C ′ ⃗ \vec{OC^\prime} OC 在全局坐标系下的坐标,也就是我们直接可以从坐标序列得出的 V g V_g Vg。旋转后的坐标系下,同一个向量 O C ′ ⃗ \vec{OC^\prime} OC q q q下的坐标实质上是基准帧内该向量的坐标,即 V V V

  3. 于是有了
    V g = R V \boldsymbol{V}_g=R\boldsymbol{V} Vg=RV

我们再来理解递归的过程:在基准帧,当前节点以其父节点为基准执行旋转,得到向量 R n V R_n\boldsymbol{V} RnV,这一向量的坐标是相对其父节点而言的;那么以父节点作为待处理的节点,继续执行这个过程,有了 R n − 1 R n V R_{n-1}R_n\boldsymbol{V} Rn1RnV,以此类推。于是,某一节点的局部坐标到全局坐标的转化矩阵就可以写为
R = R 0 R 1 R 2 ⋯ R n R=R_0R_1R_2\cdots R_n R=R0R1R2Rn

为了不让这个式子看起来太复杂,我没在公式里显式指明旋转矩阵所在节点的从属关系。但是他们之间的关系应为: R i + 1 R_{i+1} Ri+1 R i R_i Ri的子节点。

有了这个关系, R n R_n Rn就可以递归求解。即,当我们知道 R n R_n Rn节点所有祖先节点的旋转矩阵,他们按照上面的顺序乘在一起得到的结果是 R m R_m Rm, 则成立以下式子:
V g = R m R n V \boldsymbol{V}_g=R_mR_n\boldsymbol{V} Vg=RmRnV
式中只有 R n R_n Rn是未知的。

一个很棒的库:bvh-converter

安装和基本使用

最最最实际的问题,当然还是怎么把上面的理论变成程序。这其实包含了两个方向:从 BVH 变成三维坐标,和从三维坐标变成 BVH.

第二个方向牵扯到很多细节上的东西,很难给出统一解答,而第一个方向则是很容易实现的。没错,这里要说的这个库就是做这个方向的转化的。这个库名叫 bvh-converter,其 GitHub 地址是 https://github.com/tekulvw/bvh-converter

十分方便的是,这个库是加入 PyPI 的,这就意味着安装只需要一条命令:

pip install bvh-converter

更方便的是它的使用,你甚至不需要在 Python 文件里导入这个库。安装之后,只需要在命令行或者终端里键入:

bvh-converter <filename>

看到下面的输出,这就意味着转化成功了。
Reading BVH file... Building skeleton... Analyzing frames...
之后,你就会在命令行 / 终端当前目录下得到一个 csv 文件,这个文件就是转化后的三维坐标序列。转化后的 csv 文件的第一行是项目标题,纵向则是时间序列。项目标题除了第一列的时间是 Time 以外,后面的标题格式都是 <joint_name>.<X / Y / Z>,表示原本 <joint_name> 关节的三个坐标。对于 End Site,其格式则是 <joint_name>End.<X / Y / Z>

其他

此外,这个库还有别的用法。如果你安装之后报错说找不到这个库,而 pip list 可以找到这个库,安装是成功的,那么可以试试下面这条命令,指定其作为 Python 库运行:

python -m bvh-converter <filename>

如果你希望同时输出旋转信息,那么用这条命令

bvh-converter -r <filename>

之后你会在当前目录下看到多了两个 csv 文件,一个是三维坐标序列,另一个则是各个关节点的欧拉角序列(也就是 bvh 里面存储的那个)。

The End

感谢评论区朋友的补充呀,补充了 bvh-converter 这个库的用法。

文章内容依然是基于我个人理解,如有错误,万望指正。

开学了,要收拾好心情:)

  • 34
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 34
    评论
### 回答1: 可以使用软件工具进行BVH格式到BIP格式转换。例如使用Autodesk Maya软件中的"Import BVH"功能导入BVH文件,然后使用"Export Selected"功能导出为BIP格式。也可以使用其他专业的骨骼动画转换软件如Houdini, MotionBuilder等。 ### 回答2: BVH是一种常用的动作捕捉数据格式,而BIP是一种专门用于3D动画软件的骨骼动画格式。因此,要将BVH格式转换为BIP格式,需要进行以下步骤: 1.准备工作:首先需要准备一个3D动画软件,例如Autodesk 3ds Max或者MotionBuilder。这些软件都支持BIP格式的导入和导出。 2.导入BVH文件:使用所选的3D动画软件,导入BVH格式的文件。在导入过程中,软件会将BVH文件中的层次结构和动作数据转换为相应的骨骼和动画轨迹。 3.调整骨骼:确认BVH文件成功导入后,可能需要对骨骼进行调整,以适应目标BIP格式。这可能涉及到对骨骼名称、层级结构或者骨骼的旋角度进行修改。 4.调整关键帧:由于BVH和BIP格式之间的差异,需要对动画数据进行调整,使其适应BIP格式的要求。这包括消除非法动作或关键帧,并确保动作流畅地在BIP格式的骨骼上播放。 5.导出BIP文件:完成上述调整后,通过选择导出选项,将骨骼以BIP格式导出为新的文件。在导出过程中,选择适当的选项来确保输出文件符合BIP格式规范。 总结起来,将BVH格式转换为BIP格式需要导入BVH文件、调整骨骼和关键帧,并最终将其导出为BIP格式的文件。这样可以使BVH格式的动作数据能够在BIP格式的骨骼动画软件中使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值