PCL中的OpenNI采集卡框架(The OpenNI Grabber Framework in PCL)

从PCL 1.0开始,我们提供了一个新的通用采集卡接口,以提供对不同设备及其驱动程序,文件格式和其他数据源的顺利和方便的访问。

我们加入的第一个驱动程序是new OpenNI Grabber,它可以轻松地从OpenNI兼容的相机请求数据流。本教程介绍如何设置和使用抓取器,因为它非常简单,所以我们可以保持简短:)。

目前我们测试的相机是Primesense Reference Design,Microsoft Kinect和Asus Xtion Pro相机:

_images / openni_cams.jpg

#简单的例子
在可视化(visualization)中,有一段非常短的代码,其中包含了设置pcl::PointCloud<XYZ>pcl::PointCloud<XYZRGB> 云回调所需的全部代码。

下面是使用OpenNI GrabberPCL OpenNI Viewer的屏幕截图和视频。

_images/pcl_openni_viewer.jpg

Youtube视频

让我们看看代码,来自visualization/tools/openni_viewer_simple.cpp

#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>

class SimpleOpenNIViewer
{
  public:
    SimpleOpenNIViewer () : viewer ("PCL OpenNI Viewer") {}

    void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &cloud)
    {
      if (!viewer.wasStopped())
        viewer.showCloud (cloud);
    }

    void run ()
    {
      pcl::Grabber* interface = new pcl::OpenNIGrabber();

      boost::function<void (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&)> f =
        boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);

      interface->registerCallback (f);

      interface->start ();

      while (!viewer.wasStopped())
      {
        boost::this_thread::sleep (boost::posix_time::seconds (1));
      }

      interface->stop ();
    }

    pcl::visualization::CloudViewer viewer;
};

int main ()
{
  SimpleOpenNIViewer v;
  v.run ();
  return 0;
}

正如你所看到的,SimpleOpenNIViewerrun ()函数首先创建一个新的OpenNIGrabber接口。下一行看起来有点吓人,但并不是那么糟糕。我们用回调函数cloud_cb_的地址创建一个boost::bind对象,我们传递一个参考给SimpleOpenNIViewer和参数占位符(the argument palce holder)_1

然后将bind转换为一个boost::function对象,该对象在回调函数类型上模板化,在这种情况下void (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&)。结果函数对象可以用OpenNIGrabber 注册,然后启动。请注意,stop ()方法并不一定需要调用,因为析构函数会处理这个问题。

#额外细节
OpenNIGrabber提供超过一个以上的数据类型,这是我们所做Grabber接口很通用的原因,导致相对复杂的boost::bind线。实际上,我们可以在撰写本文时注册以下回调类型:

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

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

void (const boost::shared_ptr<openni_wrapper::Image>&)

这只是从内置相机提供的RGB图像。

void (const boost::shared_ptr<openni_wrapper::DepthImage>&)

这提供了深度图像,没有任何颜色或强度信息

void (const boost::shared_ptr<openni_wrapper::Image>&, const boost::shared_ptr<openni_wrapper::DepthImage>&, float constant)

当这种类型的回调被注册时,抓取器将发送RGB图像和深度图像以及常量 (1 / focal length),如果您想进行自己的视差转换,则需要该常量。

注意

所有需要深度和图像流(depth _and_ image stream)的回调类型都会启用同步机制,以确保一致的深度和图像数据。这引入了一个小滞后,因为同步器在发送第一个图像之前需要至少等待一组图像。

#开始和停止流

registerCallback调用返回的boost::signals2::connection对象,这是我们在上面的例子中忽略。但是,如果您想要中断或取消一个或多个已注册的数据流,则可以在不停止整个抓取器(grabber)的情况下调用断开回叫的方式:

boost::signals2::connection = interface (registerCallback (f));

// ...

if (c.connected ())
  c.disconnect ();

#基准(Benchmark)

以下代码片段将尝试订阅depthcolor流(streams),并作为基准测试系统的方式提供。如果您的电脑速度太慢,而您可能无法获得~29Hz+,请联系我们。我们甚至可以进一步优化代码。

#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/openni_grabber.h>
#include <pcl/common/time.h>

class SimpleOpenNIProcessor
{
public:
  void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud)
  {
    static unsigned count = 0;
    static double last = pcl::getTime ();
    if (++count == 30)
    {
      double now = pcl::getTime ();
      std::cout << "distance of center pixel :" << cloud->points [(cloud->width >> 1) * (cloud->height + 1)].z << " mm. Average framerate: " << double(count)/double(now - last) << " Hz" <<  std::endl;
      count = 0;
      last = now;
    }
  }
  
  void run ()
  {
    // create a new grabber for OpenNI devices
    pcl::Grabber* interface = new pcl::OpenNIGrabber();

    // make callback function from member function
    boost::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
      boost::bind (&SimpleOpenNIProcessor::cloud_cb_, this, _1);

    // connect callback function for desired signal. In this case its a point cloud with color values
    boost::signals2::connection c = interface->registerCallback (f);

    // start receiving point clouds
    interface->start ();

    // wait until user quits program with Ctrl-C, but no busy-waiting -> sleep (1);
    while (true)
      boost::this_thread::sleep (boost::posix_time::seconds (1));

    // stop the grabber
    interface->stop ();
  }
};

int main ()
{
  SimpleOpenNIProcessor v;
  v.run ();
  return (0);
}

#编译和运行程序

将下面的行添加到您的CMakeLists.txt文件中:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(openni_grabber)

find_package(PCL 1.2 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (openni_grabber openni_grabber.cpp)
target_link_libraries (openni_grabber ${PCL_LIBRARIES})

#故障排除

问:我得到一个错误,现在设备已连接:

   [OpenNIGrabber] No devices connected. terminate called after throwing an instance of ‘pcl::PCLIOException’ what(): pcl::OpenNIGrabber::OpenNIGrabber(const std::string&) in openni_grabber.cpp @ 69: Device could not be initialized or no devices found. [1] 8709 abort openni_viewer

答:很可能这是XnSensorServer的问题。你有安装ps-engine包吗?XnSensorServer是否存在一个旧的进程,试着杀死它。

问:我收到有关封闭网络连接的错误消息:

    terminate called after throwing an instance of ‘pcl::PCLIOException’ what(): No matching device found. openni_wrapper::OpenNIDevice::OpenNIDevice(xn::Context&, const xn::NodeInfo&, const xn::NodeInfo&, const xn::NodeInfo&, const xn::NodeInfo&) @ /home/andreas/pcl/pcl/trunk/io/src/openni_camera/openni_device.cpp @ 96 : creating depth generator failed. Reason: The network connection has been closed!

答:使用包含gspca_kinect内核模块的较新的Linux内核可能会发生此错误。该模块声称的KIT的USB接口,并防止OpenNI这样做。您可以删除内核模块(rmmod gspca_kinect)或将其黑名单(通过root执行echo “blacklist gspca_kinect” > /etc/modprobe.d/blacklist-psengine.conf)。PCL提供的OpenNI Ubuntu软件包已包含此修复程序,但您可能需要在其他发行版中使用它。

#结论
Grabber界面非常强大,通用性强,可以轻松连接到代码中的OpenNI兼容相机。我们正在编写一个可以使用相同接口的FileGrabber,并且可以从一个目录加载所有Point Cloud文件,并以一定的速率将它们提供给回调。唯一需要改变的是抓取对象(pcl::Grabber *g = new …;)的分配。

如果您想在PCL中使用传感器,请通过[email protected]与我们联系,我们会找出答案。

The OpenNI Grabber Framework in PCL

猜你喜欢

转载自blog.csdn.net/RuoQiQingCheDi/article/details/83959204
pcl