透過 OpenNI / NITE 分析人體骨架(下)

延續上一篇,這一篇主要就是把之前礙於篇幅而先跳過的部分,做個完整的說明了∼而基本上,主要的內容會分兩大部分,第一部分是「Callback Function 的細節」,來講設定 callback function 的細節;第二部分,則是「讀取骨架資料」、也就是之前 main() 裡面迴圈裡的程式了。

而在文章的最後,還有一小段,是大概描述一下這個程式執行後的狀況。

Callback Function 的細節

User Generator

在「5. Register callback functions of user generator」的部分,是使用 xn::UserGenerator 的成員函式 RegisterUserCallbacks(),來進行 callback function 的「註冊」(register);這個函式他有四個參數,他們的型別和意義分別是:

  • UserHandler NewUserCB:偵測到新使用者的 callback function
  • UserHandler LostUserCB:使用者消失的 callback function
  • void* pCookie:額外傳遞給 callback function 使用的資料
  • XnCallbackHandle& hCallback:管理 callback function 用的 handle 值,如果要取消 callback function 設定時,需要用到這個變數。

而在這裡,我們給他註冊的兩個 callback function,就是之前定義的 NewUser()LostUser(),由於這兩個 callback function 都不需要其他的資料,所以 pCookie 就直接給他 NULL 就可以了;而最後的 callback handle,雖然在這個程式裡沒有打算取消註冊(unregister),但是還是需要給他一個變數來儲存(這邊就是 hUserCB)。

其中,在 callback function 的部分,NewUser()LostUser() 在被呼叫的時候,都會取得三個變數:xn::UserGenerator& generatorXnUserID uservoid* pCookie

其中第一個參數 generator 就是 user generator 本身、也就是 main() 裡面所建立出來的 mUserGenerator;而 user 則是代表目前新抓到的使用者,當場景裡有大於一個使用者的話,就是要靠這個 XnUserID 來做識別了∼最後的 pCookie 就是在透過 RegisterUserCallbacks() 來註冊 callback function 時的額外參數;不過由於在這個例子裡,並沒有需要額外傳資料進入 callback function,所以他的值會是我們在設定時的 NULL

而在 callback function 本身的內容部分,LostUser() 雖然裡面只有輸出訊息,但是在目前版本的 OpenNI 是不可以省略的;而在 NewUser() 裡,則是會透過 GetPoseDetectionCap() 去取得 pose detection 這個 capability,並使用 StartPoseDetection() 這個函式、來讓他針對目前新抓到的使用者(user)開始進行姿勢偵測。

 

Skeleton Capability

接下來,則是「6. Register callback functions of skeleton capability」的部分;這一部分的程式,是針對 mUserGenerator 的 skeleton capability 來做設定。由於之後對於 skeleton capability 的操作比較頻繁,所以在這邊 Heresy 是先用一個物件 mSC,來做為 skeleton capability 的操作物件;而取得的方法則和其他 capability 類似,是使用 GetSkeletonCap() 這個函式。

而要使用 skeleton capability 前,也還要使用 SetSkeletonProfile() 這個函式,來設定所謂的「skeleton profile」,決定要使用那些關節。在 OpenNI 是定義了五種不同的 profile:

  • XN_SKEL_PROFILE_NONE:沒有任何關節。
  • XN_SKEL_PROFILE_ALL:代表所有關節,以目前的 NITE 來說就是 15 個(列表請見前一篇)。
  • XN_SKEL_PROFILE_UPPER:含軀幹(torso)的上半身、 以目前的 NITE 來說總共是九個關節。
  • XN_SKEL_PROFILE_LOWER:含軀幹(torso)的下半身、 以目前的 NITE 來說理論上要有七個關節。(注意!以程式內的註解來看,應該是要包含 torso 共七個,不過 Heresy 自己試著用 EnumerateActiveJoints() 來做查詢,卻只有列出不含 torso 的六個關節)
  • XN_SKEL_PROFILE_HEAD_HANDS:只有頭和雙手這三個關節。

在這邊,Heresy 是使用完整的「XN_SKEL_PROFILE_ALL」,來抓所有可用的關節。

接下來,就是要註冊 mSC 的 callback function 了。這邊使用的函式,是 xn::SkeletonCapabilityRegisterCalibrationCallbacks(),他和前面 xn::UserGeneratorRegisterUserCallbacks() 類似,都是有包含兩個 callback function 的四個參數:

  • CalibrationStart CalibrationStartCB:開始進行骨架校正的 callback function
  • CalibrationEnd CalibrationEndCB:骨架校正完的 callback function
  • void* pCookie:額外傳遞給 callback function 使用的資料
  • XnCallbackHandle& hCallback:管理 callback function 用的 handle 值

在這邊,所註冊的兩個 callback function,就是在自己定義的 CalibrationStart()CalibrationEnd();而和前面 user generator 時不同,這邊的 pCookie 由於有另外的需要,所以 Heresy 是把目前使用的 user generator 的位址(&mUserGenerator)當作額外的參數,傳進去給 callback function 使用。最後、第四個參數 callback handle 的部分,一樣是要用一個變數來儲存他,在這邊用的就是 hCalibCB

在這樣設定後,當 skeleton capability 開始進行骨架校正的時候,就會去呼叫 CalibrationStart() 這個函式,而當骨架校正完後,則是會再去呼叫 CalibrationEnd() 這個函式。其中,CalibrationStart() 這個函式也是只有輸出資訊而已,並沒有實際的用途(但是在目前的 OpenNI 環境不指定的話,程式的執行會有問題),所以在這邊就不多做說明了。

CalibrationEnd() 這個函式,則是有實際用處的函式,他必須要根據是否有正確地辨識出人體骨架,做出下一階段的動作;而他會接受四個參數,分別是:

  • xn::SkeletonCapability& skeleton:目前所使用的 skeleton capability,在這個例子裡就是 main() 裡面透過的 mUserGenerator.GetSkeletonCap() 取得的 mSC
  • XnUserID user:目前進行骨架校正的使用者。
  • XnBool bSuccess:人體骨架校正校正是否成功。
  • void* pCookie:額外傳遞的資料,由於在註冊 callback function 時是傳入 &mUserGenerator,所以這邊 pCookie 代表的意義,就是一個指向目前使用的 user generator、也就是 mUserGenerator 的指標。

CalibrationEnd() 實際的內容呢,就是先透過 bSuccess 來判斷是否有正確骨架,如果成功的話,就呼叫 skeleton.StartTracking( user ),來要求 skeleton capability 開始進行這個使用者的骨架追蹤;而如果失敗的話,則是要求 pose detectioncapability 重新開始偵測「Psi」校正姿勢,等到偵測到下一次的校正姿勢,再重新開始分析人體骨架。

不過由於 CalibrationEnd() 取得的只有 skeleton capability,並沒有 pose detection capability 的物件,所以要對 pose detection capability 做操作的話,就是要透過額外傳進來的 pCookie 來取得;在這邊,由於傳進來的是 mUserGenerator 的指標,但是由於型別已經被轉型為 void* 了,所以要使用的話,要再透過強制轉型來把他轉回 xn::UserGenerator* 才行。

而實際上,由於在這個範例裡,CalibrationEnd() 只有用到 skeleton capability 和 pose detection capability,而他本身就可以直接取得 skeleton capability,拿不到的只有 pose detection capability,所以其實也可以考慮不是把 user generator 傳進來,而只傳 pose detection capability 也是可以的。

附註:

  • 在官方的 StickFigure 範例裡,是將 user generator 宣告為全域變數,所以在 callback funciton 裡也可以直接存取,而不必用到 pCookie
  • xn::SkeletonCapability 除了 RegisterCalibrationCallbacks() 可以設定兩個 callback function 外,還有 RegisterToJointConfigurationChange() 可以設定另一個 callback function,不過因為這邊用不到,所以就不提了。

 

Pose Detection Capability

