這篇,稍微來提一下 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 為單位,但是實際上由於感應器的精確度在正常使用的距離下、並沒有這麼高,所以在使用的時候,最好確認一下自己深度上判斷的條件,不要設得太細,以免因為精確度造成問題。
之前相關文章:
[…] KINECT + OPENNI 的深度值 […]
讚讚
数据很棒,图片借鉴到了我的毕业论文中,已经注明了转载,谢谢您的分享
讚讚
Heresy大,您好,我想問一下,在OpenNI中如何獲取深度數據,得到的深度圖如何才能看到它的坐標數據,比如我在深度圖中某點單擊鼠標獲得該點的坐標,那麽怎麽才能知道該點的坐標數值呢?謝謝~
讚讚
請參考之前的教學文章
https://kheresy.wordpress.com/index_of_openni_and_kinect/documents-of-openni-1-x/
https://kheresy.wordpress.com/index_of_openni_and_kinect/documents-of-openni-2-x/
讚讚
老师好
我的问题跟他差不多 想用xtion做跟您一样的实验 但是streamDepth.readFrame(&frameDepth);可以提取数据流显示视频
但是怎么得到具体数值来做histogramne 特别是单张的图片
讚讚
請參考上面的連結,確認裡面關於深度影像資料存取的教學。
讚讚
老师 链接里有如何显示,如何读取,但是没有储存方式啊,您指的是保存为mat吗?但是我无法读取mat里的数据
讚讚
追加问题 我用cv::FileStorage fs(“vocabulary.xml", cv::FileStorage::WRITE);
fs << "vocabulary" << mScaledDepth;
fs.release();
想把深度数据存入xml里方便使用 但是存不进去 其他程序中的mat图片却可以
讚讚
1. 讀取出來不就可以自己儲存了嗎?最基本的概念,就是把每個像素的值依序讀除來,然後以自己需要的格式來輸出、儲存。
2.如果可以透過 OpenCV 把畫面畫出來的話,就代表資料是正確的,那就可以透過 OpenCV 提供的函式做資料的存取。
3. Heresy 沒有用過 FileStorage,也不知道你的錯誤問題是什麼。
如果你確定深度影像是正確的話,那且確認 OpenCV 回報給你的錯誤是什麼。
不過老實說,這種影像資料,並不建議使用 XML 這種文字格式的檔案來做儲存,檔案會變大很多,處理起來也會比較慢。
讚讚
老师 我就是用单个像素点读出的方法存在txt文档里 然后用matlab做histgram ,请问老师的histogram是用什么方法做的呢?
讚讚
在程式裡面直接用 C++ 算,不過最後圖是用 Excel 畫的。
讚讚
[…] Kinect在使用时,微软官方推荐的距离为1220mm(4’)~3810mm(12.5’),网友heresy在他的博文Kinect + OpenNI 的深度值中统计过,kinect在距离为1.0m时其精度大概是3mm,而当距离是3.0m时,其精度大概是3cm,因此当kinect在官方推荐的距离范围内使用是,如果是1.2m时,其精度应该在3mm附近,如果是3.6m时其精度就大于3cm了,因此距离越远,其深度值精度越低。另外,通过OpenNI获取到的深度信息(即z坐标)的单位是mm,这一点在程序编程中要注意,且一般的深度值用12bit(其实是可以用13bit表示的)表示,即最大值为4095,也就是代表4.095m,所以平时我们采集到的深度数据如果需要扩展到灰度图,可以乘以一个因子255/4095(为了加快该结果,一般设置为256/4096,即转换后的灰度值每变化1,代表kinect采集到的深度值变化了16mm,如果当人的距离为1米左右时,本来精度是3mm,现在经过归一化后精度确更加下降了,这时候拿这个距离值来做算法不懂会不会有影响,当然了,拿来做灰度图像的显示肯定是OK的),最后如果其深度值为0表示该位置处侦测不到像素点的深度。 […]
讚讚
Hi Heresy
想請教您,文章內所說的"深度值所代表的意義,就是該點到 Kinect 所在的平面的垂直距離。"這句話是如何得知的?因為小弟一直以為是"該點到Kinect的距離。"謝謝您。
Roger
讚讚
沒記錯的話,官方文件內有針對他的座標系統做說明。
實際上,每一點的深度值在轉換到真實世界座標系統後,就直接是 Z 的值,並是不會變的。
如果他代表的是和 Kinect 中心點的距離的話,那 Z 的值就不應該和深度值相同。
或者整個座標系統也會變成類似極座標系統的形式。
讚讚
Hello Heresy,
相當棒的一篇分析
有幾個問題想要請教
1. “透過 Kinect、連續錄下 50 的畫面”, 這是指你在同一個環境下, 在不移動Kinect, 所錄下的連續畫面嗎?
2. 在得到XnDepthPixel後, 怎麼像你一樣轉換成mm?
如果你願意分享這個實驗的更多資訊, 或是source code的話, 那就更感謝了!!!
目前我要做的實驗是, 想要比較裝上了 Nyko Zoom, 對Depth Map的影響.
謝謝
讚讚
這是 Nyko Zoom的網頁
http://www.nyko.com/products/product-detail/?name=Zoom
讚讚
Heresy 是有移動感應器,讓擷取到的資料盡量涵蓋到所有深度,以作為統計。
而 OpenNI 的 Depth Generator 取得到的深度值,本來就是 mm 了,如果只是要統計分析,不需要做而外轉換。
至於 Source code 的部分,Heresy 已經沒有留了。
不過要實做出來其實相當簡單,只要去計算每一個深度值得數量就可以了,建議可以自己寫看看。
讚讚
Hello Heresy,
目前我是用Microsoft SDK 中的 NuiTransformDepthImageToSkeleton 去取得深度值.
(根據這篇文章:
http://social.msdn.microsoft.com/Forums/en-US/kinectsdknuiapi/thread/56b6298c-7365-44fe-917e-bc3eadd91212)
跑出來的Historgram, 形狀也是類似你所做的.
現在好奇的是, 你用什麼移動感應器?
謝謝你耐心的回覆
讚讚
Heresy 用的也是 Microsoft Kinect,不過是使用 OpenNI 做測試
讚讚
謝謝回覆!!!
讚讚
[…] Kinect在使用时,微软官方推荐的距离为1220mm(4’)~3810mm(12.5’),网友heresy在他的博文Kinect + OpenNI 的深度值中统计过,kinect在距离为1.0m时其精度大概是3mm,而当距离是3.0m时,其精度大概是3cm,因此当kinect在官方推荐的距离范围内使用是,如果是1.2m时,其精度应该在3mm附近,如果是3.6m时其精度就大于3cm了,因此距离越远,其深度值精度越低。另外,通过OpenNI获取到的深度信息(即z坐标)的单位是mm,这一点在程序编程中要注意,且一般的深度值用12bit(其实是可以用13bit表示的)表示,即最大值为4095,也就是代表4.095m,所以平时我们采集到的深度数据如果需要扩展到灰度图,可以乘以一个因子255/4095(为了加快该结果,一般设置为256/4096,即转换后的灰度值每变化1,代表kinect采集到的深度值变化了16mm,如果当人的距离为1米左右时,本来精度是3mm,现在经过归一化后精度确更加下降了,这时候拿这个距离值来做算法不懂会不会有影响,当然了,拿来做灰度图像的显示肯定是OK的),最后如果其深度值为0表示该位置处侦测不到像素点的深度。 […]
讚讚
[…] Kinect在使用时,微软官方推荐的距离为1220mm(4’)~3810mm(12.5’),网友heresy在他的博文Kinect + OpenNI 的深度值中统计过,kinect在距离为1.0m时其精度大概是3mm,而当距离是3.0m时,其精度大概是3cm,因此当kinect在官方推荐的距离范围内使用是,如果是1.2m时,其精度应该在3mm附近,如果是3.6m时其精度就大于3cm了,因此距离越远,其深度值精度越低。另外,通过OpenNI获取到的深度信息(即z坐标)的单位是mm,这一点在程序编程中要注意,且一般的深度值用12bit(其实是可以用13bit表示的)表示,即最大值为4095,也就是代表4.095m,所以平时我们采集到的深度数据如果需要扩展到灰度图,可以乘以一个因子255/4095(为了加快该结果,一般设置为256/4096,即转换后的灰度值每变化1,代表kinect采集到的深度值变化了16mm,如果当人的距离为1米左右时,本来精度是3mm,现在经过归一化后精度确更加下降了,这时候拿这个距离值来做算法不懂会不会有影响,当然了,拿来做灰度图像的显示肯定是OK的),最后如果其深度值为0表示该位置处侦测不到像素点的深度。 […]
讚讚