Kinect + OpenNI 的深度值


這篇,稍微來提一下 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 為單位,但是實際上由於感應器的精確度在正常使用的距離下、並沒有這麼高,所以在使用的時候,最好確認一下自己深度上判斷的條件,不要設得太細,以免因為精確度造成問題。


之前相關文章:


OpenNI / Kinect 相關文章目錄

對「Kinect + OpenNI 的深度值」的想法

  1. Heresy大,您好,我想問一下,在OpenNI中如何獲取深度數據,得到的深度圖如何才能看到它的坐標數據,比如我在深度圖中某點單擊鼠標獲得該點的坐標,那麽怎麽才能知道該點的坐標數值呢?謝謝~

      • 老师好
        我的问题跟他差不多 想用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是用什么方法做的呢?

  2. […]    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表示该位置处侦测不到像素点的深度。 […]

  3. Hi Heresy

    想請教您,文章內所說的"深度值所代表的意義,就是該點到 Kinect 所在的平面的垂直距離。"這句話是如何得知的?因為小弟一直以為是"該點到Kinect的距離。"謝謝您。

    Roger

    • 沒記錯的話,官方文件內有針對他的座標系統做說明。

      實際上,每一點的深度值在轉換到真實世界座標系統後,就直接是 Z 的值,並是不會變的。
      如果他代表的是和 Kinect 中心點的距離的話,那 Z 的值就不應該和深度值相同。

      或者整個座標系統也會變成類似極座標系統的形式。

  4. Hello Heresy,

    相當棒的一篇分析

    有幾個問題想要請教

    1. “透過 Kinect、連續錄下 50 的畫面”, 這是指你在同一個環境下, 在不移動Kinect, 所錄下的連續畫面嗎?

    2. 在得到XnDepthPixel後, 怎麼像你一樣轉換成mm?

    如果你願意分享這個實驗的更多資訊, 或是source code的話, 那就更感謝了!!!

    目前我要做的實驗是, 想要比較裝上了 Nyko Zoom, 對Depth Map的影響.

    謝謝

  5. […]    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表示该位置处侦测不到像素点的深度。 […]

  6. […]    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表示该位置处侦测不到像素点的深度。 […]

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.