从PCL 1.0开始,PCL(三维点云处理库Point Cloud Library)提供了一个通用采集接口,这样可以方便地连接到不同的设备及其驱动、文件格式和其他数据源。PCL集成的第一个数据获取驱动是OpenNI Grabber,它使得从OpenNI兼容的设备请求数据流变得十分通用和简单。

  目前PCL最新的1.8.0版本需要自行编译,而官网上的PCL 1.6.0 All-in-one Installer只支持OpenNI 1。由于我使用的奥比中光3D摄像头只支持OpenNI 2,因此必须使用PCL 1.8.0版本。从源代码开始编译可以参考官网教程Compiling from source,为了图省事我找到一个别人编译好的PCL 1.8.0 All-in-one Installer

  将PCL 1.8.0 All-in-one Installer MSVC2013 Win64下载并安装在默认的C盘路径下“C:\Program Files\PCL 1.8.0”,OpenNI2也装到默认路径下(注意最好安装到默认了路径下,否则可能出现一些问题)。安装好后可以参考官网的教程The OpenNI Grabber Framework in PCL,实现3D点云实时获取。不过官网的教程还停留在OpenNI 1。而在OpenNI 2中OpenNIGrabber()函数的调用方式有所不同,如下所示:

  1. // OpenNI 1:
  2. pcl::Grabber* interface = new pcl::OpenNIGrabber();   // #include <pcl/io/openni_grabber.h>
  3.  
  4. // OpenNI 2:
  5. pcl::Grabber* interface = new pcl::io::OpenNIGrabber(); // #include <pcl/io/openni2_grabber.h>

  注意相应的头文件也要改变。通过下面简单的代码,可以实现从3D体感摄像头中读取深度信息,并实时显示3D点云:

  1. #include <pcl/io/openni2_grabber.h>
  2. #include <pcl/visualization/cloud_viewer.h>
  3.  
  4. class SimpleOpenNIViewer
  5. {
  6. public:
  7. SimpleOpenNIViewer() : viewer("PCL OpenNI Viewer") {} // Construct a cloud viewer, with a window name
  8.  
  9. // 定义回调函数cloud_cb_,获取到数据时对数据进行处理
  10. void cloud_cb_(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &cloud)
  11. {
  12. if (!viewer.wasStopped()) // Check if the gui was quit. true if the user signaled the gui to stop
  13. viewer.showCloud(cloud);
  14. }
  15.  
  16. void run()
  17. {
  18. // create a new grabber for OpenNI devices
  19. pcl::Grabber* interface = new pcl::io::OpenNI2Grabber();
  20.  
  21. // make callback function from member function
  22. boost::function<void(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&)> f =
  23. boost::bind(&SimpleOpenNIViewer::cloud_cb_, this, _1);
  24.  
  25. // connect callback function for desired signal
  26. boost::signals2::connection c = interface->registerCallback(f);
  27.  
  28. // start receiving point clouds
  29. interface->start();
  30.  
  31. while (!viewer.wasStopped())
  32. {
  33. boost::this_thread::sleep(boost::posix_time::seconds());
  34. }
  35.  
  36. // Stop the data acquisition
  37. interface->stop();
  38. }
  39.  
  40. pcl::visualization::CloudViewer viewer;
  41. };
  42.  
  43. int main()
  44. {
  45. SimpleOpenNIViewer v;
  46.  
  47. v.run();
  48.  
  49. return ;
  50. }

  上面代码中SimpleOpenNIViewer的run()函数首先创建了一个新的OpenNI2Grabber接口。接下来用回调函数cloud_cb_地址创建boost::bind对象,给SimpleOpenNIViewer传递一个引用和参数_1作为占位符。The bind then gets casted to a boost::function object which is templated on the callback function type, in this case void (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&). The resulting function object can the be registered with the OpenNIGrabber and subsequently started.

  OpenNIGrabber提供不止一种数据类型,我们可以注册下面几种类型的回调函数:

  1. void (const boost::shared_ptr<const pcl::PointCloud<pcl::PointXYZRGB> >&)

  2. void (const boost::shared_ptr<const pcl::PointCloud<pcl::PointXYZ> >&)

  3. void (const boost::shared_ptr<openni_wrapper::Image>&)  这仅仅提供内置摄像头生成的RGB图像

  4. void (const boost::shared_ptr<openni_wrapper::DepthImage>&)  这个提供深度图像,不带任何颜色或者亮度信息。

  5. void (const boost::shared_ptr<openni_wrapper::Image>&, const boost::shared_ptr<openni_wrapper::DepthImage>&, float constant) 采集器会发送RGB图像和深度图像

  注意:所有需要深度图像和RGB图像流的回调函数类型都会启用一个同步机制,它能保证图像和深度数据的一致。这样引入了一个小的时延,因为同步机制在发送第一张图像之前至少需要等待采集到一组图片。

  调用registerCallback将返回一个boost::signals2::connection对象,上面的例子里我们忽略掉了它。然而,如果你想要中断或者取消一个或多个注册数据流,只需要断开与回调函数的连接,而不用停止整个采集器,这样其他还在进行处理的回调函数可以正常工作:

  1. boost::signals2::connection c = interface (registerCallback (f));
  2.  
  3. // ...
  4.  
  5. if (c.connected ())
  6. c.disconnect ();

  下面通过CMake创建工程文件:

  1. cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
  2.  
  3. project(openni_grabber)
  4.  
  5. find_package(PCL 1.8 REQUIRED)
  6.  
  7. include_directories(${PCL_INCLUDE_DIRS})
  8. link_directories(${PCL_LIBRARY_DIRS})
  9. add_definitions(${PCL_DEFINITIONS})
  10.  
  11. add_executable (openni_grabber openni_grabber.cpp)
  12. target_link_libraries (openni_grabber ${PCL_LIBRARIES})

  从这里开始我遇到了很多奇怪的问题:

  1. 一开始我使用CMake生成VS2010的工程文件,可是在生成工程文件过程中总是出现“common is required but boost was not found”错误:

  按照网上提出的修改CMake文件等方式还是不管用,后来有人说是因为版本问题,应该对应的选择生成VS2013工程文件。

  2. 我又装了一个VS2013,这次选择生成VS2013工程文件,生成过程中出现了一些警告信息,如OPENNI_LIBRARY-NOTFOUND等,忽略这些信息;

  打开成功生成的工程文件,进行编译:

  可是在生成解决方案时,出现了这种错误: fatal error C1001: 编译器中发生内部错误。1>  (编译器文件“msc1.cpp”,第 1325 行)

  网上查找原因,说是VS2013编译器的Bug,需要安装Microsoft Visual Studio 2013 Update 5(适用于Visual Studio 2013的一系列新增功能和Bug修复中的最新更新)。这个更新的安装过程比较漫长...怎么安装这个更新可以参考百度知道:怎样更新VS2013 update 5

  更新装完后再重新生成就可以了,下面是通过获取摄像头探测到的深度信息生成的3D点云:

