前言

PCL使用点云作为数据格式,Kinect可以直接作为三维图像的数据源产生三维数据,其中的桥梁是OpenNI和PrimeSense。为了方便地使用Kinect的数据,还是把OpenNI获取的基础数据格式转换为点云格式。并且PCD格式的数据操作起来更为直观。

切记:理论自己慢慢看,代码是最重要的,且测试可行且正确

(1):Microsoft Kinect SDK 和 PrimeSense OpenNI 的区别

原文链接:http://blog.csdn.net/wdxzkp/article/details/6608817

注解:作者写了一系列博文,可以借鉴一下:

After playing with both the Microsoft Kinect SDK and
the PrimeSense OpenNI SDK here are some of my thoughts,Note that the Microsoft’s SDK version is the Beta version, so things may change when the final one is released)

Microsoft’s
Kinect SDK (Beta)pro: 优点

  • support for audio 支持音频
  • support for motor/tilt 支持马达
  • full body tracking: 全身追踪
    • does
      not need a calibration pose 不需要标定姿势(投降姿势)
    • includes
      head, hands, feet, clavicles 包括头,手,脚和锁骨
    • seems
      to deal better with occluded joints 看起来处理关节闭塞更好些
  • supports multiple sensors 支持多传感器(多台Kinect)
  • single no-fuss installer 简化安装(安装更容易)
  • SDK has events for when a new Video or new Depth frame is available 当新的视频或深度图有效时,SDK会有可用事件

con: 缺点

  • licensed for non-commercial use only 非商用(商业需要付费)
  • only tracks full body (no mode for hand only tracking)  只能追踪全身(不包含特定的追踪模式:例如只追踪手)
  • does not offer alignment of the color&depth image streams to one
    another yet 
    although there are features to align individual coordinates
  • and there are hints that support may come later

full body tracking:  全身追踪
only
calculates positions for the joints, not rotations 关节只有坐标数据,没有旋转数据 only
tracks the full body, no upperbody or hands only mode 只能追踪全身,不包含特定的追踪模式:例如只追踪手或上半身

seems
to consume more CPU power than OpenNI/NITE (not properly benchmarked)  和OpenNI/NITE相比,看起来更消耗CPU(没有采用适当的基准)
no gesture recognition system  不包含手势识别系统 no
support for the PrimeSense and the ASUS WAVI Xtion sensors? (can anyone confirm this?)  不支持PrimeSense和华硕的WAVI
Xtion硬件平台 only supports Win7 (x86 & x64)   只支持Win7(32位和64位) no
support for Unity3D game engine  不支持Unity3D游戏引擎 no
built in support for record/playback to disk  不支持数据记录或回放到硬盘 no
support to stream the raw InfraRed video data  不支持红外线视频数据流
SDK does not have events for when new user enters frame, leaves
frame etc  SDK没有此类发生事件,例如当一个用户被侦测到或用户丢失等等。 

PrimeSense OpenNI/NITEpro: 优点

  • license includes commercial use 可以商用(不需要付费)
  • includes a framework for hand tracking 包含手部追踪框架
  • includes a framework for hand gesture recognition 包含手势识别框架
  • can automatically align the depth image stream to the color image  可以自动对齐深度图数据到彩色图数据
  • full body tracking:  全身追踪 
    • also
      calculates rotations for the joints 包含坐标数据和旋转数据
    • support
      for hands only mode 支持特殊跟踪模式:例如:只追踪手和头或上半身
    • seems
      to consume less CPU power than Microsoft Kinect SDK’s tracker (not properly benchmarked) 和微软的SDK相比消耗的CPU更少
  • also supports the Primesense and the ASUS WAVI Xtion sensors 支持Primesense和华硕的WAVI
    Xtion硬件平台
  • supports multiple sensors although setup and enumeration is a
    bit quirky 支持多传感器但是需要安装和枚举,这一点有点古怪。
  • supports Windows (including Vista&XP), Linux and Mac OSX 支持Windows(包括Vista&XP&WIN7),Linux系统和苹果操作系统(翻者:也支持Android)
  • comes with code for full support in Unity3D game engine  自带的代码全面支持Unity3D游戏引擎(翻者:也支持Ogre)
  • support for record/playback to/from disk 支持数据记录到硬盘或从硬盘回放数据
  • support to stream the raw InfraRed video data 支持红外数据流
  • SDK has events for when new User enters frame, leaves frame etc SDK有此类发生事件,例如:当一个用户被侦测到或者用户丢失。(提供回调函数供开发者使用)

con: 缺点

  • no support for audio 不支持音频
  • no support for motor/tilt (although you can simultaneously use
    the CL-NUI motor drivers) 不支持马达(翻者:马达是微软的专利,所以primesense公司不想惹微软)
  • full body tracking:  全身追踪 
    • lacks
      rotations for the head, hands, feet, clavicles 缺乏以下关节:头,手,脚,和锁骨
    • needs
      a calibration pose to start tracking (although it can be saved/loaded to/from disk for reuse) 需要一个标定姿势(投降姿势)才能开始追踪骨骼(注意:标定数据是可以存储和提取的方便重用)
    • occluded
      joints are not estimated 关节闭塞没有被估算
  • supports multiple sensors although setup and enumeration is a
    bit quirky 支持多感应器但是需要安装和枚举,这一点有点古怪。
  • three separate installers and a NITE license string (although
    the process can be automated with my auto driver installer)  需要单独安装NITE
  • SDK does not have events for when new Video or new Depth frames
    is available SDK没有此类发生事件,例如:当新的视频或者深度图数据有效时。(翻者:OpenNI提供了类似功能的函数可使用,虽然不是回调函数,但是也很好用)

(Personal) conclusion:Microsoft
seems to have the edge when working with skeletons and/or audio.
微软在骨骼识别和音频方面有优势。(翻者:本人非常认同,微软的音频识别将会在未来的体感游戏里发挥重要的作用!)
OpenNI seems
to be best suited when working on colored pointclouds, on non-Win7 platforms and/or for commercial projects.
OpenNI似乎更适合做一些带颜色的点云的工作,和在非Win7平台来开发商业项目。
When working with gestures in specific: 手势识别 

  • If your sensor only sees the upperbody/hands and/or you want an
    existing framework to start with use OpenNI/NITE. 
    如果你想开发基于上半身或手识别的项目,可以使用OpenNI和NITE
  • When your sensor can see the full body the more stable Microsoft
    skeleton may be the best to use, however you’ll have to code your own gesture recognitions. (You’d also have to extend OpenNI/NITE for fullbody gestures btw)
    全身识别毋庸置疑微软的SDK是最好的,然而你必须自己编写你自己的手势识别代码。

(2):数据获取借鉴的三篇文章:

透過 OpneNI 讀取 Kinect 深度影像資料

http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=215

透過 OpneNI 合併 Kinect 深度以及彩色影像資料

http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=216

透過 OpenNI 建立 Kinect 3D Point Cloud:

http://viml.nchc.org.tw/blog/paper_info.php?CLASS_ID=1&SUB_ID=1&PAPER_ID=217

还有一篇文章,比较详细:

Kinect运用OpenNI产生点云

原文链接:http://blog.csdn.net/opensource07/article/details/7804246

(1):作者的例程:利用OpenNI读取Kinect...

#include <stdlib.h>
#include <iostream>
#include <string> #include <XnCppWrapper.h> using namespace std; void CheckOpenNIError( XnStatus eResult, string sStatus )
{
if( eResult != XN_STATUS_OK )
cerr << sStatus << " Error: " << xnGetStatusString( eResult ) << endl;
} int main( int argc, char** argv )
{
XnStatus eResult = XN_STATUS_OK; // 2. initial context
xn::Context mContext;
eResult = mContext.Init();
CheckOpenNIError( eResult, "initialize context" ); // set map mode
XnMapOutputMode mapMode;
mapMode.nXRes = 640;
mapMode.nYRes = 480;
mapMode.nFPS = 30; // 3. create depth generator
xn::DepthGenerator mDepthGenerator;
eResult = mDepthGenerator.Create( mContext );
CheckOpenNIError( eResult, "Create depth generator" );
eResult = mDepthGenerator.SetMapOutputMode( mapMode ); // 4. start generate data
eResult = mContext.StartGeneratingAll(); // 5. read data
eResult = mContext.WaitAndUpdateAll();
if( eResult == XN_STATUS_OK )
{
// 5. get the depth map
const XnDepthPixel* pDepthMap = mDepthGenerator.GetDepthMap();
// 6. Do something with depth map
}
// 7. stop
mContext.StopGeneratingAll();
mContext.Shutdown(); return 0;
}

(2):合并深度和RGB图像:基于对昌邑程序的修改。

#include <stdlib.h>
#include <iostream>
#include <string> #include <XnCppWrapper.h> using namespace std; void CheckOpenNIError( XnStatus eResult, string sStatus )
{
if( eResult != XN_STATUS_OK )
cerr << sStatus << " Error : " << xnGetStatusString( eResult ) << endl;
} int main( int argc, char** argv )
{
XnStatus eResult = XN_STATUS_OK; // 2. initial context
xn::Context mContext;
eResult = mContext.Init();
CheckOpenNIError( eResult, "initialize context" ); // 3. create depth generator
xn::DepthGenerator mDepthGenerator;
eResult = mDepthGenerator.Create( mContext );
CheckOpenNIError( eResult, "Create depth generator" ); // 4. create image generator
xn::ImageGenerator mImageGenerator;
eResult = mImageGenerator.Create( mContext );
CheckOpenNIError( eResult, "Create image generator" ); // 5. set map mode
XnMapOutputMode mapMode;
mapMode.nXRes = 640;
mapMode.nYRes = 480;
mapMode.nFPS = 30;
eResult = mDepthGenerator.SetMapOutputMode( mapMode );
eResult = mImageGenerator.SetMapOutputMode( mapMode ); // 6. correct view port
mDepthGenerator.GetAlternativeViewPointCap().SetViewPoint( mImageGenerator ); // 7. tart generate data
eResult = mContext.StartGeneratingAll(); // 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();
} // 10. stop
mContext.StopGeneratingAll();
mContext.Shutdown(); return 0;
}

(3):建立3D点云:对上一个程序的修改

定义一个简单的结构体: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。

把座標轉換的部分寫成一個函数
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,這樣可以減少一些索引值的計算;而因為這樣修改,之前讀取彩色影像的程式也要

constXnUInt8* pImageMap = mImageGenerator.GetImageMap();

修改為

constXnRGB24Pixel*
pImageMap = mImageGenerator.GetRGB24ImageMap();

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

// 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 直接一點一點畫出來的話,結果大概就會像上面的影片一樣了∼

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

后记

至此摘抄完毕,编译了程序,点云显示之后,测试程序检测无误....

**PCD数据获取:Kinect+OpenNI+PCL对接(代码)的更多相关文章

  1. Kinect+OpenNI+OpenCV使用

    关于OpenNI,已经可以使用2.0,可以不再使用PrimeSense: 这里的是转载其他人的 OpenCV系列: 原文:http://blog.csdn.net/chenxin_130/articl ...

  2. delphi 连接oracle对接代码

    selectt4.vclen60 as pat_d_codename,t4.vclen60 as pat_sexname,t1.pat_sex,t1.pat_d_code,t1.pat_in_no,t ...

  3. VS2010+PCL+openni配置

    PCL中文论坛:http://www.pclcn.org/bbs/forum.php 1.安装 pcl 的完全安装包可以到: http://pointclouds.org/downloads/wind ...

  4. 三维重建:QT+OpenNI+Kinect图像校正

    后记: 当时能不放弃这个方向是因为这里面涉及了一种很有效的三位场景存储方式,可能给出除图元建模之外的一种三维场景描述方式.这和Flash与位图的对比一样,基于图元的flash始终抵不过基于点描述的位图 ...

  5. PCL点云库中怎样读取指定的PCD文件,又一次命名,处理后保存到指定目录

    我一直想把处理后的pcd文件重命名,然后放到指定的目录,尝试了好久最终做到了: 比方我想读取  "table_scene_lms400.pcd" 把它进行滤波处理,重命名为 &qu ...

  6. Kinect 总结---Kinect基本认识

    玩了Kinect也有差不多一年的时间了,觉得Kinect是个挺好玩挺有未来的玩意.但是很经常做完了一次,下次又得重新看源码,没有把Kinect里的知识总结起来变为自己的知识,所以特意重新总结一下自己使 ...

  7. 使用OpenNI 2获取RGBD摄像头深度信息

    NiViewer 安装好摄像头驱动和OpenNI后,在Tools文件夹中可以找到一个程序NiViewer.NiViewer的一些基本控制方法如下: 1. ESC关闭NiViewer程序 2. 右键可以 ...

  8. PCL中点云数据格式之间的转化

    (1) 关于pcl::PCLPointCloud2::Ptr和pcl::PointCloud<pcl::PointXYZ>两中数据结构的区别 pcl::PointXYZ::PointXYZ ...

  9. Qt Load and Save PCL/PLY 加载和保存点云

    Qt可以跟VTK和PCL等其他库联合使用,十分强大,下面的代码展示了如何使用Qt联合PCL库来加载和保存PCL/PLY格式的点云: 通过按钮加载点云: void QMainWindow::on_pb_ ...

随机推荐

  1. Centos 修改主机名称

    Centos 配置主机名称: 1.首先查询一下当前的主机名称 [root@localhost~]# hostnamectl status Static hostname: ****** //永久主机名 ...

  2. OpenCV实现USM锐化与测试

    OpenCV实现USM锐化 [转]http://www.programdevelop.com/4964391/ USM (Unsharp masking) is a common operation ...

  3. [bzoj1070][SCOI2007]修车_费用流

    修车 bzoj-1070 SCOI-2007 题目大意:有m个人要修n台车,每个工人修不同的车的时间不同,问将所有的车都修完,最少需要花费的时间. 注释:$2\le m\le 9$,$1\le n \ ...

  4. cogs 9. 中心台站建设。。。

    9. 中心台站建设 ★★☆   输入文件:zpj.in   输出文件:zpj.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述]     n个城市之间有通讯网络,从这n个城 ...

  5. TensorFlow 入门之手写识别(MNIST) 数据处理 一

    TensorFlow 入门之手写识别(MNIST) 数据处理 一 MNIST Fly softmax回归 准备数据 解压 与 重构 手写识别入门 MNIST手写数据集 图片以及标签的数据格式处理 准备 ...

  6. Docker入门介绍

    Docker是一种虚拟化技术       刚開始看Docker,感觉非常抽象"An open platform for distributed applications for develo ...

  7. 关于JOS 未对全部内存分页映射之前 物理地址映射问题的思考

    在kern/pmap.c 里面会又以下这段代码,要知道boot_alloc只会分配线性地址,真正建立虚拟页和物理页映射关系的在后面的page_alloc. ////////////////////// ...

  8. 翻译Beginning iOS 7 Development中文版

    不会iOS开发好像真的说只是去,来本中文版的Beginning iOS 7 Development吧. 看了Beginning iOS 7 Development这本书,感觉蛮不错的.全英文的,没有中 ...

  9. JavaScript或者Jqurey把控件id作为參数来调用

    1.JavaScript把控件id作为參数调用 <script type="text/javascript"> function xx(pmba) { document ...

  10. [POJ 2282] The Counting Problem

    [题目链接] http://poj.org/problem?id=2282 [算法] 数位DP [代码] #include <algorithm> #include <bitset& ...