1. 程式人生 > >PCL中的OpenNI採集卡框架(The OpenNI Grabber Framework in PCL)

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

讓我們看看程式碼,來自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]與我們聯絡,我們會找出答案。