Home People Research Blog Courses Links Search Download
NCHC

Blog

Blog 最新文章

  1. 提供新版 Edge 的 HoloLens 2 Insider Preview
    2021/01/20 08:55
  2. Facebook Oculus Quest 2 開箱文
    2021/01/13 14:19
  3. GitLab 手動執行 pipeline 的預輸入變數
    2021/01/04 11:14

Blog 最新回應

  1. 謝謝你提供的資訊...
    2021/01/17 17:40
  2. MSVC 也是有在進步的 XD...
    2020/12/24 15:55
  3. “如果不想另外定義一個 struct 的........
    2020/12/24 15:49

Keyword 關鍵字

3D立體 Kinect Valve Index Docker iFlyover javascript MR Java 開放資料 CubeX HTC Vive svn CUDA 開放資料 OpenXR VR Pandas Pandas VR C++14 Python OpenNI2 HTC Vive Pro C++17 OpenNI NiTE2 OpenGL PHP GitLab C++ 3d print Oculus OpenMP Python HoloLens 2 Boost HTC Vive Focus 資料視覺化 資訊地圖 OpenCL C++14 C++11 Oculus Rift S Oculus Quest 2 Vulkan Qt Docker xml Windows MR WebGL OpenCV ASUS Xtion C++20 OpenVR git

類別:技術相關 » 技術研究
文章發表|我要回應|RSS訂閱

不用校正姿勢的 NITE 1.5

前一陣子前有提過了,PrimeSense 在新推出的 1.5.x 的 NITE 中,終於讓 user generator 可以不需要擺出 Psi 校正姿勢、就直接進行人體的骨架追蹤了∼如此一來,要用 Kinect 透過 OpenNI 來做人體的骨架追蹤,在程式的撰寫上就可以稍微簡單一些了!而這一篇,就大概來提一下,新版 user generator 要怎麼用吧∼

不過在開始之前,建議請先回去大概看過之前的介紹文章,這樣應該會比較有些概念:

  • 透過 OpenNI / NITE 分析人體骨架(上)、透過 OpenNI / NITE 分析人體骨架(下)
  • 使用 Qt 顯示 OpenNI 的人體骨架
  • OpenNI 人體骨架分析部分補充、OpenNI XnSkeletonJointOrientation 簡單分析
舊有程式可以不用改

首先很重要的,新的 user generator 提供了不用校正姿勢的人體骨架追蹤後,已經寫好、要使用 psi 校正姿勢的程式還可以用嗎?要不要修改呢?答案是不用,舊有的程式都還是可以再不修改程式碼的情況下,正常運作的!以之前《使用 Qt 顯示 OpenNI 的人體骨架》一文的範例程式(下載)來說,不但程式碼可以不用修改,就連編譯好的執行檔,也都還是可以直接執行、使用的∼

而此時,之前偵測到新的使用者後、需要此用 Pose detection 來偵測 Psi 校正姿勢、並進行骨架校正的 callback function,也同樣都會被正常地執行到。不過相對的,舊有的程式在沒有經過修改的情況下,要進行骨架追蹤,應該還是需要擺出骨架校正的 Psi 姿勢的;不過,現在要的 Psi 判定變成非常地簡單、而且校正的也相當地快速,所以其實還是滿方便的∼

新的程式比較簡單

而如果希望不用擺出特定校正姿勢的話,新的程式要怎麼寫呢?Heresy 這邊是根據官方的 NiUserTracker 這個範例,來做簡化以及修改的。

首先,如果想要知道目前系統的 User Generator 所提供的 Skeleton Capability 是否有提供不需要特定校正姿勢的骨架追蹤的話,可以使用 Skeleton Capability 的 NeedPoseForCalibration() 這個函式來做確認。大致用法就是像下面這樣:

xn::UserGenerator mUser;
// ....
bool bNeedPose = mUser.GetSkeletonCap().NeedPoseForCalibration();

而如果確定 Skeleton Capability 有支援不需要特定校正姿勢的話,就可以省略掉 Pose Detection 部分的程式了∼新的流程,大致會如下圖所示:

雖然好像還是要很多步驟,但是實際上和之前還需要使用 Pose Detection 的方法相比(流程圖),其實已經算是簡化相當多了∼而實際上,雖然上面的流程圖裡有四個 callback function(New User、Lost User、Calibration Start、Calibration End),但是實際上,有必要一定要實作的,就只有 New User 和 Calibration End 這兩個而已。

如此一來,本來《透過 OpenNI / NITE 分析人體骨架(上)》中的範例程式,則可以簡化如下:

#include <stdlib.h>
#include <iostream>
#include <vector>

#include <XnCppWrapper.h>

using namespace std;

// callback function of user generator: new user
void XN_CALLBACK_TYPE NewUser( xn::UserGenerator& generator,
XnUserID user,
void* pCookie )
{
cout << "New user identified: " << user << endl;
generator.GetSkeletonCap().RequestCalibration( user, true );
}

// callback function of skeleton: calibration end
void XN_CALLBACK_TYPE CalibrationEnd( xn::SkeletonCapability& skeleton,
XnUserID user,
XnCalibrationStatus eStatus,
void* pCookie )
{
cout << "Calibration complete for user " << user << ", ";
if( eStatus == XN_CALIBRATION_STATUS_OK )
{
cout << "Success" << endl;
skeleton.StartTracking( user );
}
else
{
cout << "Failure" << endl;
skeleton.RequestCalibration( user, true );
}
}


