這篇還是算延續前一篇的《透過 OpneNI 合併 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 );
unsigned int uPointNum = mDepthMD.FullXRes() * mDepthMD.FullYRes(); // 2. build the data structure for convert
XnPoint3D* pDepthPointSet = new XnPoint3D[ uPointNum ];
unsigned int 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];
}
} // 3. un-project points to real world
XnPoint3D* p3DPointSet = new XnPoint3D[ uPointNum ];
rDepthGen.ConvertProjectiveToRealWorld( uPointNum, pDepthPointSet, p3DPointSet );
delete[] pDepthPointSet; // 4. build point cloud
for( i = 0; i < uPointNum; ++ i )
{
// skip the depth 0 points
if( p3DPointSet[i].Z == 0 )
continue; vPointCloud.push_back( SColorPoint3D( p3DPointSet[i], pImage[i] ) );
}
delete[] p3DPointSet;
}

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

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

const XnUInt8* pImageMap = mImageGenerator.GetImageMap();

修改為

const XnRGB24Pixel* pImageMap = mImageGenerator.GetRGB24ImageMap();

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

第二部分「build the data structure for convert」,則是將深度影像的 640 x 480 個點,都轉換為XnPoint3D 形式的一為陣列,已準備進行之後的座標轉換。

第三部分「un-project points to real world」則就是實際進行轉換的部分了。這邊要把座標由影像的座標系統轉換到 3D 座標系統,主要是用 Depth Generator 的 ConvertProjectiveToRealWorld() 這個函式;而它的使用方法也很簡單,只要告訴他要轉換的點的數量(uPointNum)、把要轉換的點用陣列的形式傳(constXnPoint3D*)進去,並給他一塊已經 allocate 好的 XnPoint3D 陣列(p3DPointSet),就可以自動進行轉換了~

第四部份 Heresy 則是再用一個迴圈去掃過全部的點,並把深度為 0 的點給去掉(因為這些點是代表是 Kinect 沒有辦法判定深度的部分)、並和顏色的資訊一起轉換為 SColorPoint3D 的形式,丟到 vPointCloud 裡儲存下來了。

(這個動作其實也可以在第二步的時候先做掉,但是在那邊做顏色的部分會比較麻煩就是了。)

而回到主程式的部分,本來讀取資料的程式是:

// 8. read data
eResult = mContext.WaitNoneUpdateAll();
if( eResult == XN_STATUS_OK )
{
// 9a. get the depth map
const XnDepthPixel* pDepthMap = mDepthGenerator.GetDepthMap();
// 9b. get the image map
const XnUInt8* pImageMap = mImageGenerator.GetImageMap();
}

前面也提過了,Heresy 這邊不打算提及用 OpenGL 顯示的部分,所以這邊為了不停地更新資料,所以改用一個無窮迴圈的形式來不停地更新資料、並進行座標轉換;而轉換後的結果,也很簡單地只輸出它的點的數目了。

// 8. read data
vector<SColorPoint3D> vPointCloud;
while( true )
{
eResult = mContext.WaitNoneUpdateAll();
// 9a. get the depth map
const XnDepthPixel* pDepthMap = mDepthGenerator.GetDepthMap(); // 9b. get the image map
const XnRGB24Pixel* pImageMap = mImageGenerator.GetRGB24ImageMap(); // 10 generate point cloud
vPointCloud.clear();
GeneratePointCloud( mDepthGenerator, pDepthMap, pImageMap, vPointCloud );
cout << "Point number: " << vPointCloud.size() << endl;
}

如果是要用 OpenGL 畫出來的話,基本上就是不要使用無窮迴圈,而是在每次要畫之前,再去讀取 Kinect 的資料、並透過 GeneratePointCloud() 做轉換了~而如果不打算重建多邊形、而是像 Heresy 直接一點一點畫出來的話,結果大概就會像上面的影片一樣了~

通过 OpenNI 建立 Kinect 3D Point Cloud的更多相关文章

  1. An Algorithm for Surface Encoding and Reconstruction From 3D Point Cloud Data

    An Algorithm for Surface Encoding and Reconstruction From 3D Point Cloud Data https://www.youtube.co ...

  2. OpenCV、PCL;Xtion、kinect;OpenNI、kinect for windows SDK比较

    一.对比介绍: 1. OpenCV:开源跨平台,OpenCV于1999年由Intel建立,如今由Willow Garage提供支持. 2. OpenNI:OpenNI组织创建于2010年11月.主要成 ...

  3. **PCD数据获取:Kinect+OpenNI+PCL对接(代码)

    前言: PCL使用点云作为数据格式,Kinect可以直接作为三维图像的数据源产生三维数据,其中的桥梁是OpenNI和PrimeSense.为了方便地使用Kinect的数据,还是把OpenNI获取的基础 ...

  4. RGB_D_开发征程(使用Kinect)

    学习历程依此为纲! Kinect学习资料: kinect和openNI开发资料汇总:http://blog.csdn.net/chenli2010/article/details/6887646 原始 ...

  5. 另一篇xtion、kinect选择比较(openni下)

    小小Xtion开箱测评!!2012年03月12日 19:52:55 原文:http://page.renren.com/601107241/note/811764499 ASUS Xtion Pro ...

  6. Kinect for Windows SDK开发入门(15):进阶指引 下

    Kinect for Windows SDK开发入门(十五):进阶指引 下 上一篇文章介绍了Kinect for Windows SDK进阶开发需要了解的一些内容,包括影像处理Coding4Fun K ...

  7. [译]Kinect for Windows SDK开发入门(十八):Kinect Interaction交互控件

    本文译自 http://dotneteers.net/blogs/vbandi/archive/2013/03/25/kinect-interactions-with-wpf-part-i-getti ...

  8. OpenCV中Kinect的使用(1)

    图像处理中一般为了更好的获取外部信息都会使用到Kinect,其优势在于除了传统的RGB摄像头之外,还拥有一个获取深度信息的3D深度感应器,因此可以获得外界物体的3维信息实现物体的跟踪.手势识别等各项功 ...

  9. Kinect 开发 —— 全息图

    Kinect的另一个有趣的应用是伪全息图(pseudo-hologram).3D图像可以根据人物在Kinect前面的各种位置进行倾斜和移动.如果方法够好,可以营造出3D控件中3D图像的效果,这样可以用 ...

随机推荐

  1. 【原创】MapReduce计数器

    MapReduce框架内置了一些计数器的支持,当然,我们也可以设置自己的计数器用来满足一些特殊的要求. 其实计数器可以用来完成很多事,关键要看你如何用,例如你想知道map输入数据的指定记录特定的信息有 ...

  2. windows 7 中将“我的电脑”锁定到任务栏

    1.在桌面右击->新建->快捷方式 2.输入%SystemRoot%\explorer.exe /E,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}点击下 ...

  3. [C#]生成预定义全颜色表

    生成Color类所有static预定义成员的颜色表 const long CELLS_PER_LINE = 10; const float MARGIN = 12; const float CELL_ ...

  4. jQuery进行图片预先加载

    /** **将图片加载到内存中,在页面任何位置引用的时候,直接从缓存中读取,提升用户的体验,提高网站的流畅度.** **/ <!DOCTYPE html PUBLIC "-//W3C/ ...

  5. sql语句相关整理

    select * from jcls_lawfirms where length(lf_2)=2 for updateselect * from jcls_lawfirms where length( ...

  6. ActiveMQ, Qpid, HornetQ and RabbitMQ in Comparison

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...

  7. libpcre.so.1 cannot be found

    安装完Nginx之后,启动报错. [vagrant@localhost sbin]$ sudo ./nginx ./nginx: error while loading shared librarie ...

  8. PHP同时操作两个mysql数据库

    $connect=mysql_connect("localhost","root","",true); $db=mysql_select_d ...

  9. mac jdbc连接mysql

    1.下载jdbc驱动: http://dev.mysql.com/downloads/connector/j/ 2.增加jdbc的jar包至项目的libs文件夹并build path 2.改动环境变量 ...

  10. Ubuntu Server 12.04 静态IP简洁配置

    PS:很长时间没使用Ubuntu了,刚才安装个Ubuntu Server 12.04做测试.Ubuntu的网络设置跟Redhat系是不一样的,配置IP时发现跟以前的Ubuntu桌面版本也有所不同,记录 ...