通过Kinect的深度图像数据计算三维点云

在可以透過 OpenNI 讀取到 Kinect 的深度、色彩資訊之後,其實就可以試著用這些資訊,來重建 3D 的環境做顯示了~不過實際上,在前面的範例中所讀到的深度資訊,都算是原始資料,而且座標軸也都是感應器二維影像的座標系統,如果要重建 3D 場景的話,這些資訊都還是需要換算的;所幸,OpenNI 在 Depth Generator 已經有提供ConvertProjectiveToRealWorld()和ConvertRealWorldToProjective()這兩個函式,可以幫助程式開發者快速地進行座標轉換了!

而如果把直接把這些 3D 的點位附加顏色、用 OpenGL 畫出來呢,就大概會是下面影片的樣子吧~

當然,point cloud 不見得是最好的顯示方式,有需要的話也可以重建出多邊形再畫,不過多邊形的重建已經算是另一個主題了,所以 Heresy 也不打算在這邊討論;另外,Heresy 在這篇也不會提及 OpenGL 顯示的部分,只會提供簡單的範例,示範如何建立出這些 point cloud 而已。

而為了儲存這些點的位置以及顏色資訊,這邊先定義了一個簡單的結構、SColorPoint3D:

struct SColorPoint3D{ float X; float Y; float Z; float R; float G; float B; SColorPoint3D( XnPoint3D pos, XnRGB24Pixel color ) {X = pos.X;Y = pos.Y;Z = pos.Z;R = (float)color.nRed / 255;G = (float)color.nGreen / 255;B = (float)color.nBlue / 255; }};

這個結構只是單純的六個福點數,分別記錄這個點的位置、以及顏色;而建構子的部分,則是傳入 OpenNI 定義的結構的變數:代表位置的XnPoint3D 以及代表 RGB 顏色的XnRGB24Pixel。

而為了方便起見,Heresy 把座標轉換的部分寫成一個函式GeneratePointCloud(),其內容如下:

void GeneratePointCloud( xn::DepthGenerator& rDepthGen,const XnDepthPixel* pDepth,const XnRGB24Pixel* pImage,vector<SColorPoint3D>& vPointCloud ){ // 1. number of point is the number of 2D image pixel xn::DepthMetaData mDepthMD; rDepthGen.GetMetaData( mDepthMD ); uPointNum = mDepthMD.FullXRes() * mDepthMD.FullYRes(); XnPoint3D[ uPointNum ]; i, j, idxShift, idx; for( j = 0; j < mDepthMD.FullYRes(); ++j ) {idxShift = j * mDepthMD.FullXRes();for( i = 0; i < mDepthMD.FullXRes(); ++i ){idx = idxShift + i;pDepthPointSet[idx].X = i;pDepthPointSet[idx].Y = j;pDepthPointSet[idx].Z = pDepth[idx];} } XnPoint3D[ uPointNum ]; rDepthGen.ConvertProjectiveToRealWorld( uPointNum, pDepthPointSet, p3DPointSet ); delete[] pDepthPointSet; ( i = 0; i < uPointNum; ++ i ) {( p3DPointSet[i].Z == 0 )continue;vPointCloud.push_back( SColorPoint3D( p3DPointSet[i], pImage[i] ) ); }}

這個函示要把xn::DepthGenerator以及讀到的深度影像和彩色影像傳進來,用來當作資料來源;同時也傳入一個vector<SColorPoint3D>,作為儲存轉換完成後的 3D 點位資料。

其中,深度影像的格式還是一樣用XnDepthPixel的 const 指標,不過在彩色影像的部分,Heresy 則是改用把 RGB 封包好的XnRGB24Pixel,這樣可以減少一些索引值的計算;而因為這樣修改,之前讀取彩色影像的程式也要由

constXnUInt8* pImageMap = mImageGenerator.GetImageMap();

修改為

constXnRGB24Pixel* pImageMap = mImageGenerator.GetRGB24ImageMap();

而在函式內容的部分,第一段的部分主要是透過取得 depth generator 的 meta-data:xn::DepthMetaData來做簡單的大小、索引計算;如果不想這樣用的話,其實也是可以直接用 640 x 480 這樣固定的值來做計算,不過就是要和之前在SetMapOutputMode()所設定的解析度一致就是了。

“人无完人金无足赤”,只要是人就不会是完美的,

通过Kinect的深度图像数据计算三维点云

相关文章:

你感兴趣的文章:

标签云: