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 Grabber
的PCL 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; }
正如你所看到的,SimpleOpenNIViewer
的run ()
函式首先建立一個新的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)
以下程式碼片段將嘗試訂閱depth
和color
流(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]
與我們聯絡,我們會找出答案。