這部分的最後,則是「7. Register callback functions of Pose Detection capability」,也就是 pose detection capability 的設定;這邊所用來註冊 callback function的,是 xn::PoseDetectionCapability 的成員函式 RegisterToPoseCallbacks()。其實他和前面 user generator 或 skeleton capability 類似,也是可以註冊兩個 callback function、要指定四個參數:

  • PoseDetection PoseStartCB:偵測到姿勢時會被呼叫的 callback funtion
  • PoseDetection PoseEndCB:當偵測到的姿勢結束的時候會被呼叫的 callback function
  • void* pCookie:額外傳遞的資料
  • XnCallbackHandle& hCallback:管理 callback function 用的 handle 值

而和前面兩項相比,比較特別的一點是,在這個程式裡,我們只註冊了第一個 callback function,也就是 PoseStartCBPoseDetected()!對於第二個 callback function PoseEndCB,在這邊是沒有去使用,而僅只有給他一個 NULL 的。這是由於 PoseEndCB 在這個例子裡面並沒有要做任何事、也沒有任何用處,而且在目前的 OpenNI 版本,可以把它省略而不會有問題。

相較於此,如果把 skeleton capability 的 CalibrationStartCB 省略掉的話,是會導致程式執行到一半當掉的;理論上,這是不該發生問題的,所以只能希望之後 OpenNI 能修正這個問題了。

所以,在這邊執行 RegisterToPoseCallbacks() 註冊 callback function 時,傳進去的四個參數依序為:PoseDetectedNULL&mUserGeneratorhPoseCB;其中後面兩者的意義和設定 skeleton capability 時是相同的,所以在這邊就不多加介紹了。

回到 PoseDetected() 這個函式本身,他在被呼叫時,會接受到四個參數:

  • xn::PoseDetectionCapability& poseDetection:pose detection capability 本身的物件參考,在這邊是等同於 main() 裡面,透過 mUserGenerator.GetPoseDetectionCap() 取得的 pose detection capability 物件。
  • const XnChar* strPose:偵測到的姿勢,這邊是以字串的形式來告訴 callback function,這邊偵測到的是哪種姿勢(不過目前似乎也只有「Psi」一種)。
  • XnUserID user:偵測到該姿勢的使用者
  • void* pCookie:額外傳遞的資料,這邊代表的意義就是一個指向目前使用的 user generator、也就是 mUserGenerator 的指標。

而在 OpenNI 偵測到校正用的姿勢、並呼叫 PoseDetected() 後,他做了兩件事。第一件事是去呼叫 user generator 的 skeleton capability 的 RequestCalibration() 函式,要求 skeleton capability 開始針對擺出校正姿勢的使用者(user)進行人體骨架的校正;而之後,由於已經偵測到姿勢、並且進入下一個處理階段了,所以也要透過 StopPoseDetection() 這個函式,來停止對這個使用者繼續做姿勢的偵測。

 

讀取骨架資料

讀取骨架資料的部分,在程式碼裡面就是「10. get user information」開始的部分了。

首先,要讀取 user generator 的相關資料時,大多都需要使用 XnUserID 來指定是要針對哪一個使用者來做操作;而要取得使用者的資料,則是要透過 user generator 的 GetUsers() 來讀取。

而 OpenNI 對於這種未知數量的資料讀取,基本上都是採用同樣的形式,像以 GetUsers() 來說,就是要給他一個已經分配好記憶體位址的陣列、讓他寫入資料,並給他分配好的空間大小、讓他知道可以寫多少東西進去。所以 GetUsers() 的介面,就是

XnStatus xn::UserGenerator::GetUsers( XnUserID aUsers[], XnUInt16& nUsers )
 

而使用的話,大致上就是(程式碼摘錄自 NITE 範例的 StickFigure.cpp):

XnUserID Users[10];
XnUInt16 nUsers = 10;
g_UserGenerator.GetUsers( Users, nUsers );

這樣寫的話,他就會試著去由取得 g_UserGenerator 目前偵測到的前十個使用者,並將這些使用者的資料,儲存在 Users 這個 XnUserID 陣列裡;而在執行之後,nUsers 的值也會跟著被修改成取得的使用者資料數量。

比如說 g_UserGenerator 有五個使用者的話,在執行過上面的程式後,Users 的前五項就會被寫入資料、而 nUsers 的值也會從 10 變成 5;如果 g_UserGenerator 有十五個使用者的話,在執行過後,Users 的十項都會被寫入資料、而 nUsers 的值則會維持是 10,後面五個使用者的資料就沒讀出來了。

