這篇,稍微來提一下 Kinect 在 OpenNI 的環境下的深度資料性質吧∼
上面這張圖,是 Heresy 透過 Kinect、連續錄下 50 的畫面的深度分布統計資料(Histogram),橫軸是深度(單位 mm)、縱軸則是該深度所抓到的點的數量。雖然隨著場景的不同,得到的結果應該會有落差,但是上面的統計圖,應該還是有一定程度的參考價值。(原始資料)
深度值的意義
不過,這邊首先,Heresy 先釐清一個 Heresy 之前弄錯的地方。那就是,在投影(projective)坐標系、也就是透過 Depth Generator 直接得到的深度圖上,像素的值其實就是直接代表深度值,單位就是 mm;它所代表的意義,就是該點到 Kinect 所在的平面的垂直距離。
而在透過 depth generator 的 ConvertProjectiveToRealWorld() 這個函式轉換到真實世界(real world)坐標系的時候,其實 Z 的值是不會變的;他會根據投影座標系統上的 ( X, Y, Z ),去計算出在真實世界坐標系的位置,理論上會是 ( X’, Y’, Z ),雖然 X / Y 的執會改變,但是實際上 Z 的值應該都是維持不變的。也就是說,在 OpenNI 裡(或者更嚴格的來說,在 OpenNI 的 Kinect 這個裝置上)投影座標系統和真實世界座標系統的深度值所代表的意義是相同的。
所以,如果只是想知道某個點的深度,或是兩個點的深度差的話,其實不用轉換到真實世界座標系統,直接在投影座標系統針對 Z 值做計算就可以了∼但是,如果是想知道兩點的距離的話,那就還是要透過轉換的函式,把真實世界座標系統的 X / Y 算出來了。
深度的範圍以及精確度
Kinect 的深度有效範圍,根據《Kinect for Windows SDK 官方中文開發教學影片》的投影片的說法,是建議在 1.2 公尺到 3.6 公尺左右;不過實際上,在 OpenNI 中,depth generator 有提供一個 GetDeviceMaxDepth() 函式,可以用來取得這個深度感應器可以偵測到的最遠距離。而 Kinect 所回報的值是 10,000mm、也就是 10 公尺,算是比微軟官方建議的大了不少。
不過雖然他號稱能到這樣的範圍,但是從上方的統計圖裡資料分布的不同應該可以看的出來,實際上深度點的分布密度,在前方是比較高的,而到了後面,密度就很低了!這也代表著,Kinect 這款深度感應器,在比較近的位置,能提供比較高的精確度,而比較遠的地方,精確度就降低了。
實際上,以這組資料來說,深度的部分是從 328mm 開始有偵測到深度的,之前基本上都沒有;這應該也就是 Kinect 能取得的最短深度了(有沒有可能更小?不確定)。但是實際上,這時候能抓到的資料量並不多、也不穩定,所以並不建議使用這種距離的資料。而這個時候,每間隔 1mm 的深度,都可以找到資料點,也就是在取得的資料上,精確度應該是可以到達 1mm 的。
而當深度到達 611mm 後,資料就不再是連續,而會有缺值;也就是某些深度會完全沒有資料,代表著精確度開始降低了。向在這邊有缺值的深度點,依序是 611、622、631、638、644、650…可以發現,缺資料的深度間隔,是越來越高的!而這樣隨著距離越來越遠,有缺值的深度也就越多、分布的密度也就越來越疏,代表精深度的確度越來越低。
大概到 100 公分左右時,大概就已經掉到資料間隔是 3mm 了,這也代表了在這個距離下,3mm 內的深度差異,Kinect 是無法區隔的∼到了 200 公分時,基本上 1 公分左右的差異,Kinect 就已經無法區隔了;而到 300 公分時,則是大約 3 公分內的差異都無法分辨。
而最後有抓到資料的深度,是 9,758(976 公分),不過資料量同樣也很小,不會建議使用這個區段的資料。而前幾的有資料的深度,則是 8,996、9,236、9490;基本上,已經是要格超過 20 公分的間隔了∼也就是說,當到了一定的深度後(約 8 公尺),20 公分以內的深度差異,Kinect 是分辨不出來的。
所以,雖然透過 OpenNI 得到的 Kinect 的深度資料是以 mm 為單位,但是實際上由於感應器的精確度在正常使用的距離下、並沒有這麼高,所以在使用的時候,最好確認一下自己深度上判斷的條件,不要設得太細,以免因為精確度造成問題。
大牛您好:最近出了个PCL(point cloud library)的数据库,是专门处理点云数据的开源库,目前已经关于kinect的各类数据处理,希望博主有时间可以看看哈,目前除了官方网站没有什么比较好的交流论坛了:(
to jingjing123 感謝你的分享。PCL Heresy 也有去看過,只是他所需要建置的環境太繁瑣了,雖然他有簡易安裝包,但是有幾個額外的 library 和 Heresy 這邊的環境有重疊…再加上連 OpenNI 都要是 patch 過的…Heresy 是覺得麻煩啦∼所以一直沒有真得下去用…至於會不會認真研究?可能要看之後有沒有時間吧。
想請問一下 我從kinect 獲得的(x y z) 是指投影座標嗎? 例如 320×240 中的某一點 (100 20 1000)
to James
如果你是透過 OpenNI Depth Generator 拿到的話,基本上應該就是只有深度值;再加上影像的 x, y,構成投影座標系統上的一個點。
所以如果要轉成世界座標(X Y Z) Z=深度值
那X Y 呢?
x=f *X /Z , y=f*Y/Z 嗎?
x y 為320×240 中間某一點
f 為焦距
麻煩請解答,謝謝
您好,座標轉換的部分,請參考:
http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=217
基本上,提供投影座標系統的 x, y, z 就可以轉換成世界座標系統的點了,不需要 f。
heresy你好,关于用opencv获得kinect的深度视频一直有一个疑惑,就是在oni格式下看到的是越靠近Kinect(当然是在有效范围内)的物体越亮(黄色),越远也就越暗。但是在得到的avi深度视频(黑白)中,却是越靠近Kinect的物体越暗(颜色越深),越远的地方颜色越浅(白色)。感觉像是把颜色颠倒了一样,这个是什么原因呢?
to zzscorpio
深度值基本上只是一個浮點數,不代表任何顏色。
如果要用顏色來呈現深度值的話,需要自己把深度值對應到自己想要的色彩。
不同的程式會有不同的色彩對應,只是單純對應的方法不一樣而已。
请教一下,那个转换坐标系为什么要除以Z呢?用X除以Z不就是说除以了深度值么?怎么变成了x了。
to fox
建議請直接用內建的功能進行轉換。
您好,我获取的深度信息通过DepthGenerator的GetMetaData来获取的深度信息数据,此时应该获取的是投影坐标系中的像素信息,单纯对Z信息进行变换,进行显示,得到的图像在距离较近时会有大片不重合的部分,请问这是不是由于kinect在检测深度时有缺值导致的呢
你是指彩色影像和深度影像的位置不一致嗎?
你有使用 Alternative View Point Cap 來做修正嗎?
而實際上,由於Kinect 或 ASUS Xtion Pro Live 在硬體上,彩色影像攝影機以及深度攝影機本來就是在不同的地方,所以本來就一定會有視角上的不同。而雖然可以透過軟體進行修正,但是在近距離的時候,還是會有明顯的誤差,這個應該算是硬體上的限制了。
我是用的是OpenCV来创建显示图像,利用GetMetaData获得深度数据,使用了Alternative View Point Cap 进行修正,确实是在显示的时候是靠近kinect的地方会出现较大的不一致,在查资料的时候发现说是kinect获得深度数据是有ID信息的,我并没有去除数据中的ID信息,是不是数据的ID导致的呢?
to hanxv
不確定你的不一致是到什麼程度。
個人是建議你試試看用 OpenNI 官方範例 NiViewer,切到 overlay 模式,看看在同樣的距離下,是否會有同樣的狀況。
另,不知道你所說的 ID 是指什麼。
heresy老师您好,我想请问一下骨骼关节的获取,手势识别以及setSmooth函数降噪的基本原理。是不是由于这部分是属于NITE,没有开源?因此资料很少?
to cts
是的,這部分都是屬於 middle 的實作,也就 NITE 的部分。
很感谢老师的指导,我同时打开我自己的程序和NiViewer进行了测试,发现二者在相同距离下的图像显示基本是一样的,我是用灰度图像进行显示,灰度值和距离成比例关系,越靠近kinect,灰度值越小,图像也就呈黑色,在远距离时灰度值越大,在显示时,发现在一些距离较远的地方也出现了很多灰度值较小的区域,经过老师指点,打开NiViewer程序发现也是出现这种情况,自己得到的深度信息显示的图像应该还需要进一步处理,才能得到较好的显示效果,很感谢老师的指导
老師你好,不好意思我想請問一下有關於 KINECT 中 骨架數據的儲存語法?以及他可以儲存格式。
to Rex
如果是 OpenNI 的話,基本上就是要手動把各關節點的資訊讀取出來,然後自己看要怎麼把它存下來。
基本上儲存是要自己寫的。
老師你好,可以請問一下儲存的語法嗎?我想要自動存成TXT檔可是我只找到 this.skeletonData = new Skeleton[kinect.SkeletonStream.FrameSkeletonArrayLength]; 其用法不知如何運用新手上路老師請多包涵。謝謝老師
to Rex
確認一下,你現在是使用什麼語言、哪個方案再做開發?
感覺上你似乎不是使用 OpenNI、而是使用 Kinect for Windows SDK?
如果是的話,抱歉,Heresy 這邊是使用 OpenNI、並沒有使用 Kinect for Windows SDK。
另外,在標準 C 裡,可以透過 fstream 來對檔案進行存取,建議可以參考看看。
老師你好,老師我是使用 Kinect for Windows SDK,如果我是在C 中的話透過 fstream的話要如何寫?不好意思新手上路,有很多不懂請多多包涵。感謝老師辛苦了。
to Rex
網路上有很多相關範例,建議可以先參考看看
http://www.cplusplus.com/doc/tutorial/files/
heresy老师,您好,新手上路,我想做一张类似您这样的一张条形图,可以参考哪里的代码?
to henry
Heresy 這張圖是輸出成純文字檔後,然後用 Excel 畫的耶
heresy,您好,假如我知道彩色图像的一个二维点(100,100),将它投影到深度图像中,用XnStatus xn::DepthGenerator::ConvertProjectiveToRealWorld(XnUInt32 nCount,const XnPoint3D *aProjective,XnPoint3D *aRealWorld)const
这个函数将它转换为实际空间中的坐标时,而这个函数中的aProjective坐标点应该是三维的,那么我这个y值应该怎样获得呢?
to ty
2D 影像上的一個點,本來就是三度空間裡面的一條線。
所以你要把投影座標系統裡的點轉換到真實世界座標系統,就必須要指定它的深度,也就是 Z 的值(應該不是 y)。
而一般來說,這個 z 的直就是去取 depth generator 裡的象素值。
嗯,我上面打错了,我是想问的怎么取Z值,打成了y,谢谢您了哈
TO zzscorpio:
请问你是怎么得到深度视频的,我最近也在做这个,但是写入的视频总是有问题,你能给我点指导么,谢谢!