参考:

The OpenNI Grabber Framework in PCL

PCL中的OpenNI点云获取框架

Capture Point Cloud with PCL 1.8 and Kinect

PCL-1.8.0 All In One安装配置

http://unanancyowen.com/en/pcl18/

pcl/visualization/tools/openni2_viewer.cpp

PCL中的OpenNI点云获取框架(OpenNI Grabber Framework in PCL)的更多相关文章

  1. 在PCL中如何实现点云压缩(2)

    博客转载自:http://www.pclcn.org/study/shownews.php?lang=cn&id=125 压缩配置文件: 压缩配置文件为PCL点云编码器定义了参数集.并针对压缩 ...

  2. 在PCL中如何实现点云压缩(1)

    点云由庞大的数据集组成,这些数据集通过距离.颜色.法线等附加信息来描述空间三维点.此外,点云能以非常高的速率被创建出来,因此需要占用相当大的存储资源,一旦点云需要存储或者通过速率受限制的通信信道进行传 ...

  3. PCL—低层次视觉—点云分割(邻近信息)

    分割给人最直观的影响大概就是邻居和我不一样.比如某条界线这边是中华文明,界线那边是西方文,最简单的分割方式就是在边界上找些居民问:"小伙子,你到底能不能上油管啊?”.然后把能上油管的居民坐标 ...

  4. PCL中outofcore模块---基于核外八叉树的大规模点云的显示

    写在前面   最近公众号的活动让更多的人加入交流群,尝试提问更多的我问题,群主也在积极的招募更多的小伙伴与我一起分享,能够相互促进.   这里总结群友经常问,经常提的两个问题,并给出我的回答: (1) ...

  5. 基于传统方法点云分割以及PCL中分割模块

      之前在微信公众号中更新了以下几个章节 1,如何学习PCL以及一些基础的知识 2,PCL中IO口以及common模块的介绍 3,PCL中常用的两种数据结构KDtree以及Octree树的介绍    ...

  6. PCL中IO模块和类的介绍

    I/O模块中共有21个类 (1)class pcl::FIleReader:定义了PCD文件的读取接口,主要用作其他读取类的父类   pcl::FileReader有pcl::PCDReader和pc ...

  7. PCL中的类

    1. PCLBase pcl_base.h中定义了PCL中的基类PCLBase,PCL中的大部分算法都使用了其中的方法. PCLBase实现了点云数据及其索引的定义和访问. 两个主要的变量input_ ...

  8. kd-tree理论以及在PCL 中的代码的实现

    (小技巧记录:博客园编辑的网页界面变小了使用Ctrl  ++来变大网页字体) 通过雷达,激光扫描,立体摄像机等三维测量设备获取的点云数据,具有数据量大,分布不均匀等特点,作为三维领域中一个重要的数据来 ...

  9. kd-tree理论以及在PCL 中的代码的实现(转载)

    该文转自:https://www.cnblogs.com/li-yao7758258/p/6437440.html kd-tree理论以及在PCL 中的代码的实现   (小技巧记录:博客园编辑的网页界 ...

随机推荐

  1. [转]抢先Mark!微信公众平台开发进阶篇资源集锦

    FROM : http://www.csdn.net/article/2014-08-01/2820986 由CSDN和<程序员>杂志联合主办的 2014年微信开发者大会 将于8月23日在 ...

  2. 微信二维码扫描无法下载APK文件的解决办法

  3. Java NIO和IO的区别(转)

    原文链接:Java NIO和IO的区别 下表总结了Java NIO和IO之间的主要差别,我会更详细地描述表中每部分的差异. 复制代码代码如下: IO                NIO面向流     ...

  4. QT TCP网络编程

    首先介绍一下TCP:(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议.相比而言UDP,就是开放式.无连接.不可靠的传输层 ...

  5. html table奇偶行颜色设置 (CSS选择器)

    :nth-child(n) 选择器匹配属于其父元素的第 N 个子元素,不论元素的类型.n 可以是数字.关键词或公式. 下面的例子, 设置表格的奇偶行背景颜色不同:单独设置表格的第1列背景颜色不同. & ...

  6. Linq to Sql并发冲突及处理策略

    0. 并发冲突的示例 单用户的系统现在应该比较罕见了,一般系统都会有很多用户在同时进行操作:在多用户系统中,涉及到的一个普遍问题:当多个用户“同时”更新(修改或者删除)同一条记录时,该如何更新呢?   ...

  7. 泊松分布E(X^2)

    由于求期望实际就是求平均值,所以E(X^2)=E[X*X]=E[X*X]+E(X)-E(X)=E[X*X+X-X]=E[X(X-1)+X]E[X(X-1)+X]=E[X(X-1)]+E(X)即:和的平 ...

  8. c/c++ 变量作用域

    在程序的不同位置,可能会声明各种不同类型(这里指静态或非静态)的变量.然而,声明的位置不同.类型不同导致每个变量在程序中可以被使用的范围不同.我们把变量在程序中可以使用的有效范围称为变量的作用域. 任 ...

  9. 如何给USB移动硬盘格式化分区

    硬盘盒装好后,插在电脑USB接口上,电脑正常识别到移动硬盘后,但因为全新硬盘没有分区,在"我的电脑"里是看不到盘符的.下面以40G移动硬盘分区讲一下硬盘如何分区.1.操作系统最好是 ...

  10. BigDecimal 的幂次方运算

    public static void main(String[] args){ BigDecimal bg1, bg2; bg1 = new BigDecimal("200000.45&qu ...