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)。

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


OpenNI / Kinect 相關文章目錄

對「NiTE 2 的手部追蹤」的想法

  1. 新手發問:
    請問一下在vs2012跑這個範例時,在5b 跟 6這兩個地方的 Point3f&
    都有出現錯誤error C2872: ‘Point3f’ : 模稜兩可的符號的訊息,請問該怎麼解決呢?
    謝謝

    • 這個錯誤應該是因為有其他同樣命名為 Point3f 的 class 造成的。
      你還有 include 其他 header 檔嗎?有可能是你用的其他函式庫,也有同名的類別,所以會造成編譯器不知道該用哪個。(例如:OpenCV)
      如果是這個狀況的話,請不要用 using namespace 的方法省略 namespace 就可以了。

  2. Heresy您好:
    我想請問一下,一定要手勢偵測才能偵測手部的位置嗎?

    我有嘗試把手勢偵測拿掉,可是他就偵測不到手部了。

    • 文中有說:「要先偵測到手的位置,然後再針對這個位置進行追蹤」
      如果你知道手的位置所在,也可以強制指定從該點開始追蹤。

  3. 您好 H大大
    請問這個NITE2 手部追蹤的程序 是否可以改為簡單的滑鼠模擬事件 ?
    是否可以像在之前的這篇 <>中一樣加入CVMouse 這個 class ?
    我是初學者 希望H大大可以給我一點提示 ;)
    謝謝

  4. […] PrimeSense 的 NiTE 主要是提供了人的骨架追蹤,以及手部追蹤的功能,基本上應該算是在 OpenNI 這個架構下,最重要、也最常被使用的 middleware library 了。不過由於他的手部追蹤的功能,僅能提供位置的追蹤、和簡單的動態手勢辨識,並沒有辦法去針對手的狀態、或是手指作分析,算是比較可惜的地方。 […]

  5. […] 這篇,算是簡單的概念實作測試吧…Heresy 是試著在 OpenCV 的環境下,透過 NiTE 的手部追蹤的功能,來時做體感的按鈕。由於只是概念實作,所以在圖形的部分,算相當地簡單就是了~如果有需要的話,也可以自己根據需求作加強。 […]

發表留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料