這篇還是算延續前一篇的《透過 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. JAVA面试题——JAVA编程题1(2015.07.22——湛耀)

    实现代码很简单:   package com.xiaozan.shopping;   import java.util.Arrays;   public class ShoppingCart {    ...

  2. PC问题-使用BAT方法设置IP地址

    ::------以下为批处理文件内容---- @echo off ::set slection1= set/p slection1=请输入IP地址: netsh interface ip set ad ...

  3. [Git]git常用命令总结

    git clone url 将远程库复制到本地 git status 查看本地库的状态 git add filename.filetype 将库中被修改的文件标记为添加状态 git diff 查看库中 ...

  4. PL/SQL基础

    打印  hi set serveroutput on   --打开输出开关 declare           --说明部分(变量说明,光标申明或者例外说明) begin           --程序 ...

  5. HTML对JSON的操作

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  6. 查看当前正在被执行的sql

    由于在公司服务器上在某个时段查询某个sql执行比较慢,由来查询当前正在被执行的sql Select t.text,SUBSTRING(t.text, (r.statement_start_offset ...

  7. Kinect开发学习笔记之(一)Kinect介绍和应用

    Kinect开发学习笔记之(一)Kinect介绍和应用 zouxy09@qq.com http://blog.csdn.net/zouxy09 一.Kinect简单介绍 Kinectfor Xbox ...

  8. [linux]date命令时间戳和时间之间的转换

    非常多时候我们查看数据库的数据,或者是一些别人系统中的数据须要用时间戳来查询.或者查询出来的结果是个时间戳. 还有时候,查询条件须要输入时间戳. 我之前的办法就是用在线工具来完毕,后来用mac了.我觉 ...

  9. oracle数据库导入导出的dmp(转)

    window下: imp必须要dba用户,所以用sysdba用户登陆,然后给予chnlmgr用户dba权限 grant connect,resource,dba to chnlmgr; 全部导入 im ...

  10. java pdu短信解码

    java pdu短信解码 长短信未验证 有兴趣的可以试试 根据python的方法改写的 /** * PDU短信解析 * * * @param pduPayload * @return */ publi ...