這一篇主要是針對《透過 OpenNI / NITE 分析人體骨架(上)》和《透過 OpenNI / NITE 分析人體骨架(下)》這兩篇文章,做一些簡單的資料補充。由於這算是比較簡單的筆記,所以就簡單寫一下,不附上完整的程式碼了。
關節位置的平滑化
實際上,OpenNI 所讀出來的深度資料有一定的誤差、甚至每個點的值在李英固定的情況下,也會有相當程度的變動。而同樣的情況,也發生在透過 xn::SkeletonCapability 讀取到的關節位置上;也就是說,讀取到的關節位置,會有一定程度的抖動的現象。
而要怎樣減輕這樣的問題呢?OpenNI 在 xn::SkeletonCapability 這個 capability 裡有提供一個名為 SetSmoothing() 的函式,可以傳入一個浮點樹當作調整參數、來針對讀取到的結果作平滑化;他的值的範圍應該是 0 到 1 之間,越大的話得到的結果連續下來會越平滑,不過相對的也會喪失細節、並且增加一些時間上的延遲。
所以,基本上這部分可能是要視需求去做參數的調整。而理論上,只要在初始化階段透過 SetSmoothing() 這個函式設定好平滑化的參數後,就可以減輕關節資料抖動的現象了。
使用現有的校正資料(不用再擺出校正姿勢)
在使用 OpenNI 做人體姿勢分析的時候,標準的作法是需要擺出 NITE 的標準校正姿勢、也就是所謂的 PSI 姿勢的。不過說實話,要使用者都得擺出這個姿勢一小段時間後、才能開始使用,其實算是滿麻煩的。而實際上 OpenNI 是有提供骨架校正資料的儲存取存取,某種程度上是可以用來做到「不用先擺校正姿勢的人體骨架分析」的!
以目前的 OpenNI 來說,它提供了兩組(四個)相關的函式,可供利用。這兩組函式分別為:
- 儲存、讀取記憶體裡的校正資料
- XnStatus SaveCalibrationData( XnUserID user, XnUInt32 nSlot )
- XnStatus LoadCalibrationData( XnUserID user, XnUInt32 nSlot )
- 儲存、讀取檔案形式的校正資料
- XnStatus SaveCalibrationDataToFile( XnUserID user, const XnChar *strFileName )
- XnStatus LoadCalibrationDataFromFile( XnUserID user, const XnChar *strFileName )
第一組的函式,是可以將已經特定使用者(根據 user ID)校正好的骨架資料,透過 SaveCalibrationData() 儲存到記憶體裡指定的 slot 中(用整數來代表 slot 編號),之後再透過 LoadCalibrationData() 讀出來、套用指定的使用者上使用。
而第二組的函式基本上也是類似的,不過他是將骨架的校正資料以檔案的形式來做儲存與讀取;如此一來,就算程式已經結束過、要重新執行,也還是可以重複利用這些校正過的資料。
要使用這兩組函式其實也不複雜。儲存的部分,主要就是要等到使用者已經完成骨架的校正後(就是《透過 OpenNI / NITE 分析人體骨架(上)》中的 CalibrationEnd() 裡),透過 SaveCalibrationData() 或 SaveCalibrationDataToFile() 來將校正好的資料儲存下來。
而之後要套用儲存下來的骨架校正資料的話,則是要 user generator 有抓到新的使用者、建立新的 user 後(就是《透過 OpenNI / NITE 分析人體骨架(上)》中的 NewUser() 裡),透過 LoadCalibrationData() 或 LoadCalibrationDataFromFile(),直接將儲存好的骨架校正資料讀取出來、並直接套用在新的 user 上(透過指定 user ID)。如此一來,OpenNI 就會認為這個 user 已經經過骨架校正的步驟了∼也就是說,可以不用再擺出指定的校正姿勢(PSI),就可以直接開始追蹤骨架了∼
而這樣的功能比較直接的應用,應該就是先儲存好一組校正的結果資料,然後之後對於所有新偵測到的使用者,都直接套用這一組骨架校正資料了!這樣基本上,就算是做到「不用擺出校正姿勢的人體骨架分析與追蹤」了∼而實際測試的話,這個方法在某種程度上應該算是可行的∼
不過,在 Heresy 來看,透過指定姿勢(PSI)來進行骨架的校正實際上應該還是有其必要性的;而這樣的作法,算是把一組校正好的骨架資料當作標準範例、硬套用到所有其他 user generator 偵測到的「使用者上」,所以還是會有可能有問題的。像 Heresy 在實際測試的時候,不但有可能會導致某些非人的物體,也被硬套上骨架的情形,而即使是人,在某些狀況下,也會有骨架資料沒辦法正確追蹤的狀況。整體來說,Heresy 是覺得這種強制套用校正資料的方法,穩定性是相對比較差的。
目前沒有繼續再玩下去,不過 Heresy 現在的想法,是覺得應該可以透過骨架各關節的可靠度,來判斷這種強制套用的結果是否合適,如此或許可以略過某些不合適的例子;但是實際上這也還只是個想法,並沒有經過實測就是了。
你好,我在执行SaveCalibrationDataToFile的时候会出现XN_STATUS_INVALID_OPERATION错误。不知道您有什么好的解决方法么?我的编程环境是fedora系统 vim多谢多谢!
to Erich.AMA您好,Heresy 在測試的時候似乎沒碰到這樣的問題。不過目前是猜測,有沒有可能是您要儲存校正資料的那個 user,並沒有正確地完成骨架校正呢?
Heresy, 刚才我在看NITE的例程(Sample-Players)发现一个问题:当我用手盖住kinect的摄像头以后,会失去所有的user,player数据。当我的手移开以后,重新检测用户,能够显示user,在图像中的人身上也有1,2,3..的显示,但是不会再去分析我的骨骼数据后来我把AssignPlayer()里的一段程序给注释掉,刚才的问题就解决了,并且此时我的新用户不需要在做那个Psi姿势注释掉的部分为: //if (com.Z == 0) //{ // printf(“AssignPlayer中,但是com.Z=%d,已经return
“,com.Z); // return FALSE; //}这个com应该是我用户的坐标值,但是我测试了一下,发现他的z坐标一直都是0啊~查了一下g_UserGenerator.GetCoM(user, com);,发现是这样的一个类型的函数:XN_C_API XnStatus XN_C_DECL xnGetUserCoM()请问这是个windows的API吗?有什么用?注释掉以后会有什么问题?对了,注释部分中间那个printf()语句是我自己加的~
GetCoM() 是 xn::UserGenerator 提供、用來取得使用者位置的函式,可以參考 [url=http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=262]OpenNI 的 User Generator[/url] 一文。基本上,Heresy 沒有去研究過 Player 這個範例。不過 GetCoM() 得到的 Z 值不見得會一定是 0,應該說,會得到 0 是代表他沒有辦法正確抓到使用者的位置。(另,他的型別是 float,你不應該用 %d)而在這個範例裡,他是為了避免要重新校正骨架,所以把第一次骨架校正成功後的資料都存下來,之後發現的新使用者,都會透過使用這個校正好的資料,直接套用、並追蹤骨架。不過他這邊範例這樣的寫法,應該是:當發現新的使用者的時候,就先試圖去透過 GetCoM() 來取得使用者的位置,如果是正確的位置(非 0)的話,就去讀取骨架的校正資料、並開始骨架的追蹤。而如果在一開始就沒有辦法取得正確的位置的話,之後也就不會進行骨架的追蹤了。可是以目前測試的結果來看,User generator 在 new user callback 裡,並沒有辦法正確地透過 GetCoM() 取得使用者的位置 !所以你才會發現在 AssignPlayer(),每次都得到 Z == 0 的結果。這應該算是 NITE 的 bug 吧…
确实是这样~谢谢heresy 大大~
heresy 大大您好:有個問題想請教您,是否除了這個方法之外, 還有沒有其他的方法可以像Windows kinect 一樣, user走進來, 骨架便show出來…想詢問您有沒有辦法…正苦惱中…謝謝
to kinen 文章中已經有提到了,透過 SaveCalibrationDataToFile() 和 LoadCalibrationDataFromFile() 可以做到一定的程度。只要先存下一組 Calibration Data,之後只要有偵測到 user,就套用這組 data,那基本上就可以做到一定程度了。(但是,這樣也會有其他問題要處理就是了)或者,透過 kinect-mssdk-openni-bridge,讓 OpenNI 去使用 Microsoft 的 SDK 也是一個方法http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=245
初來乍到,請教heresy,我在調用SaveCalibrationDataToFile() 和 LoadCalibrationDataFromFile() 時,均返回XN_STATUS_NOT_IMPLEMENTED,不知heresy可知道原因
to 訪客
您好,沒弄錯的話,在 NITE 支援不需要 Psi 姿勢的骨架追蹤後,就已經把這兩項功能拿掉了。所以目前應該是無法使用的。
to heresy
TKS。NITE現在只是不需要進行psi姿勢的檢測卻仍然需要骨架分析的步驟,而上述程式是記錄和讀取骨架數據的,既然利用它們可以省略掉骨骼校正的過程,不知道為何要拿掉這兩項功能,對此仍有懷疑。
to 訪客
拿掉的原因可能要去問 PrimeSense 了…
只能說目前的版本的確是無法使用的。
我用setsmoothing()来减少抖动的时候,为什么刚开始还是会抖,过了15秒左右又不抖了,能告诉我怎么办吗?我设的参数是0.8!!
to 求大神指导
他的平滑化應該是基於時間軸做的,所以一開始資料不足的情況下,不會有很好的平滑化效果。
不過實際上,這還是取決於 NITE 內部的實作,所以還是不是很肯定就是了。