NiTE 2 的手部追蹤

這篇是延續前一篇的《NiTE 2 的手勢偵測》,繼續來講 NiTE 2 所提供的手部追蹤功能。NiTE 2 所提供的手部追蹤功能,和手勢偵測一樣,是由 HandTracker 提供的,而在使用上則是和在 OpenNI 1.x 的時候(參考)一樣,都是要先偵測到手的位置,然後再針對這個位置進行追蹤;所以一般在使用上,大多是搭配手勢偵測,找到手的位置後,再開始追蹤。

而寫成程式的話,基本上就會是像下面這樣子:

// STL Header
#include <iostream>
#include <vector>
 
// 1. include NiTE Header
#include <NiTE.h>
 
// using namespace
using namespace std;
using namespace nite;
 
int main( int argc, char** argv )
{
// 2. initialize NiTE
NiTE::initialize();
 
// 3. create hand tracker
HandTracker mHandTracker;
mHandTracker.create();
 
// 4. set gesture
mHandTracker.startGestureDetection( GESTURE_WAVE );
mHandTracker.startGestureDetection( GESTURE_CLICK );
mHandTracker.startGestureDetection( GESTURE_HAND_RAISE );
 
// main loop
for( int i = 0; i < 3000; i )
{
// 4. get new frame
HandTrackerFrameRef mHandFrame;
mHandTracker.readFrame( &mHandFrame );
 
// 5a. get gesture data
const Array<GestureData>& aGestures = mHandFrame.getGestures();
for( int i = 0; i < aGestures.getSize(); i )
{
// 5b. start hand tracking
const Point3f& rPos = aGestures[i].getCurrentPosition();
HandId mHandID;
mHandTracker.startHandTracking( rPos, &mHandID );
cout << "Found hand and start tracking" << endl;
}

// 6. Get hands data
const Array<HandData>& aHands = mHandFrame.getHands();
for( int i = 0; i < aHands.getSize(); i )
{
const HandData& rHand = aHands[i];
cout << "Hand " << rHand.getId();
if( rHand.isNew() )
cout << " Start tracking";
else if( rHand.isLost() )
cout << " Lost";
 
if( rHand.isTracking() )
{
const Point3f& rPos = rHand.getPosition();
cout << " at " << rPos.x << ", " << rPos.y << ", " << rPos.z;
}
cout << endl;
 
if( rHand.isTouchingFov() )
cout << "  Touch FOV" << endl;
}

}
 
// 6. shutdown
mHandTracker.destroy();
NiTE::shutdown();
 
return 0;
}

上面的範例程式,在大架構下都和之前的手勢偵測的相同,有改到的地方,基本上就是主迴圈內,也就黃底(5 和 6)的部分了。

首先,在偵測到手勢之後,如果要開始追蹤這支手,就是要去呼叫 HandTrackerstartHandTracking() 這個函式,要求 NiTE 開始追蹤現在這個點。這個函式需要兩個參數,第一個就是要追蹤的位置,基本上就是直接把偵測到手勢的位置(rPos)給他就可以了;而第二個參數,則是輸出用的,它可以用來知道現在開始追蹤的手的編號(HandID),可以做之後的管理之用。

接下來,則是透過 HandTrackerFrameRefgetHands() 這個函式,來取得目前有再追蹤的手的陣列;其中,每一個手的資料,都是用 HandData 這個型別來儲存的。HandData 有提供六個函式,可以用來取得手部的相關資料,透過 getId() 可以取得手的編號(就是前面 startHandTracking() 的編號),而透過 getPosition(),則可以取得手部目前現在的位置。

而除了這兩個 get 的函式外,他還提供了 isNew()isLost()isTracking(),可以用來判斷這隻手的狀態。另外比較特別的,是它還有提供一個 isTouchingFov() 的函式,可以用來判斷手部是否已經碰到攝影機視角的邊緣,在許多時候,也是相當有用的~

上面的範例程式在執行後,會在偵測到手勢後,就自動開始做手部的追蹤,並把手部的位置做文字的輸出。而由於有針對 GESTURE_HAND_RAISE 做偵測,所以應該手隨便動一下,就會開始偵測了。而開始追蹤後,就會一直輸出手部所在的位置,直到手離開畫面、被判定已經停止追蹤(lost)。

至於有圖形介面的範例,就等之後有時間再補上吧。

16 thoughts on “NiTE 2 的手部追蹤”

  1. 博主,如果用OpenCV画出手的运动轨迹,能否给个思路呢

  2. heresy大大你好。我看了你的文章学习到了好多东西,表示万分的感谢。最近想接触一下NiTE2,不过OPENNI官网的支援好像有点问题,完全上不去。能不能请大大你分享一下NiTE2呢?

  3. to the2ndapple,
    国外有团队支持哦~http://structure.io/openni:lol:

  4. to heresy
    果然是这样,之前还不敢相信哦。那请问大大现在哪里还能下载到NiTE2?现在有在做一个关于kinect的手部跟踪设计,需要用到这个呢,如果不使用NiTE2的部件的话还有其他的实现方法么?

  5. to chao
    首先谢谢这位大大提供的网站,我有进去浏览过,但是这个网址只有提供openni,这个是我有的。我现在需要的NiTE2,这个东西不是开源的,GitHub上面也找不到。所以来问问哪里可以能够获取NiTE2.

  6. to the2ndapple

    PrimeSense NiTE 的授權協議內包含了不可自行散佈,所以基本上,現在應該已經沒有正式的管道可以取得了。
    有需要的話必須自己去找有沒有人有放備份的下載;不過基本上這個行為是侵權的。

  7. 想請問Heresy 神大
    有兩手偵測位置放大縮小 的教學嗎?
    感恩大大 指導

  8. 您好,您说開始手部追蹤後,就會一直輸出手部所在的位置,直到手離開畫面、被判定已經停止追蹤,可是我检测时手挥动完,手臂下垂到一定程度时,就会丢失被跟踪的手部,停止输出坐标,怎么回事?

  9. to Avril

    幾種可能:
    1. 你的手已經超出螢幕範圍了
    2. 你的手有一段時間都沒有動、所以被判定已停止
    3. 手部和其他深度相近的東西過於靠近,導致無法繼續追蹤

  10. 非常感谢您的回复,如果是第3种情况,有没有什么好的解决方法,当手与物体接近时,仍能追踪到手的坐标。

  11. to Avril

    基本上,除非要自己針對這種狀況去設計新的演算法,否則應該無解。
    如果深度過近的話,從深度圖上就已經無法區分出哪邊是要追蹤的區域了,自然沒辦法繼續追蹤。

發佈回覆給「the2ndapple」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。