int main( int argc, char** argv )
{
// 1. initial context
xn::Context mContext;
mContext.Init();

// 2. create user generator
xn::UserGenerator mUserGenerator;
mUserGenerator.Create( mContext );

// 3. Register callback functions of user generator
XnCallbackHandle hUserCB;
mUserGenerator.RegisterUserCallbacks( NewUser, NULL, NULL, hUserCB );

// 4. Register callback functions of skeleton capability
xn::SkeletonCapability mSC = mUserGenerator.GetSkeletonCap();
mSC.SetSkeletonProfile( XN_SKEL_PROFILE_ALL );
XnCallbackHandle hCalibCB;
mSC.RegisterToCalibrationComplete( CalibrationEnd, &mUserGenerator, hCalibCB );


// 5. start generate data
mContext.StartGeneratingAll();
while( true )
{
// 6. Update date
mContext.WaitAndUpdateAll();

// 7. get user information
XnUInt16 nUsers = mUserGenerator.GetNumberOfUsers();
if( nUsers > 0 )
{
// 8. get users
XnUserID* aUserID = new XnUserID[nUsers];
mUserGenerator.GetUsers( aUserID, nUsers );

// 9. check each user
for( int i = 0; i < nUsers; i )
{
// 10. if is tracking skeleton
if( mSC.IsTracking( aUserID[i] ) )
{
// 11. get skeleton joint data
XnSkeletonJointTransformation mJointTran;
mSC.GetSkeletonJoint( aUserID[i], XN_SKEL_HEAD, mJointTran );

// 12. output information
cout << "The head of user " << aUserID[i] << " is at (";
cout << mJointTran.position.position.X << ", ";
cout << mJointTran.position.position.Y << ", ";
cout << mJointTran.position.position.Z << ")" << endl;
}
}
delete [] aUserID;
}

}
// 13. stop and shutdown
mContext.StopGeneratingAll();
mContext.Release();

return 0;
}

在上面的程式碼中,NewUser() 這個就是在偵測到有新的使用者時,會被執行的 callback function;而內容呢,就是直接去呼叫 xn::SkeletonCapability 的 RequestCalibration() 函式、要求他對於偵測到的新使用者(user)進行骨架的校正。

而接下來,xn::SkeletonCapability 就會試著去分析使用者的骨架、並進行校正的工作,等到骨架校正的動作完成後,就會呼叫 CalibrationEnd() 這個 callback function。而它的內容和本來的很接近,就是要先判斷骨架校正的結果是否正常(XnCalibrationStatus 應該要是 XN_CALIBRATION_STATUS_OK),如果正常的話,就是接著透過 xn::SkeletonCapability 的 StartTracking() 函式、開始追蹤 user 的骨架;而如果失敗的話,則是重新透過 RequestCalibration()、要求 xn::SkeletonCapability 再度對 user 進行骨架的校正。

所以實際上,新的人體骨架的追蹤架構,其實主要就是省略掉 Pose Detection 的部分而已了∼再來,就是 NITE 內部的實作應該也做了不少修改,所以在效率上也好了不少。

而上面的程式,基本上是只有用 standard output 來輸出結果而已,並沒有任何的圖形介面;如果希望看到有畫面的範例程式的話,請參考這個使用 Qt 來做圖形介面的範例,這隻程式基本上是根據《使用 Qt 顯示 OpenNI 的人體骨架》一文的範例程式修改而成的,在這邊就不多做說明了。


這篇就寫到這了。話說,本來 Heresy 一直以為新版的 OpenNI 和 NITE 應該會在偵測到 user 後,就自動做骨架的校正、而不必額外再去做設定;不過現在看來,至少還是要自己去要求 xn::SkeletonCapability 進行骨架的校正與追蹤的。

想想,其實這也算是合理的。畢竟,不是每個時候都有需要去知道畫面內的使用者的骨架,如果 OpenNI 每次都直接做掉的話,其實只會增加許多無謂的計算;而現在這樣可以控制,也算是比較好的方法了∼

張貼者:heresy於2011/12/06 15:57 下午有2則回應,瀏覽次數:4,127次
林雄民 於 2012/02/28 15:03 下午 回應:
您好,又来打扰您了~很高興
第四步:
// 4. Register callback functions of skeleton capability
xn::SkeletonCapability mSC = mUserGenerator.GetSkeletonCap();
mSC.SetSkeletonProfile( XN_SKEL_PROFILE_ALL );
XnCallbackHandle hCalibCB;
mSC.RegisterToCalibrationComplete( CalibrationEnd, &mUserGenerator, hCalibCB );

我仿照您的代码,自己写了个类,刚开始在类里面的一个叫capture()的成员函数上照搬您上面的代码,编译通过。

但是,但是。。


我试着将您这里的mSC作为类的成员函数(private),其余的代码还是放在capture()

这样,编译的时候报错:
no matching function for call to ‘xn::SkeletonCapability::SkeletonCapability

然后系统会自动把错误光标指向我的类的构造函数。

要是把mSC=mUserGenerator.GetSkeletonCap();放在构造函数里面。其余不变,还是报错。

您知道是怎么回事吗?是xn::SkeletonCapability声明之后必须初始化吗?
即xn::SkeletonCapability mSC = mUserGenerator.GetSkeletonCap();
作者作者heresy 於 2012/02/29 09:35 上午 回應:
to 林雄民

建議請參考 OpenNI 的 API Reference。
OpenNI 的 Capability 都沒有 default constructor,必須要在宣告變數時同時初始化。

-- TOP --

我要回應
* 身份  訪客 (暱稱:)
 本篇文章作者 (帳號:密碼:)
* 內容      
很高興 悲傷 震驚 疑惑 大笑 發瘋 傷心
* 留言密碼 (請輸入下方圖片中去除前、後位數的數字,共五碼。)
說明 1. * 表示必填欄位。
2. 不支援HTML Tag。
   

-- TOP --

© Visualization and Interactive Media Laboratory of NCHC, 2007 - 2021, All Rights Reserved. Contact E-mail