OpenNI 的座標系統

恩…最近才發現,雖然 Heresy 有就深度值得意義和精確度做過簡單的探討(參考《Kinect OpenNI 的深度值》,但是除了在之前「3D 體感應用研習工作坊」的課程投影片(參考)裡面,有說明過 OpenNI 的投影世界座標系統(projective coordinate system)和真實世界座標系統(real world coordinate system)外,似乎都沒有在部落格上整理過相關的資料?所以現在來補一下,大概解釋一下 OpenNI 中這兩個座標系統的定義、關係。

投影座標系統/Projective Coordinate System

首先,在之前《使用 Qt GraphicsView 顯示 OpenNI 影像資料》一文中,已經有提供範例,可以使用 Nokia Qt,在 2D 的環境下把 OpenNI 抓到的影像顯示出來了;而顯示出來的結果,大致上會像右圖的樣子。

而實際上,這個時候深度資訊所使用的,就是 OpenNI 的「投影座標系統」。這邊的「投影」所代表的意義,實際上應該就是電腦 3D 圖學裡面,「把三度空間場景裡的東西、以指定的方法投影到一個設定好的平面上、產生出一張平面的圖」的意思。

在 OpenNI 的投影座標系統裡,基本上是以左上角為 (0, 0) 的原點,往右邊為正的 X 軸、往下方為正的 Y 軸;這樣的定義,和一般電腦中影像的座標系統是相同的。

而 Z 軸的正向,可以視為往螢幕內延伸,這樣就形成了一個右手座標系統(如果把 Z 軸看成出螢幕,就會變成左手座標系統);像下圖就是透過 OpenGL 把 OpenNI 得到的資訊,以投影座標系統的形式畫成 3D 的結果;其中 Z 軸就是透過 Depth Generator 讀取到的深度,不過由於考量到 Z 軸的值的範圍和 X/Y 的差異很大,所以這邊有把 X 和 Y 軸放大十倍來做顯示。

其中,畫面左上角就是 (0,0,0)、也就是原點;紅線代表 X 軸、綠線代表 Y 軸、藍線則是代表Z 軸;而黃色的框線所構成的長方體,則是感應器理論上可以看到的範圍,一般狀況下得到的點都會在這個四方體內。

而由於投影座標系統裡的 X / Y 軸的單位是像素、Z 軸的單位則是公厘,所以其實單位是不一致的;再加上直接這樣畫出來的話,其實可以發現 3D 場景裡的物體其實是有變形的,也就是會有「越遠的東西越小」的效果,所以其實並不適合直接把投影座標系統上的資料,拿來做 3D 空間的處理。

真實世界座標系統/Real World Coordinate System

由於投影座標系統基本上是針對 2D 平面的影像再做處理用的,如果要在 3D 環境下做處理,在取得投影座標系統的資料後,需要透過 OpenNI 內 Depth Generator 所提供的 ConvertProjectiveToRealWorld() 這個函式,來將投影座標系統上的座標點,轉換成真實世界座標系統的座標點。這部分的使用說明,可以參考《透過 OpenNI 建立 Kinect 3D Point Cloud》一文。

而 OpenNI 的真實世界座標系統,基本上是感應器(Kinect 或 Xtion Pro)為原點的座標系統;感應器的前方為正的 Z、上方為正的 Y,而感應器的右方則為正的 X。所以實際上,這個座標系統是採用「左手座標系統」的形式;而如果畫成示意圖的話,基本上就會是像右邊的樣子。

如果把 OpenNI 得到的深度資料,在透過 depth generator 的 ConvertProjectiveToRealWorld() 轉換到這個所謂的真實世界座標系統後,透過 3D 畫出來的話,就會變成像下面的圖的樣子:

基本上,上圖中的紅綠藍三種顏色的粗線,一樣分別是對應到 X/Y/Z 三個軸的方向。而黃色的線所構成像是金字塔的四角錐,就是感應器理論上可以看到的區域;他所代表的意義,和在投影座標系統裡的長方體其實是相同的,只是投影座標系統的長方體是經過投影、變形的結果而已。

而在真實世界座標系統裡,X / Y / Z 三個軸的單位就會是一致的,都是公厘;而物體也不會因為遠近而有變形、或大小的改變,只有精確度會隨著 Z 的變大而變低。

不過,如果是要像 Heresy 一樣搭配 OpenGL 來使用的話,還要注意的就是:OpenNI 的真實世界座標系統是「左手座標系統」,而 OpenGL 則是採用「右手座標系統」!兩者的 X 方向是相反的~如果不加上鏡射(mirror)的效果的話,看到的東西是會左右相反的~也就是會變成下圖的樣子:

上面所選的視角或許看的不是很清楚,下面用比較高的視角來俯瞰、應該就比較清楚了。下面左圖就是有經過鏡射處理、符合真實世界狀況的左手座標系統的;而下方右圖,則是不經過鏡射處理、直接把 3D 的點使用 OpenGL 的右手座標系統畫出來的效果。應該可以很明顯看得出來,左右是顛倒的。

所以在處理真實世界座標系統的話,最好也考慮一下自己所使用的 3D 函式庫是採用哪種座標系統、是否和 OpenNI 所定義的相符。(不過就算沒有考慮,一般大概也就是只會產生靜像效果而已)

這篇大致上就是這樣了,這部分有很多地方基本上是自己摸索出來的,如果有不正確的地方請麻煩指證。
對於座標系統的簡單說明,可以參考維基百科

9 thoughts on “OpenNI 的座標系統”

  1. 太谢谢了!最近正头疼这个!非常感谢详细解释!

  2. heresy,你好,总喜欢定时看看你的blog,呵呵。 最近也在做三维坐标的事情,发现一个问题: 用ConvertProjectiveToRealWorld()转换后的到的坐标其实和真实世界坐标系还是不一样的。 我发现转换后图像上某点的Y的值是和它到图像中心的距离是成正比例的(比例我还没算)。 同样地面上的一条直线,如果他在图像的位置是水平的,那么hough变换后得到的端点的世界坐标Y是接近的,但是直线如果在图像上不是水平的 那么他们的Y相差很大。 但是按理解地面上的直线的Y应该是一样。

  3. 您好!最近我需要相关Kinect 结合OpenNI做骨架提取,经过我对骨架数据的分析,我发现在OpenNI结合Nite中获取的骨架有两个特点:1,由于镜像原因,获取的骨架数据里面的左右手/肩膀等其实是和现实世界相反的,因为它所指的Left和Right是当然看到骨架时候,画面所显示的左右(这一点可以通过它同时提供的在深度图片上的像素位置所确定)。2,我发现他们的骨架数据其实是一个右手坐标系,也就是说,从Kinect的的视角看向前方,Kinect的左边为X的正方向,因为经过我简单测试,当人整个正对Kinect站在它的左边时候,获取骨架的X值全部为负,站在右边时,获取的骨架数据全部的X值全部为正。
    但是,我现在不是十分确定这样理解是否正确?如果您有空,麻烦也能分析一下Nite获取的骨架数据吗?非常感谢。

  4. 不对,是“当人正对Kinect,站在从Kinect视角认为的的右边时候,获取骨架的X值全部为负,左边为正”

  5. 以下为Nite官方文档:“Joint positions and orientations are given in the real world coordinate system.The origin of the system is at the sensor. X points to the right of the, Y points up, and Z points in the direction of increasing depth. The coordinate frame is shown in the figure above.” X是人体面对Kinect时候的右边,所以它是一个右手坐标系。

  6. to billy

    Heresy 自己對他的座標系統的理解,基本上就如同本文的說明。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *