這篇還是算延續前一篇的《透過 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. Learning JavaScript Design Patterns The Observer Pattern

    The Observer Pattern The Observer is a design pattern where an object (known as a subject) maintains ...

  2. vc关于文件拷贝

    单个文件的拷贝 system  针对单个文件 CopyFile  针对单个文件 /** @file_extension egg: .txt .png **/ void CopyFileToDir(CS ...

  3. ApkTool动态打包

    引言: APK在推广的时候可能会须要动态打包APK.比方公布到不同渠道的时候,须要在manifest文件里改动渠道信息.或者app在推广的时候.须要在apk包里面加上推广人信息等. 环境变量: 1.J ...

  4. 雄踞AppStore榜首的游戏&lt;别踩到白块儿&gt;源码分析和下载(一)

    AppStore和Android市场情况 莫名其妙爆红的游戏 真的莫名其妙,笔者下这个游戏两次.第一次在豌豆荚排行榜看到这款游戏,名字怪怪的,下载下来尝试一下,没认为有什么新颖的,还在思虑这是不是刷榜 ...

  5. cocos2dx 3.1创建工 mac

    1.下载cocos2dx 3.1版本号 2.打开终端,cd 进入 cocos2d-x-3.1.1/tools/cocos2d-console/bin 3.cocos new game -p com.t ...

  6. 进程环境之setjmp和longjmp函数

    在C中,goto语句是不能跨越函数的,而执行这样跳转功能的是函数setjmp和longjmp.这两个函数对于处理发生在深层嵌套函数调用中的出错情况是非常有用的. setjmp和longjmp函数也称为 ...

  7. C++ ORM ODB 入门介绍(一)

    C++的语言特性决定了在C++中的ORM框架不可能像Java,C#那没有那么灵活. C++的ORM框架一般都是基于模板,编译时,因此其效率比起Java中的ORM框架更高. ODB是一个比较独立,成熟的 ...

  8. SpringMVC——项目启动时从数据库查询数据

    SpringMVC项目中遇到这样的问题: 1.很多数据字典需要从数据库中查询: 2.懒得修改SQL语句: 3.想在项目中声明静态变量存储数据字典,但是希望这个字典可以在项目启动时进行加载. 当遇到这样 ...

  9. semaphore(信号量)使用说明

    例子:      以一个停车场运作为例.为了简单起见,假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了五辆车,看门人允许其中三辆不受阻碍的进入,然后放下车拦,剩下的车则必须在入口等待, ...

  10. 重写equals方法的约定

    1. 什么时候需要重写Object.equals方法 如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法. ...