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