- 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