而實際上比較好的方法,應該是先去取得使用者的數量,再來讀取相關的資料;所以 Heresy 在這邊的做法,就是先透過 user generator 的 GetNumberOfUsers() 函式,來取得目前的使用者數量(「10. get user information」的部分),之後再根據這個已知的數量,去取得使用者的資料(「11. get users」的部分)。

接下來,Heresy 則是用迴圈的方式,去針對每一個偵測到的使用者都做處理。在迴圈內的第一步,就是透過 skeleton capability 的 IsTracking() 函式,來判斷使否正在追蹤該使用者的骨架資料(「13. if is tracking skeleton」的部分);如果有的話,他的骨架資料才是有意義、有需要去讀取的。

如同前一篇文章所提過的,OpenNI 的關節資料標括了位置(position)和角度(orientation),而在讀取骨架資料的時候,也可以透過使用不同的函式,來讀取不同的資料;OpenNI 的 xn::SkeletonCapability 有提供三個函式,分別是:

  • GetSkeletonJointPosition():讀到的資料是只有位置資訊的 XnSkeletonJointPosition
  • GetSkeletonJointOrientation():讀到的資料是只有角度資訊的 XnSkeletonJointOrientation
  • GetSkeletonJoint():讀到的資料是包括位置和角度的 XnSkeletonJointTransformation

至於到底要用哪種讀取方法,就是看個人需求了。Heresy 在這邊的程式裡,是使用 GetSkeletonJoint() 來讀取關節的資料(「14. get skeleton joint data」的部分),他的方法基本上就是要指定要讀取「哪個使用者」的「哪個關節」,也就是必須要一個關節、一個關節來做讀取;而 Heresy 為了簡化程式,這邊就只有讀取頭部、也就是 XN_SKEL_HEAD 的資料了。

最後,由於 Heresy 沒有寫圖形顯示的部分,所以在把關節資料讀取出來後,也就只有很簡單地用文字的形式,把讀到的資料做輸出了(「15. output information」的部分)∼

 

小結

基本上,這個程式還是只有純文字的 console 介面。在執行起來後,他會在有事件發生的時候,輸出一些對應事件的訊息,像是「New user identified」、「User xxx lost」之類的。而當使用者擺出校正姿勢、並且校正成功、成功地抓到骨架後,程式就會不斷地輸出目前抓到的骨架的頭部位置,直到使用者離開為止。

雖然這樣的程式基本上沒什麼意義,但是要拿來做基本的 OpenNI 人體骨架的範例、測試,應該也算是夠了∼如果要延伸的話,就是在去根據讀取到的骨架資料,看看是要拿來幹嘛了∼

61 thoughts on “透過 OpenNI / NITE 分析人體骨架(下)”

  1. 如果想要用读出的骨架资料来控制一个骨骼模型的运动应该怎么做?

  2. 您好,這取決於你要控制的骨骼模型本身是麼設定的了。OpenNI 本身只能讀出骨架的資料,其餘的部分要自行解決。

  3. 不好意思 因為我要做精密的人體角度動作控制請問目前因某種原因不能測想問 這個程式原本是讀取角度及位置的動作那麼 我抓出來只有位置 是因為 只顯示了位置 而沒顯示角度那如果要改成角度舉例 應該是這樣?RIGHT_HAND.position.orientation.X 這樣嗎?

  4. 我大概知道了只是我還是不能理解RIGHT_HAND.orientation.orientation.elements[0]顯示有9個陣列(1個點9個方位?9個角度?)請問各表示什麼呢?

  5. @pauliaia 建議你可以參考 NITE 官方的範例 StickFigure,裡面有實際把它畫出來的例子。

  6. 嗯 目前我有比較大的疑問就是 他到底表示的是甚麼東西RIGHT_HAND.orientation.orientation.elements[0]這段測試過後 很詭異的 竟然全部都是0而在StickFigure 這個程式當中是額外乘了100不管如何 因為我不是很清楚OPENGL 不太清楚裡面表是甚麼就我需要的來說 我需要的是角度舉手投足所得到的夾角這東西對我來說 有用到的嗎?目前主要不知道他是甚麼 我怎麼弄 他顯示都是0

  7. 基本上,如果只是要理解 XnSkeletonJointOrientation 的意義,和 OpenGL 沒什麼關係。XnSkeletonJointOrientation 的內容是三個值為一組所構成的三個向量,基本上你可以把他想成是某個關節的座標軸定義,也就是定義出這個關節點的 X/Y/Z 的方向;而相關的定義,在 OpenNI 官方所提供的文件內也是有做說明的(雖然很簡略)。在 StickFigure 這個範例的 drawOrientation() 裡,他就只是把這三個軸畫出來而已;而乘上 100,只是要把這個座標軸放大而已。而如果你只是要夾角的話,基本上有這個關節點連接的兩個肢體的方向去計算,應該就求得出來了吧?

  8. 不知道是不是我 有少打什麼XnSkeletonJointOrientation 弄出來9個陣列的值都是0我是參考這篇透過 OpenNI / NITE 分析人體骨架(上)沒什麼改 就多幾個cout

  9. 您好,Heresy 自己有在測試過,以這個範例程式來說,頭部的部分應該是可以讀到 Orientation 的值的。但是相對的,XN_SKEL_RIGHT_HAND 的部分應該是 NITE 無法判斷出他的方向(沒有相對資料判斷),所以他的 fConfidence 的值都會是 0,代表無法判斷。

  10. 嗯 謝謝你的測試 因為有某些關係 需要動到人體四肢動作的角度關係的問題不論如何 感謝你的回答

  11. 您好!我想請問一下,透過GetSkeletonJoint所得到的位置,要如何轉換成顯示螢幕上的座標呢?

  12. to leon 請使用 depth generator 所提供的轉換函式 ConvertRealWorldToProjective()。

  13. 多謝~雖然剛剛在其他地方爬到您的文章有提到,不過還是謝謝您不厭其煩的回答

  14. 您好!请问现在开发openni有哪些方面的资料啊,借鉴一下!我的邮箱是libo-123.com@163.com,谢谢!

  15. KINECT如果移动的话骨骼跟踪很容易丢失,这个是什么原因?

  16. to tnt
    這是內部演算法實作的關係。
    這類動作偵測、分析的演算法,基本上大多都是設計在固定場景的情況下做處理的,除非自己針對這個問題重新實作骨架追蹤的演算法,不然沒有辦法解決。

  17. 非常谢您的回答。但是我发现微软基于KINECT的骨骼跟踪不容易丢失,难道它们用的算法不一样?

  18. to tnt

    微軟的 Kinect for Windows SDK 或是 Xbox 360,使用的都是他自家的演算法,而 OpenNI 使用的則是 PrimeSense 提供的 NITE,兩者是不同的。

  19. 你好,我看了下你的文章,我想如何利用检测的结果得到左手的6 号7号和 9号骨骼点的角度,请问下有什么方法吗??谢谢…

  20. to huangcheng
    角度的計算一般都是用三角函數來算兩向量之間的夾角?

  21. 请问为什么我把代码复制到我的main.cpp里 运行之后有错误
    fatal error LNK1120: 30 个无法解析的外部命令

  22. to OnePiece

    你的錯誤訊息應該是在編譯階段的錯誤,而非執行階段。
    而 link error 基本上一般都是沒有正確 link 需要的 lib 檔所造成的。建議請檢察專案的設定,是否有正確的設定。

  23. 谢谢! 附加依赖库写成2.0版本的了。。成功运行之后 只说识别到新用户 不输出头的位置啊 请问是要什么姿势么?

  24. to harry

    基本上這個範例就是在做這件事。
    但是如果處理速度不夠快,他就會跳過中間的資料而已。

  25. 現在我是想play錄製好的video,從裏面獲取每一幀骨骼信息。但是openni官方給出的guide沒有涉及到這方面,您有什麽好的建議?

  26. 或者在錄製的時候,可以按照幀數保存骨骼信息到文件中。

  27. 爲了存儲每一幀的畫面,我想到的辦法就是依照時間了。kinect每一秒30幀,那就1/30秒截取一下。您有什麽好的建議呢?

  28. to harry

    個人會建議,不需要直接用 timer 去抓 1/30 秒,而是直接在回圈內呼叫 WaitAndUpdateAll() 來更新資料,並把時間記錄下來。
    因為實務上,考慮到零零總總的問題,他並不能保證你每 1/30 都會有資料。

  29. Heresy大大,在阅读了你的《使用 Qt 顯示 OpenNI 的人體骨架》这篇文章后,我想尝试把骨骼點存放在sqlite的數據庫裡,所以修改CSkeltem中类的UpdateSkeleton方法的代碼如下:
    XnPoint3D JointsReal[15];
    JointsReal[ 0] = GetSkeletonPos( XN_SKEL_HEAD );
    JointsReal[ 1] = GetSkeletonPos( XN_SKEL_NECK );
    JointsReal[ 2] = GetSkeletonPos( XN_SKEL_TORSO );
    JointsReal[ 3] = GetSkeletonPos( XN_SKEL_LEFT_SHOULDER );
    JointsReal[ 4] = GetSkeletonPos( XN_SKEL_LEFT_ELBOW );
    JointsReal[ 5] = GetSkeletonPos( XN_SKEL_LEFT_HAND );
    JointsReal[ 6] = GetSkeletonPos( XN_SKEL_RIGHT_SHOULDER );
    JointsReal[ 7] = GetSkeletonPos( XN_SKEL_RIGHT_ELBOW );
    JointsReal[ 8] = GetSkeletonPos( XN_SKEL_RIGHT_HAND );
    JointsReal[ 9] = GetSkeletonPos( XN_SKEL_LEFT_HIP );
    JointsReal[10] = GetSkeletonPos( XN_SKEL_LEFT_KNEE );
    JointsReal[11] = GetSkeletonPos( XN_SKEL_LEFT_FOOT );
    JointsReal[12] = GetSkeletonPos( XN_SKEL_RIGHT_HIP );
    JointsReal[13] = GetSkeletonPos( XN_SKEL_RIGHT_KNEE );
    JointsReal[14] = GetSkeletonPos( XN_SKEL_RIGHT_FOOT );

    if(isRecord){
    startRecordToDatabase(JointsReal, nRow, countFrame);
    countFrame ;
    }
    // convert form real world to projective
    m_OpenNI.GetDepthGenerator().ConvertRealWorldToProjective( 15, JointsReal, m_aJoints );

    目的是當用戶點擊start button時(界面上的一个button),isRecord變為TRUE,開始save data。但是奇怪的是,我只能save一幀的數據(只有15個骨骼點),之後的數據完全save不下來。是需要增加一個線程么?

    求大大解答,謝謝~

  30. to rpg

    這個得看你整個程式架構是怎麼寫的了。
    Heresy 之前應是用 timer 去做更新的,如果你的畫面有不斷地更新的話,代表他有繼續在讀資料,這樣可能就是你儲存資料的程式沒有被放到主回圈裏面,所以只被呼叫一次。

  31. updateskeleton這個函數在timeevent裏面被調用,應該是要不斷更新的呀?

    我原來的觀點是updateskeleton這個函數應該是要不斷調用的,但實際好像不是這樣啊。

    那我應該把存儲資料的程式放在timeevent裏面么?

  32. 順便說一句,我用的就是您的程式,想在您的程式基礎上將骨骼點存儲。

  33. to rpg

    如果你確定他有在更新資料時被執行到的話,那比較有可能的就是寫入資料庫的時候(startRecordToDatabase?)有問題了。
    個人會建議你透過設定中斷點等方法,來確認到底有沒有被執行到。

  34. 我的确debug过,的确执行了那个函数。不过我感觉可能是数据被覆盖了。我会加一个变量进去test一下。

    还有一个问题,在save data的时候,画面会卡顿,是不是用了多线程就可以解决?

  35. 測試了之後發現,的確數據庫裡的數據被覆蓋了;但是也只有26針數據。也就是說才save了不到一秒鐘的數據。。。我去確信我寫在主循環裏面了。。。:cry:

  36. 大大,進一步測試后發現save的data很不穩定,有的時候會save90針的數據,有的時候才20多針。很奇怪。。。

  37. to rpg

    以你描述的狀況,個人會認問題應該是你資料庫寫入的部分可能有點問題…
    這部分就得看你到底怎麼把她寫到資料庫裡的了。

  38. 我的數據庫是sqlite,寫入代碼:
    query.prepare(“INSERT INTO tab1 (ID, FrameNum,Position, X,Y,Z) ”
    “VALUES (:ID, :FrameNum, :Position, :X,:Y,:Z)”);
    query.bindValue(“:ID”,nRow);
    query.bindValue(“:FrameNum”,countFrame);
    query.bindValue(“:Position”,”torso”);
    query.bindValue(“:X”,JointsReal[2].X);
    query.bindValue(“:Y”,JointsReal[2].Y);
    query.bindValue(“:Z”,JointsReal[2].Z);
    nRow ;
    query.exec();
    這個代碼我copy了15次,把點存進去。但是執行很不穩定。 是我的insert有問題?debug的時候的確每一段都執行了。

  39. to rpg

    抱歉,Heresy 沒有用 SQLite 這個資料庫系統,不太確定它的使用環境。
    不過如果已經確定你的資料插入動作都有被執行到、且有資料被蓋過去的現象,那代表 SQLite 在你現在的寫法下,應該是有一些問題的。

    個人只能建議你在確認看看 SQLite 針對這種高頻率的寫入的情況下,是否有什麼更好的寫法(例如批次寫入)。
    或是改用別的儲存方法來做儲存。

  40. 恩,謝謝大大。我現在單獨測試sqlite高頻率寫入,看有沒問題。

  41. 您好,我刚学习openNI,我用kinect测试,不能识别卧姿的骨骼,那openNI能在人躺下的情况下提取骨骼数据,并画出骨骼人吗?

  42. to jessie
    NiTE 基本上是以處理站姿為主來設計的,其他姿勢(尤其是躺著)不太能做很好的處理。
    這點 OpenNI / NiTE 和 Kinect for Windows SDK 是一樣的

  43. 您好,非常感谢您的回复。
    我用kinect 的sdk做实验,如果躺下,骨骼完全检测不出来,他有个三重重力加速度计,要求对地面进行检测,与地面垂直才能做出骨骼点,那openNI也是这样吗,一点信息都检测不出来?还有我下载的openNI怎么只有深度的例程可以出来图像,骨骼的那个没有图像,只是出数据,怎么回事?

  44. to jessie

    1. OpenNI 雖然沒有參考重力加速器的資料,一樣不能偵測躺下的狀態。(K4W 應該也沒有)

    2. 建議你確認你執行的程式,他有有圖形的版本。

  45. 谢谢博主,那如果我想测卧姿的,博主有没有什么好的建议,非常感谢:D

  46. 问题补充:
    躺下的时候,将kinect吊在房顶上,人体正上方,利用kinect和openNI也不能测吗?

  47. to jessie

    沒有測試過、無法確認;只能說要試試看才知道。
    不過,個人認為很有可能會因為人和地板過度接近、而導致人體很難被追蹤出來、進而無法追蹤。

  48. 您好,请问将背景分离出的前景图像作为骨骼判断的输入图像吗,对前景图像中的人体进行骨架跟踪判断?
    我看骨骼数据流读取用readFrame(&userFrame)直接读入整帧图像并将骨骼信息直接存入userFrame中,如何将其换成我做完处理后的图像帧中一定范围的图像,只判断该范围内的人体骨骼??
    非常感谢!!!

  49. 您好,非常感谢您的回复
    请问怎样查看Nite2、openni的API中各个函数源码定义?

  50. to Avril
    請參考官方文件,SDK 安裝完後都有。
    OpenNI 也可以自己下去看原始碼。

  51. 您好! 新手遇到一个问题,在运行这段程序的时候弹出了错误的对话框,显示”0x000007fef15b377a 处有未经处理的异常: 0xC0000005: 读取位置 0x0000000000000010 时发生访问冲突”,是因为空指针的问题吗?该怎么去查找问题?

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

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *