NiTE2 基本使用


NiTE(官網)是 PrimeSense 針對 OpenNI 這個深度感應器程式開發 Framework 所推出的一套 middleware,他主要的功能,包括了使用者的偵測、人體骨架的分析與追蹤、手部的追蹤、姿勢手勢辨識等等。

在 OpenNI 1.x 的時候,雖然 OpenNI 是提供了一個開放的框架,讓開發者自行根據規格來實作各自的 middleware;但是實際上,到最後還是只有 NiTE 這一套而已…或許是這個原因,在 OpenNI 2 的新架構下,OpenNI 的框架不再去定義 middleware 的介面和功能,而是把本來屬於 plug-in 的 middleware,改成讓使用者直接去使用的函式庫的形式。

在這種模式下,OpenNI 2 的 middleware library 的功能變得更自由,不再被 OpenNI 定義的介面綁死,在開發上也更彈性了~而在 OpenNI 2 發布的同時,也就已經有不少由其他開發者提供的 middleware library 跟著一起上線了(連結)~

而當然,PrimeSense 還是有持續維護他們的 NiTE、針對 OpenNI 2 推出新的 NiTE 2(連結),繼續提供本來就有的手部、骨架追蹤,以及姿勢和手勢的偵測。不過由於整個架構的改變,使用方法和 OpenNI 1.x 的時候也有很大的差別;這邊,就大概來講一下怎麼在 OpenNI 2 的架構下,使用 NiTE 2 吧~


專案設定

首先,在專案設定的部分,要設定的項目和 OpenNI 2 基本上是相同的,包括了:

  • 「C/C++」的「Gerenal」(一般)裡的「Additional Include Directories」(其他 Include 目錄)要加上 $(NITE2_INCLUDE)$(NITE2_INCLUDE64)

  • 「Linker」(連結器)的「Gerenal」(一般)裡的「Additional Library Directories」(其他程式庫目錄)要加上 $(NITE2_LIB)$(NITE2_LIB64)

  • 「Linker」(連結器)的「Input」(輸入)裡的「Additional Dependencies」(其他相依性)要加上 NiTE2.lib

比較完整的圖文設定說明,請參考《OpenNI 2 基本程式範例》一文,基本上,只是修改要甜的東西、把 OpenNI2 改成 NITE2 而已。不過另外要注意的就是,由於 NiTE 會使用到 OpenNI,所以本來 OpenNI 2 的設定也是需要加上去的

再來,就是和 OpenNI 2 一樣,在程式執行的時候,會需要使用到 NiTE 的 Redist 目錄(預設是在 C:\Program Files\PrimeSense\NiTE2\Redist)下的檔案,所以也是一樣,需要讓程式找到的這些檔案。也因為會同時需要 OpenNI 2 和 NiTE 2 兩個函式庫的 Redist 資料夾,Heresy 會建議把這兩個資料夾的檔案,複製出來、放到同一個資料夾,然後把這個資料夾設定成為這個專案的「Working Directory」(工作路徑),這樣程式才可以正常執行;如果沒有處理好的話,可能就會出現類似下面的錯誤訊息:

Failed to initialize OpenNI
        Found no files matching '.\OpenNI2\Drivers\*.dll'
Could not find data file .\NiTE2/s.dat
current working directory = C:\Program Files\OpenNI2\Redist

如果遇到「遺失 dll」的錯誤訊息,或是執行時有上面的錯誤訊息的話,請確認程式工作路徑下,要有下列的檔案:NiTE.iniNiTE2.dllOpenNI.iniOpenNI2.dllPS1080.ini ,以及 NiTE2OpenNI2 這兩個資料夾。這些檔案,基本上都是在 OpenNI 和 NiTE 的 Redist 資料夾裡面的。


基本架構

NiTE 2 的架構、和使用概念,基本上都和 OpenNI 2(請參考《OpenNI 2 簡介》)非常地相似,所以如果已經知道 OpenNI 2 的程式怎麼寫,應該很容易就可以上手。比較大略性的來看,會使用來控制的類別,主要包括了:

  • nite::NiTE

    NiTE 2 的整體環境控制的類別,基本上是用來控制 NiTE 的初始化和停止。

    openni::OpenNI 一樣,他所有的函示都是 static 的,使用時不需要實體化變數出來。

  • nite::UserTracker

    用來追蹤使用者的類別,包括了使用者的管理,以及骨架追蹤、姿勢偵測等功能;性質和 OpenNI 1.x 的 User Generator 類似。

    讀取出來的資料類型,是 nite::UserTrackerFrameRef

  • nite::HandTracker

    用來進行手部追蹤的類別,除了追蹤手部位置外,也包含了手勢的偵測。基本上算是把 OpenNI 1.x 的 Hands Generator 和 Gesture Generator 的功能加在一起。

    讀取出來的資料類型,是 nite::HandTrackerFrameRef

基本上,NiTE 只又在程式開始、結束的時候需要用到,中間基本上是用不到的;使用概念和 openni::OpenNI 一樣。而 UserTrackerHandTracker 的使用概念,則也和 openni::VideoStream 相似。更完整的說明,可以參考官方的文件,檔案預設是在 C:\Program Files\PrimeSense\NiTE2\Documentation


基本使用

NiTE 2 雖然需要 OpenNI 2 的功能(NiTE.h 就會去使用 OpenNI.h),但是實際上,如果只是單純要使用 NiTE 所提供的功能的話,在程式碼裡面,是可以完全不出現 OpenNI 的東西的~他最基本的使用流程,大致如下:

  1. include NiTE.h 這個 header 檔,之後 NiTE C++ API 的東西,都會在 nite 這個 namespace 下。

  2. 呼叫 nite::NiTE::initialize() 來進行整個 NiTE 環境的初始化。

  3. 宣告出一個 NiTE 的物件,如果是要做使用者/骨架的追蹤的話,就是使用 nite::UserTracker,如果是要做手部相關的處理的話,則是用 nite::HandTracker

    之後再透過他所提供的 create() 函式,來完成 NiTE Tracker 的建立。

    • create() 這個函式有一個參數,可以指定要使用哪一個 openni::Device,如果不指定的話,NiTE 會自己去找一個可以用的,自己開啟來使用。

  4. 和 OpenNI 的 VideoStream 不同,NiTE 2 提供的兩個 Tracker,都沒有 start()stop() 的函示可以用來控制開始和結束。所以要使用的話,就是直接進入主迴圈,透過 readFrame() 這個函式,來取得對應的 frame reference(nite::UserTrackerFrameRefnite::HandTrackerFrameRef);而之後會用到的資料,基本上都在讀取到的 frame reference 中。

  5. 程式結束時,呼叫 Tracker 的 destory() 函式,把 Track 關掉。

  6. 最後,呼叫 nite::NiTE::shutdown(),關閉整個 NiTE 環境。


簡單的範例

上面算是概要性的講了一下 NiTE 2 要怎麼使用,接下來,則是一個極簡單的 NiTE 的範例。在這個範例程式裡面,基本上是直接去使用 NiTE2 的 UserTracker 來進行使用者的追蹤,完全不會直接使用到 OpenNI 的介面。

// STL Header
#include <iostream>
 
// 1. include NiTE Header
#include <NiTE.h>
 
// using namespace
using namespace std;
 
int main( int argc, char** argv )
{
  // 2. initialize NiTE
  nite::NiTE::initialize();
 
  // 3. create user tracker
  nite::UserTracker mUserTracker;
  mUserTracker.create();
 
  nite::UserTrackerFrameRef mUserFrame;
  for( int i = 0; i < 300; ++ i )
  {
    // 4. get user frame
    mUserTracker.readFrame( &mUserFrame );
 
    // 5. get users' data
    const nite::Array<nite::UserData>& aUsers = mUserFrame.getUsers();
    for( int i = 0; i < aUsers.getSize(); ++ i )
    {
      const nite::UserData& rUser = aUsers[i];
      if( rUser.isNew() )
        cout << "New User [" << rUser.getId() << "] found." << endl;
      if( rUser.isLost() )
        cout << "User [" << rUser.getId()  << "] lost." << endl;
    }
  }
  nite::NiTE::shutdown();
 
  return 0;
}

可以看到,整個流程基本上和 OpenNI 2 非常的相近,最大的差別,就在於 UserTracker 讀取到的資料,是 UserTrackerFrameRef 的形式,資料的存取方法和 OpenNI 的 VideoStream 不同而已。

像在個範例面,Heresy 就是先透過 UserTrackerFrameRefgetUsers() 這個函式,來取得使用者的列表;這邊的列表,會是一個陣列 nite::UserData 的陣列(和 OpenNI 2 一樣,NiTE 2 又自己定義一個 Array…他們完全沒有想過可以直接用 OpenNI 2 寫好的,或直接用 STL 現成的嗎? orz),裡面儲存的是目前偵測到的所有使用者。

不過由於這篇文章 Heresy 還不會仔細提 UserTrackerFrameRef 的各項功能細節,所以這邊就只有先使用他提供的 isNew()isLost() 這兩個函式,來判斷這個使用者是剛被偵測到?還是不見了。包括骨架追蹤在內的細節,就等之後的文章再來說明了。

另外,如果要進行錯誤偵測的話,基本上也和 OpenNI 2 的方法(參考《OpenNI 2 的錯誤處理》)類似,只是回傳的狀態型別從 openni::Status 變成 nite::Status 而已。


這篇算是 NiTE2 的基本概論,大致上就先到這邊了。接下來應該是還會再花時間,針對 UserTrackerHandTracker 做進一步的說明(希望還有時間繼續寫下去…)。


OpenNI / Kinect 相關文章目錄

廣告

對「NiTE2 基本使用」的想法

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.