通过 OpenNI 建立 Kinect 3D Point Cloud

這篇還是算延續前一篇的《透過 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 直接一點一點畫出來的話,結果大概就會像上面的影片一樣了~

时间: 2024-10-21 15:17:18

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

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

一.对比介绍: 1. OpenCV:开源跨平台,OpenCV于1999年由Intel建立,如今由Willow Garage提供支持. 2. OpenNI:OpenNI组织创建于2010年11月.主要成员之一是PrimeSense公司(以色列一家公司,被苹果收购(2013年11月25),Kinect1核心芯片,华    硕Xtion).其他成员还有开发ROS的机器人公司Willow Garage,以及游戏公司Side-Kick.(因此OpenNI完全支持华硕,而不完全支持kinect2) 3. P

kinect的openni总结

Kinect到手快一个月了,期间查阅了很多资料,见识了很多牛人,他们的工作如此漂亮,让我大开眼界.现将自己所掌握的资料汇总于此,以便随时查阅. 首先是csdn上小斤童鞋的系列文章: Kinect开发教程一:OpenNI的安装与开发环境配置 Kinect开发教程二:OpenNI读取深度图像与彩色图像并显示 Kinect开发教程三:利用OpenNI进行手势识别 Kinect开发教程四:用Kinect控制鼠标玩水果忍者PC版 其次是mp77技术交流频道上的系列文章,基于openNI的<user gui

Kienct与Arduino学习笔记(1) 基础知识之Arduino’Kinect‘Processing

转载请注明出处:http://blog.csdn.net/lxk7280         首先,对即将要用到的主要东西进行初步的理解. 分为两大类,硬件和软件.硬件,即Kinect.软件,即Arduino和Processing.Arduibo相信很多人都用过,机器人.四轴飞行器等电子产品不少与Arduino这个浪漫的编译器有联系,为什么说浪漫呢,这不得不从它的开发者说起,Arduino的开发者可以说是艺术家出身,所以Arduino总给人一种浪漫高贵的感觉,不得不吐槽一下Keil,界面确实不怎么好

怎样在自己的Blog中展现3D标签云效果

在用Wordpress创建自己的Blog后,怎样在自己的Blog中安装绚丽的标签3D云呢?本文将带怎样用插件来实现这个3D标签云的效果. 我用的插件为:3D TagCloud 步骤一:打开Wordpress的编辑页面,选择插件,如下图所示:(http://localhost/wpc/wp-admin/) 步骤二:安装完成之后,启动这个插件. 步骤三:设置配置参数(3D Tag Cloud),详细参数如下图所示: 步骤四:进入Blog文章页面,看实际效果如下图所示:(http://localhos

用css3做一个3D立方体

首先看一下效果图 1.坐标系,要在脑海里先建立一个3D坐标系 如下图,看清楚x,y,z轴 2.html代码. <div class="container"> <!--包裹六个面的元素--> <div class="cube"> <!--立方体的六个面--> <div class="plane-front">前面</div> <div class="plane-

《Kinect应用开发实战》读书笔记---干货集合

本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接: http://blog.csdn.net/cartzhang/article/details/45029841 作者:cartzhang 说明:本帖内容同时在GALAXIX的Kinect区发表.<Kinect应用开发实战>读书笔记 此书内容针对SDK版本为1.5版本,跟后来版本之前有微小的差别. <Kinect应用开发实战>读书笔记 对于初学来说,本书很不错,将来挺多的基础和细节. 非常感谢本书作者. 以

DirectX 9.0 3D 笔记

1.3.0 预备 1.HAL,硬件抽象层,由D3DDEVTYPE_HAL指定 2.REF,参考光栅设备 3.COM,组件对象模型,使之向下兼容,视为C++类. 1.3.1 表面 4.IDirect3DSurface9,描述表面. (1)LockRect:获取指向表面存储区的指针,通过指针对每一个像素进行读写. (2)UnlockRect:执行完LockRect后,必须调用此来解锁. (3)GetDesc:填充结构D3DSURFACE_DESC来获取表面的描述信息. 1.3.2 多重采样 5.多重

[cvpr17]Multi-View 3D Object Detection Network for Autonomous Driving

3D点云做detection的一篇milestone paper.经典的two-stage方法(region proposal-based method).思路来自于经典的faster rcnn. 整个模型如下图 图一. 整体模型 3D Point Cloud Representation 这篇文章可以归纳为是multiview-based method,multi-view的方法是指将三维点云按照不同view进行映射,得到很多的2D图像,因为2D图像的CNN很强大,这样就可以用2D CNN处理

html中2D,3D效果的实现

2D 2D就是平时看到的平面,就是在屏幕上水平和垂直的交叉线X轴Y轴. 2d中的位移属性:transform:translate(参数1,参数2) 参数1:在X轴上移动的距离(正值右移,负值左移)参数2:在Y轴上移动的距离(正值下移,负值上移) 也可以单独设置XY轴,transform:translateX(),transform:translateY(). 2d中的缩放属性:transform:scale(参数1,参数2) 参数在0~0.9999中为缩小,大于1放大,参数1:水平缩小放大 参数