Kinect2.0获取关节姿态(Joint Orientation)
- Bones Hierarchy
骨骼层次结构从SpineBase作为根节点开始,一直延伸到肢体末端(头、指尖、脚):
层级结构如下图所示:
通过IBody::GetJointOrientations函数可以获取到关节的姿态:
HRESULT = pBody -> GetJointOrientations(_countof(joints), jointOrientations);
关节姿态是一个结构体,其中包含了代表姿态的四元数部分:
typedef struct _JointOrientation { JointType JointType; Vector4 Orientation; // quaternion } JointOrientation;
这里要搞清楚很关键的一点就是姿态是相对于哪个坐标系来描述的以及坐标系是如何定义的。网上说法不一(根本就找不到一个官方的解释...),MSDN论坛上有些人说是相对于父节点来描述的,那样的话要获得某一节点的绝对姿态必须遍历骨骼层次结构直到根节点,并将遍历路径上的旋转矩阵(四元数)相乘,以获得相对于固定坐标系的姿态矩阵. To calculate the absolute orientation of each bone, multiply the rotation matrix of the bone by the rotation matrices of the parents (up to the root joint). 不过也有讨论说这个姿态就是摄像机坐标下的,而不是相对于父节点的。如果是这样的话就省去了很多中间计算步骤。下面进行测试来看看关节姿态到底是怎么描述的:
1. 末端节点(Head、HandTip、Thumb、Feet)不含有姿态信息,这些关节返回的四元数各分量都为0:
2. 所有的关节姿态描述都以摄像机坐标系为参考,当人体站正朝向Kinect时SpineBase关节处的坐标系如下图所示。此时返回的关节四元数理论上应为(w,x,y,z)=(0,0,1,0),对应的Z-Y-X欧拉角为(180°,0,180°)或(0,180°,0)
站正后进行测试,输出SpineBase关节的四元数,可以看出与理论结果很接近:
下面我保持身体竖直,绕着从头顶到脚底的轴线(Y轴)旋转一定角度,将SpineBase关节的姿态四元数转换成欧拉角并记录在CSV文件中。下图是根据原始数据绘制的曲线图,可以看出我在绕Y轴旋转身体时X轴和Z轴角度是没有太大变化的(由于Kinect精度所限和各种噪声干扰也不可能一直是180°),而Y轴角度数据有明显的线性增长趋势,对应了我身体的匀速转动:
3. 关节坐标系的Y轴沿着骨骼的方向,Z轴为骨骼转动轴( Z-axis points to the direction that makes sense for the joint to rotate),X轴与Y轴和Z轴垂直,构成右手坐标系:
- Bone direction(Y green) - always matches the skeleton.
- Normal(Z blue) - joint roll, perpendicular to the bone
- Binormal(X red) - perpendicular to the bone and norma
比如对于肘关节和膝关节来说,只有一个转动自由度,因此Z轴(平行于冠状轴)朝向身体的两侧,关节带动骨骼绕着Z轴旋转,如下图所示:
当站正朝向kinect时,右肘关节的姿态四元数理论上应为(w,x,y,z)=(0, 0.707, 0, 0.707),下面是站正测试得到的实际值,可以看出还算比较接近:
另外也可以在Kinect Studio中的Monitor 3D View界面上进行设置来查看关节姿态信息:
关节箭头显示的方向就是法向,即旋转轴的指向:
可以看出肩关节和髋关节的Z轴都是指向身体前方。有了这些关节姿态信息我们就可以方便的控制虚拟人物或者实体机器人(当然得到每个关节的三位坐标点然后计算关节夹角也可以)。
参考:
Adventures in Motion Capture: Using Kinect Data (Part 1)
Adventures in Motion Capture: Using Kinect Data (Part 2)
Adventures in Motion Capture: Using Kinect Data (Part 3)
How to interpret JointOrientation data