openni_grabber.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of Willow Garage, Inc. nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  */
00037 
00038 #include <pcl/pcl_config.h>
00039 #ifdef HAVE_OPENNI
00040 
00041 #include <pcl/io/openni_grabber.h>
00042 #include <pcl/point_cloud.h>
00043 #include <pcl/point_types.h>
00044 #include <pcl/common/time.h>
00045 #include <pcl/console/print.h>
00046 #include <pcl/io/pcl_io_exception.h>
00047 #include <boost/shared_array.hpp>
00048 #include <boost/filesystem.hpp>
00049 #include <iostream>
00050 
00051 namespace pcl
00052 {
00053   typedef union
00054   {
00055     struct
00056     {
00057       unsigned char Blue;
00058       unsigned char Green;
00059       unsigned char Red;
00060       unsigned char Alpha;
00061     };
00062     float float_value;
00063     uint32_t long_value;
00064   } RGBValue;
00065 }
00066 
00068 pcl::OpenNIGrabber::OpenNIGrabber (const std::string& device_id, const Mode& depth_mode, const Mode& image_mode)
00069   : rgb_sync_ ()
00070   , ir_sync_ ()
00071   , device_ ()
00072   , rgb_frame_id_ ()
00073   , depth_frame_id_ ()
00074   , image_width_ ()
00075   , image_height_ ()
00076   , depth_width_ ()
00077   , depth_height_ ()
00078   , image_required_ (false)
00079   , depth_required_ (false)
00080   , ir_required_ (false)
00081   , sync_required_ (false)
00082   , image_signal_ (), depth_image_signal_ (), ir_image_signal_ (), image_depth_image_signal_ ()
00083   , ir_depth_image_signal_ (), point_cloud_signal_ (), point_cloud_i_signal_ ()
00084   , point_cloud_rgb_signal_ (), point_cloud_rgba_signal_ (), point_cloud_eigen_signal_ ()
00085   , config2xn_map_ (), depth_callback_handle (), image_callback_handle (), ir_callback_handle ()
00086   , running_ (false)
00087 {
00088   // initialize driver
00089   onInit (device_id, depth_mode, image_mode);
00090 
00091   if (!device_->hasDepthStream ())
00092     THROW_PCL_IO_EXCEPTION ("Device does not provide 3D information.");
00093 
00094   depth_image_signal_    = createSignal<sig_cb_openni_depth_image> ();
00095   ir_image_signal_       = createSignal<sig_cb_openni_ir_image> ();
00096   point_cloud_signal_    = createSignal<sig_cb_openni_point_cloud> ();
00097   point_cloud_i_signal_  = createSignal<sig_cb_openni_point_cloud_i> ();
00098   ir_depth_image_signal_ = createSignal<sig_cb_openni_ir_depth_image> ();
00099 
00100   ir_sync_.addCallback (boost::bind (&OpenNIGrabber::irDepthImageCallback, this, _1, _2));
00101   if (device_->hasImageStream ())
00102   {
00103     // create callback signals
00104     image_signal_             = createSignal<sig_cb_openni_image> ();
00105     image_depth_image_signal_ = createSignal<sig_cb_openni_image_depth_image> ();
00106     point_cloud_rgb_signal_   = createSignal<sig_cb_openni_point_cloud_rgb> ();
00107     point_cloud_rgba_signal_  = createSignal<sig_cb_openni_point_cloud_rgba> ();
00108     point_cloud_eigen_signal_ = createSignal<sig_cb_openni_point_cloud_eigen> ();
00109     rgb_sync_.addCallback (boost::bind (&OpenNIGrabber::imageDepthImageCallback, this, _1, _2));
00110     openni_wrapper::DeviceKinect* kinect = dynamic_cast<openni_wrapper::DeviceKinect*> (device_.get ());
00111     if (kinect)
00112       kinect->setDebayeringMethod (openni_wrapper::ImageBayerGRBG::EdgeAware);
00113   }
00114 
00115   image_callback_handle = device_->registerImageCallback (&OpenNIGrabber::imageCallback, *this);
00116   depth_callback_handle = device_->registerDepthCallback (&OpenNIGrabber::depthCallback, *this);
00117   ir_callback_handle    = device_->registerIRCallback (&OpenNIGrabber::irCallback, *this);
00118 }
00119 
00121 pcl::OpenNIGrabber::~OpenNIGrabber () throw ()
00122 {
00123   try
00124   {
00125     stop ();
00126 
00127     // unregister callbacks
00128     device_->unregisterDepthCallback (depth_callback_handle);
00129 
00130     if (device_->hasImageStream ())
00131       device_->unregisterImageCallback (image_callback_handle);
00132 
00133     if (device_->hasIRStream ())
00134       device_->unregisterIRCallback (image_callback_handle);
00135 
00136     // release the pointer to the device object
00137     device_.reset ();
00138     
00139     // disconnect all listeners
00140     disconnect_all_slots<sig_cb_openni_image> ();
00141     disconnect_all_slots<sig_cb_openni_depth_image> ();
00142     disconnect_all_slots<sig_cb_openni_ir_image> ();
00143     disconnect_all_slots<sig_cb_openni_image_depth_image> ();
00144     disconnect_all_slots<sig_cb_openni_point_cloud> ();
00145     disconnect_all_slots<sig_cb_openni_point_cloud_rgb> ();
00146     disconnect_all_slots<sig_cb_openni_point_cloud_rgba> ();
00147     disconnect_all_slots<sig_cb_openni_point_cloud_i> ();
00148     disconnect_all_slots<sig_cb_openni_point_cloud_eigen> ();
00149 
00150     openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
00151     driver.stopAll ();
00152   }
00153   catch (...)
00154   {
00155     // destructor never throws
00156   }
00157 }
00158 
00160 void
00161 pcl::OpenNIGrabber::checkImageAndDepthSynchronizationRequired ()
00162 {
00163   // do we have anyone listening to images or color point clouds?
00164   if (num_slots<sig_cb_openni_point_cloud_rgb>   () > 0 ||
00165       num_slots<sig_cb_openni_point_cloud_rgba>  () > 0 ||
00166       num_slots<sig_cb_openni_point_cloud_eigen> () > 0 ||
00167       num_slots<sig_cb_openni_image_depth_image> () > 0)
00168     sync_required_ = true;
00169   else
00170     sync_required_ = false;
00171 }
00172 
00174 void
00175 pcl::OpenNIGrabber::checkImageStreamRequired ()
00176 {
00177   // do we have anyone listening to images or color point clouds?
00178   if (num_slots<sig_cb_openni_image>             () > 0 ||
00179       num_slots<sig_cb_openni_image_depth_image> () > 0 ||
00180       num_slots<sig_cb_openni_point_cloud_eigen> () > 0 ||
00181       num_slots<sig_cb_openni_point_cloud_rgba>  () > 0 ||
00182       num_slots<sig_cb_openni_point_cloud_rgb>   () > 0)
00183     image_required_ = true;
00184   else
00185     image_required_ = false;
00186 }
00187 
00189 void
00190 pcl::OpenNIGrabber::checkDepthStreamRequired ()
00191 {
00192   // do we have anyone listening to depth images or (color) point clouds?
00193   if (num_slots<sig_cb_openni_depth_image>       () > 0 ||
00194       num_slots<sig_cb_openni_image_depth_image> () > 0 ||
00195       num_slots<sig_cb_openni_ir_depth_image>    () > 0 ||
00196       num_slots<sig_cb_openni_point_cloud_eigen> () > 0 ||
00197       num_slots<sig_cb_openni_point_cloud_rgb>   () > 0 ||
00198       num_slots<sig_cb_openni_point_cloud_rgba>  () > 0 ||
00199       num_slots<sig_cb_openni_point_cloud>       () > 0 ||
00200       num_slots<sig_cb_openni_point_cloud_i>     () > 0 )
00201     depth_required_ = true;
00202   else
00203     depth_required_ = false;
00204 }
00205 
00207 void
00208 pcl::OpenNIGrabber::checkIRStreamRequired ()
00209 {
00210   if (num_slots<sig_cb_openni_ir_image>       () > 0 ||
00211       num_slots<sig_cb_openni_point_cloud_i>  () > 0 ||
00212       num_slots<sig_cb_openni_ir_depth_image> () > 0)
00213     ir_required_ = true;
00214   else
00215     ir_required_ = false;
00216 }
00217 
00219 void
00220 pcl::OpenNIGrabber::start ()
00221 {
00222   try
00223   {
00224     // check if we need to start/stop any stream
00225     if (image_required_ && !device_->isImageStreamRunning ())
00226     {
00227       block_signals ();
00228       device_->startImageStream ();
00229       //startSynchronization ();
00230     }
00231 
00232     if (depth_required_ && !device_->isDepthStreamRunning ())
00233     {
00234       block_signals ();
00235       if (device_->hasImageStream () && !device_->isDepthRegistered () && device_->isDepthRegistrationSupported ())
00236       {
00237         device_->setDepthRegistration (true);
00238       }
00239       device_->startDepthStream ();
00240       //startSynchronization ();
00241     }
00242 
00243     if (ir_required_ && !device_->isIRStreamRunning ())
00244     {
00245       block_signals ();
00246       device_->startIRStream ();
00247     }
00248     running_ = true;
00249   }
00250   catch (openni_wrapper::OpenNIException& ex)
00251   {
00252     THROW_PCL_IO_EXCEPTION ("Could not start streams. Reason: %s", ex.what ());
00253   }
00254   // workaround, since the first frame is corrupted
00255   boost::this_thread::sleep (boost::posix_time::seconds (1));
00256   unblock_signals ();
00257 }
00258 
00260 void
00261 pcl::OpenNIGrabber::stop ()
00262 {
00263   try
00264   {
00265     if (device_->hasDepthStream () && device_->isDepthStreamRunning ())
00266       device_->stopDepthStream ();
00267 
00268     if (device_->hasImageStream () && device_->isImageStreamRunning ())
00269       device_->stopImageStream ();
00270 
00271     if (device_->hasIRStream () && device_->isIRStreamRunning ())
00272       device_->stopIRStream ();
00273 
00274     running_ = false;
00275   }
00276   catch (openni_wrapper::OpenNIException& ex)
00277   {
00278     THROW_PCL_IO_EXCEPTION ("Could not stop streams. Reason: %s", ex.what ());
00279   }
00280 }
00281 
00283 bool
00284 pcl::OpenNIGrabber::isRunning () const
00285 {
00286   return (running_);
00287 }
00288 
00290 void
00291 pcl::OpenNIGrabber::onInit (const std::string& device_id, const Mode& depth_mode, const Mode& image_mode)
00292 {
00293   updateModeMaps (); // registering mapping from config modes to XnModes and vice versa
00294   setupDevice (device_id, depth_mode, image_mode);
00295 
00296   rgb_frame_id_ = "/openni_rgb_optical_frame";
00297 
00298   depth_frame_id_ = "/openni_depth_optical_frame";
00299 }
00300 
00302 void
00303 pcl::OpenNIGrabber::signalsChanged ()
00304 {
00305   // reevaluate which streams are required
00306   checkImageStreamRequired ();
00307   checkDepthStreamRequired ();
00308   checkIRStreamRequired ();
00309   if (ir_required_ && image_required_)
00310     THROW_PCL_IO_EXCEPTION ("Can not provide IR stream and RGB stream at the same time.");
00311 
00312   checkImageAndDepthSynchronizationRequired ();
00313   if (running_)
00314     start ();
00315 }
00316 
00318 std::string
00319 pcl::OpenNIGrabber::getName () const
00320 {
00321   return std::string ("OpenNIGrabber");
00322 }
00323 
00325 void
00326 pcl::OpenNIGrabber::setupDevice (const std::string& device_id, const Mode& depth_mode, const Mode& image_mode)
00327 {
00328   // Initialize the openni device
00329   openni_wrapper::OpenNIDriver& driver = openni_wrapper::OpenNIDriver::getInstance ();
00330 
00331   try
00332   {
00333     if (boost::filesystem::exists (device_id))
00334     {
00335       device_ = driver.createVirtualDevice (device_id, true, true);
00336     }
00337     else if (driver.getNumberDevices () == 0)
00338     {
00339       THROW_PCL_IO_EXCEPTION ("No devices connected.");
00340     }
00341     else if (device_id[0] == '#')
00342     {
00343       unsigned index = atoi (device_id.c_str () + 1);
00344       //printf("[%s] searching for device with index = %d\n", getName().c_str(), index);
00345       device_ = driver.getDeviceByIndex (index - 1);
00346     }
00347 #ifndef _WIN32
00348     else if (device_id.find ('@') != std::string::npos)
00349     {
00350       size_t pos = device_id.find ('@');
00351       unsigned bus = atoi (device_id.substr (0, pos).c_str ());
00352       unsigned address = atoi (device_id.substr (pos + 1, device_id.length () - pos - 1).c_str ());
00353       //printf("[%s] searching for device with bus@address = %d@%d\n", getName().c_str(), bus, address);
00354       device_ = driver.getDeviceByAddress (static_cast<unsigned char>(bus), static_cast<unsigned char>(address) );
00355     }
00356 #endif
00357     else if (!device_id.empty ())
00358     {
00359       //printf("[%s] searching for device with serial number = %s\n", getName().c_str(), device_id.c_str());
00360       device_ = driver.getDeviceBySerialNumber (device_id);
00361     }
00362     else
00363     {
00364       device_ = driver.getDeviceByIndex (0);
00365     }
00366   }
00367   catch (const openni_wrapper::OpenNIException& exception)
00368   {
00369     if (!device_)
00370       THROW_PCL_IO_EXCEPTION ("No matching device found. %s", exception.what ());
00371     else
00372       THROW_PCL_IO_EXCEPTION ("could not retrieve device. Reason %s", exception.what ());
00373   }
00374   catch (const pcl::PCLIOException&)
00375   {
00376     throw;
00377   }
00378   catch (...)
00379   {
00380     THROW_PCL_IO_EXCEPTION ("unknown error occured");
00381   }
00382 
00383   XnMapOutputMode depth_md;
00384   // Set the selected output mode
00385   if (depth_mode != OpenNI_Default_Mode)
00386   {
00387     XnMapOutputMode actual_depth_md;
00388     if (!mapConfigMode2XnMode (depth_mode, depth_md) || !device_->findCompatibleDepthMode (depth_md, actual_depth_md))
00389       THROW_PCL_IO_EXCEPTION ("could not find compatible depth stream mode %d", static_cast<int> (depth_mode) );
00390 
00391     XnMapOutputMode current_depth_md =  device_->getDepthOutputMode ();
00392     if (current_depth_md.nXRes != actual_depth_md.nXRes || current_depth_md.nYRes != actual_depth_md.nYRes)
00393       device_->setDepthOutputMode (actual_depth_md);
00394   }
00395   else
00396   {
00397     depth_md = device_->getDefaultDepthMode ();
00398   }
00399 
00400   depth_width_ = depth_md.nXRes;
00401   depth_height_ = depth_md.nYRes;
00402   
00403   if (device_->hasImageStream ())
00404   {
00405     XnMapOutputMode image_md;
00406     if (image_mode != OpenNI_Default_Mode)
00407     {
00408       XnMapOutputMode actual_image_md;
00409       if (!mapConfigMode2XnMode (image_mode, image_md) || !device_->findCompatibleImageMode (image_md, actual_image_md))
00410         THROW_PCL_IO_EXCEPTION ("could not find compatible image stream mode %d", static_cast<int> (image_mode) );
00411 
00412       XnMapOutputMode current_image_md =  device_->getImageOutputMode ();
00413       if (current_image_md.nXRes != actual_image_md.nXRes || current_image_md.nYRes != actual_image_md.nYRes)
00414         device_->setImageOutputMode (actual_image_md);
00415     }
00416     else
00417     {
00418       image_md = device_->getDefaultImageMode ();
00419     }
00420 
00421     image_width_  = image_md.nXRes;
00422     image_height_ = image_md.nYRes;
00423   }
00424 }
00425 
00427 void
00428 pcl::OpenNIGrabber::startSynchronization ()
00429 {
00430   try
00431   {
00432     if (device_->isSynchronizationSupported () && !device_->isSynchronized () &&
00433         device_->getImageOutputMode ().nFPS == device_->getDepthOutputMode ().nFPS &&
00434         device_->isImageStreamRunning () && device_->isDepthStreamRunning ())
00435         device_->setSynchronization (true);
00436   }
00437   catch (const openni_wrapper::OpenNIException& exception)
00438   {
00439     THROW_PCL_IO_EXCEPTION ("Could not start synchronization %s", exception.what ());
00440   }
00441 }
00442 
00444 void
00445 pcl::OpenNIGrabber::stopSynchronization ()
00446 {
00447   try
00448   {
00449     if (device_->isSynchronizationSupported () && device_->isSynchronized ())
00450       device_->setSynchronization (false);
00451   }
00452   catch (const openni_wrapper::OpenNIException& exception)
00453   {
00454     THROW_PCL_IO_EXCEPTION ("Could not start synchronization %s", exception.what ());
00455   }
00456 }
00457 
00459 void
00460 pcl::OpenNIGrabber::imageCallback (boost::shared_ptr<openni_wrapper::Image> image, void*)
00461 {
00462   if (num_slots<sig_cb_openni_point_cloud_rgb>   () > 0 ||
00463       num_slots<sig_cb_openni_point_cloud_rgba>  () > 0 ||
00464       num_slots<sig_cb_openni_point_cloud_eigen> () > 0 ||
00465       num_slots<sig_cb_openni_image_depth_image> () > 0)
00466     rgb_sync_.add0 (image, image->getTimeStamp ());
00467 
00468   if (image_signal_->num_slots () > 0)
00469     image_signal_->operator()(image);
00470 }
00471 
00473 void
00474 pcl::OpenNIGrabber::depthCallback (boost::shared_ptr<openni_wrapper::DepthImage> depth_image, void*)
00475 {
00476   if (num_slots<sig_cb_openni_point_cloud_rgb>   () > 0 ||
00477       num_slots<sig_cb_openni_point_cloud_rgba>  () > 0 ||
00478       num_slots<sig_cb_openni_point_cloud_eigen> () > 0 ||
00479       num_slots<sig_cb_openni_image_depth_image> () > 0)
00480     rgb_sync_.add1 (depth_image, depth_image->getTimeStamp ());
00481 
00482   if (num_slots<sig_cb_openni_point_cloud_i>  () > 0 ||
00483       num_slots<sig_cb_openni_ir_depth_image> () > 0)
00484     ir_sync_.add1 (depth_image, depth_image->getTimeStamp ());
00485 
00486   if (depth_image_signal_->num_slots () > 0)
00487     depth_image_signal_->operator()(depth_image);
00488 
00489   if (point_cloud_signal_->num_slots () > 0)
00490     point_cloud_signal_->operator()(convertToXYZPointCloud(depth_image));
00491 }
00492 
00494 void
00495 pcl::OpenNIGrabber::irCallback (boost::shared_ptr<openni_wrapper::IRImage> ir_image, void*)
00496 {
00497   if (num_slots<sig_cb_openni_point_cloud_i>  () > 0 ||
00498       num_slots<sig_cb_openni_ir_depth_image> () > 0)
00499     ir_sync_.add0(ir_image, ir_image->getTimeStamp ());
00500 
00501   if (ir_image_signal_->num_slots () > 0)
00502     ir_image_signal_->operator()(ir_image);
00503 }
00504 
00506 void
00507 pcl::OpenNIGrabber::imageDepthImageCallback (const boost::shared_ptr<openni_wrapper::Image> &image,
00508                                              const boost::shared_ptr<openni_wrapper::DepthImage> &depth_image)
00509 {
00510   // check if we have color point cloud slots
00511   if (point_cloud_rgb_signal_->num_slots () > 0)
00512   {
00513     PCL_WARN ("PointXYZRGB callbacks deprecated. Use PointXYZRGBA instead.\n");
00514     point_cloud_rgb_signal_->operator()(convertToXYZRGBPointCloud<pcl::PointXYZRGB> (image, depth_image));
00515   }
00516 
00517   if (point_cloud_rgba_signal_->num_slots () > 0)
00518     point_cloud_rgba_signal_->operator()(convertToXYZRGBPointCloud<pcl::PointXYZRGBA> (image, depth_image));
00519 
00520   // check if we have color point cloud slots
00521   if (point_cloud_eigen_signal_->num_slots () > 0)
00522     point_cloud_eigen_signal_->operator()(convertToEigenPointCloud (image, depth_image));
00523 
00524   if (image_depth_image_signal_->num_slots () > 0)
00525   {
00526     float constant = 1.0f / device_->getDepthFocalLength (depth_width_);
00527     image_depth_image_signal_->operator()(image, depth_image, constant);
00528   }
00529 }
00530 
00532 void
00533 pcl::OpenNIGrabber::irDepthImageCallback (const boost::shared_ptr<openni_wrapper::IRImage> &ir_image,
00534                                           const boost::shared_ptr<openni_wrapper::DepthImage> &depth_image)
00535 {
00536   // check if we have color point cloud slots
00537   if (point_cloud_i_signal_->num_slots () > 0)
00538     point_cloud_i_signal_->operator()(convertToXYZIPointCloud (ir_image, depth_image));
00539 
00540   if (ir_depth_image_signal_->num_slots () > 0)
00541   {
00542     float constant = 1.0f / device_->getDepthFocalLength (depth_width_);
00543     ir_depth_image_signal_->operator()(ir_image, depth_image, constant);
00544   }
00545 }
00546 
00548 pcl::PointCloud<pcl::PointXYZ>::Ptr
00549 pcl::OpenNIGrabber::convertToXYZPointCloud (const boost::shared_ptr<openni_wrapper::DepthImage>& depth_image) const
00550 {
00551   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud <pcl::PointXYZ>);
00552 
00553   cloud->height = depth_height_;
00554   cloud->width = depth_width_;
00555   cloud->is_dense = false;
00556 
00557   cloud->points.resize (cloud->height * cloud->width);
00558 
00559   register float constant = 1.0f / device_->getDepthFocalLength (depth_width_);
00560 
00561   if (device_->isDepthRegistered ())
00562     cloud->header.frame_id = rgb_frame_id_;
00563   else
00564     cloud->header.frame_id = depth_frame_id_;
00565 
00566   register int centerX = (cloud->width >> 1);
00567   int centerY = (cloud->height >> 1);
00568 
00569   float bad_point = std::numeric_limits<float>::quiet_NaN ();
00570 
00571   // we have to use Data, since operator[] uses assert -> Debug-mode very slow!
00572   register const unsigned short* depth_map = depth_image->getDepthMetaData ().Data ();
00573   if (depth_image->getWidth() != depth_width_ || depth_image->getHeight () != depth_height_)
00574   {
00575     static unsigned buffer_size = 0;
00576     static boost::shared_array<unsigned short> depth_buffer (0);
00577 
00578     if (buffer_size < depth_width_ * depth_height_)
00579     {
00580       buffer_size = depth_width_ * depth_height_;
00581       depth_buffer.reset (new unsigned short [buffer_size]);
00582     }
00583     depth_image->fillDepthImageRaw (depth_width_, depth_height_, depth_buffer.get ());
00584     depth_map = depth_buffer.get ();
00585   }
00586 
00587   register int depth_idx = 0;
00588   for (int v = -centerY; v < centerY; ++v)
00589   {
00590     for (register int u = -centerX; u < centerX; ++u, ++depth_idx)
00591     {
00592       pcl::PointXYZ& pt = cloud->points[depth_idx];
00593       // Check for invalid measurements
00594       if (depth_map[depth_idx] == 0 ||
00595           depth_map[depth_idx] == depth_image->getNoSampleValue () ||
00596           depth_map[depth_idx] == depth_image->getShadowValue ())
00597       {
00598         // not valid
00599         pt.x = pt.y = pt.z = bad_point;
00600         continue;
00601       }
00602       pt.z = depth_map[depth_idx] * 0.001f;
00603       pt.x = static_cast<float> (u) * pt.z * constant;
00604       pt.y = static_cast<float> (v) * pt.z * constant;
00605     }
00606   }
00607   cloud->sensor_origin_.setZero ();
00608   cloud->sensor_orientation_.w () = 0.0f;
00609   cloud->sensor_orientation_.x () = 1.0f;
00610   cloud->sensor_orientation_.y () = 0.0f;
00611   cloud->sensor_orientation_.z () = 0.0f;  
00612   return (cloud);
00613 }
00614 
00616 template <typename PointT> typename pcl::PointCloud<PointT>::Ptr
00617 pcl::OpenNIGrabber::convertToXYZRGBPointCloud (const boost::shared_ptr<openni_wrapper::Image> &image,
00618                                                const boost::shared_ptr<openni_wrapper::DepthImage> &depth_image) const
00619 {
00620   static unsigned rgb_array_size = 0;
00621   static boost::shared_array<unsigned char> rgb_array (0);
00622   static unsigned char* rgb_buffer = 0;
00623 
00624   boost::shared_ptr<pcl::PointCloud<PointT> > cloud (new pcl::PointCloud<PointT>);
00625 
00626   cloud->header.frame_id = rgb_frame_id_;
00627   cloud->height = std::max (image_height_, depth_height_);
00628   cloud->width = std::max (image_width_, depth_width_);
00629   cloud->is_dense = false;
00630 
00631   cloud->points.resize (cloud->height * cloud->width);
00632 
00633   float constant = 1.0f / device_->getImageFocalLength (depth_width_);
00634   register int centerX = (depth_width_ >> 1);
00635   int centerY = (depth_height_ >> 1);
00636 
00637   register const XnDepthPixel* depth_map = depth_image->getDepthMetaData ().Data ();
00638   if (depth_image->getWidth () != depth_width_ || depth_image->getHeight() != depth_height_)
00639   {
00640     static unsigned buffer_size = 0;
00641     static boost::shared_array<unsigned short> depth_buffer (0);
00642 
00643     if (buffer_size < depth_width_ * depth_height_)
00644     {
00645       buffer_size = depth_width_ * depth_height_;
00646       depth_buffer.reset (new unsigned short [buffer_size]);
00647     }
00648 
00649     depth_image->fillDepthImageRaw (depth_width_, depth_height_, depth_buffer.get ());
00650     depth_map = depth_buffer.get ();
00651   }
00652 
00653   // here we need exact the size of the point cloud for a one-one correspondence!
00654   if (rgb_array_size < image_width_ * image_height_ * 3)
00655   {
00656     rgb_array_size = image_width_ * image_height_ * 3;
00657     rgb_array.reset (new unsigned char [rgb_array_size]);
00658     rgb_buffer = rgb_array.get ();
00659   }
00660   image->fillRGB (image_width_, image_height_, rgb_buffer, image_width_ * 3);
00661   float bad_point = std::numeric_limits<float>::quiet_NaN ();
00662 
00663   // set xyz to Nan and rgb to 0 (black)  
00664   if (image_width_ != depth_width_)
00665   {
00666     PointT pt;
00667     pt.x = pt.y = pt.z = bad_point;
00668     pt.b = pt.g = pt.r = 0;
00669     pt.a = 255; // point has no color info -> alpha = max => transparent 
00670     cloud->points.assign (cloud->points.size (), pt);
00671   }
00672   
00673   // fill in XYZ values
00674   unsigned step = cloud->width / depth_width_;
00675   unsigned skip = cloud->width * step - cloud->width;
00676   
00677   int value_idx = 0;
00678   int point_idx = 0;
00679   for (int v = -centerY; v < centerY; ++v, point_idx += skip)
00680   {
00681     for (register int u = -centerX; u < centerX; ++u, ++value_idx, point_idx += step)
00682     {
00683       PointT& pt = cloud->points[point_idx];
00685       // Check for invalid measurements
00686 
00687       if (depth_map[value_idx] != 0 &&
00688           depth_map[value_idx] != depth_image->getNoSampleValue () &&
00689           depth_map[value_idx] != depth_image->getShadowValue ())
00690       {
00691         pt.z = depth_map[value_idx] * 0.001f;
00692         pt.x = static_cast<float> (u) * pt.z * constant;
00693         pt.y = static_cast<float> (v) * pt.z * constant;
00694       }
00695       else
00696       {
00697         pt.x = pt.y = pt.z = bad_point;
00698       }
00699     }
00700   }
00701 
00702   // fill in the RGB values
00703   step = cloud->width / image_width_;
00704   skip = cloud->width * step - cloud->width;
00705   
00706   value_idx = 0;
00707   point_idx = 0;
00708   RGBValue color;
00709   color.Alpha = 0;
00710 
00711   for (unsigned yIdx = 0; yIdx < image_height_; ++yIdx, point_idx += skip)
00712   {
00713     for (unsigned xIdx = 0; xIdx < image_width_; ++xIdx, point_idx += step, value_idx += 3)
00714     {
00715       PointT& pt = cloud->points[point_idx];
00716       
00717       color.Red   = rgb_buffer[value_idx];
00718       color.Green = rgb_buffer[value_idx + 1];
00719       color.Blue  = rgb_buffer[value_idx + 2];
00720       
00721       pt.rgba = color.long_value;
00722     }
00723   }
00724   cloud->sensor_origin_.setZero ();
00725   cloud->sensor_orientation_.w () = 0.0;
00726   cloud->sensor_orientation_.x () = 1.0;
00727   cloud->sensor_orientation_.y () = 0.0;
00728   cloud->sensor_orientation_.z () = 0.0;
00729   return (cloud);
00730 }
00731 
00733 pcl::PointCloud<Eigen::MatrixXf>::Ptr
00734 pcl::OpenNIGrabber::convertToEigenPointCloud (const boost::shared_ptr<openni_wrapper::Image> &image,
00735                                               const boost::shared_ptr<openni_wrapper::DepthImage> &depth_image) const
00736 {
00737   static unsigned rgb_array_size = 0;
00738   static boost::shared_array<unsigned char> rgb_array (0);
00739   static unsigned char* rgb_buffer = 0;
00740 
00741   boost::shared_ptr<pcl::PointCloud<Eigen::MatrixXf> > cloud (new pcl::PointCloud<Eigen::MatrixXf>);
00742 
00743   cloud->properties.acquisition_time = depth_image->getTimeStamp ();
00744   cloud->height = depth_height_;
00745   cloud->width = depth_width_;
00746   cloud->is_dense = false;
00747   // Prepare channels. Default soring order for channels is: rgb x y z
00748   cloud->channels["rgb"].name = "rgb";
00749   cloud->channels["x"].name = "x"; cloud->channels["y"].name = "y"; cloud->channels["z"].name = "z";
00750   cloud->channels["rgb"].offset = 0;
00751   cloud->channels["x"].offset = 4; cloud->channels["y"].offset = 8; cloud->channels["z"].offset = 12;
00752   cloud->channels["x"].size = cloud->channels["y"].size = cloud->channels["z"].size = cloud->channels["rgb"].size = 4;
00753   cloud->channels["rgb"].datatype = 6;
00754   cloud->channels["x"].datatype = cloud->channels["y"].datatype = cloud->channels["z"].datatype = 7;
00755   cloud->channels["x"].count = cloud->channels["y"].count = cloud->channels["z"].count = cloud->channels["rgb"].count = 1;
00756 
00757   // Resize the output to width * height * 4Bpp (xyz+rgb)
00758   cloud->points.resize (cloud->height * cloud->width, 4);
00759 
00760   float constant = 1.0f / device_->getImageFocalLength (cloud->width);
00761   register int centerX = (cloud->width >> 1);
00762   int centerY = (cloud->height >> 1);
00763 
00764   register const XnDepthPixel* depth_map = depth_image->getDepthMetaData ().Data ();
00765   if (depth_image->getWidth () != depth_width_ || depth_image->getHeight() != depth_height_)
00766   {
00767     static unsigned buffer_size = 0;
00768     static boost::shared_array<unsigned short> depth_buffer (0);
00769 
00770     if (buffer_size < depth_width_ * depth_height_)
00771     {
00772       buffer_size = depth_width_ * depth_height_;
00773       depth_buffer.reset (new unsigned short [buffer_size]);
00774     }
00775 
00776     depth_image->fillDepthImageRaw (depth_width_, depth_height_, depth_buffer.get ());
00777     depth_map = depth_buffer.get ();
00778   }
00779 
00780   // here we need exact the size of the point cloud for a one-one correspondence!
00781   if (rgb_array_size < image_width_ * image_height_ * 3)
00782   {
00783     rgb_array_size = image_width_ * image_height_ * 3;
00784     rgb_array.reset (new unsigned char [rgb_array_size]);
00785     rgb_buffer = rgb_array.get ();
00786   }
00787   image->fillRGB (image_width_, image_height_, rgb_buffer, image_width_ * 3);
00788 
00789   // depth_image already has the desired dimensions, but rgb_msg may be higher res.
00790   register int color_idx = 0, depth_idx = 0;
00791   RGBValue color;
00792   color.Alpha = 0;
00793 
00794   float bad_point = std::numeric_limits<float>::quiet_NaN ();
00795 
00796   for (int v = -centerY; v < centerY; ++v)
00797   {
00798     for (register int u = -centerX; u < centerX; ++u, color_idx += 3, ++depth_idx)
00799     {
00801       // Check for invalid measurements
00802       if (depth_map[depth_idx] == 0 ||
00803           depth_map[depth_idx] == depth_image->getNoSampleValue () ||
00804           depth_map[depth_idx] == depth_image->getShadowValue ())
00805       {
00806         cloud->points.row (depth_idx).setConstant (bad_point);
00807       }
00808       else
00809       {
00810         cloud->points (depth_idx, 3) = depth_map[depth_idx] * 0.001f;
00811         cloud->points (depth_idx, 1) = static_cast<float> (u) * cloud->points (depth_idx, 3) * constant;
00812         cloud->points (depth_idx, 2) = static_cast<float> (v) * cloud->points (depth_idx, 3) * constant;
00813       }
00814 
00815       // Fill in color
00816       color.Red = rgb_buffer[color_idx];
00817       color.Green = rgb_buffer[color_idx + 1];
00818       color.Blue = rgb_buffer[color_idx + 2];
00819       cloud->points (depth_idx, 0) = color.float_value;
00820     }
00821   }
00822   return (cloud);
00823 }
00824 
00826 pcl::PointCloud<pcl::PointXYZI>::Ptr
00827 pcl::OpenNIGrabber::convertToXYZIPointCloud (const boost::shared_ptr<openni_wrapper::IRImage> &ir_image,
00828                                              const boost::shared_ptr<openni_wrapper::DepthImage> &depth_image) const
00829 {
00830   boost::shared_ptr<pcl::PointCloud<pcl::PointXYZI> > cloud (new pcl::PointCloud<pcl::PointXYZI > ());
00831 
00832   cloud->header.frame_id = rgb_frame_id_;
00833   cloud->height = depth_height_;
00834   cloud->width = depth_width_;
00835   cloud->is_dense = false;
00836 
00837   cloud->points.resize (cloud->height * cloud->width);
00838 
00839   float constant = 1.0f / device_->getImageFocalLength (cloud->width);
00840   register int centerX = (cloud->width >> 1);
00841   int centerY = (cloud->height >> 1);
00842 
00843   register const XnDepthPixel* depth_map = depth_image->getDepthMetaData ().Data ();
00844   register const XnIRPixel* ir_map = ir_image->getMetaData ().Data ();
00845 
00846   if (depth_image->getWidth () != depth_width_ || depth_image->getHeight () != depth_height_)
00847   {
00848     static unsigned buffer_size = 0;
00849     static boost::shared_array<unsigned short> depth_buffer (0);
00850     static boost::shared_array<unsigned short> ir_buffer (0);
00851 
00852     if (buffer_size < depth_width_ * depth_height_)
00853     {
00854       buffer_size = depth_width_ * depth_height_;
00855       depth_buffer.reset (new unsigned short [buffer_size]);
00856       ir_buffer.reset (new unsigned short [buffer_size]);
00857     }
00858 
00859     depth_image->fillDepthImageRaw (depth_width_, depth_height_, depth_buffer.get ());
00860     depth_map = depth_buffer.get ();
00861 
00862     ir_image->fillRaw (depth_width_, depth_height_, ir_buffer.get ());
00863     ir_map = ir_buffer.get ();
00864   }
00865 
00866   register int depth_idx = 0;
00867   float bad_point = std::numeric_limits<float>::quiet_NaN ();
00868 
00869   for (int v = -centerY; v < centerY; ++v)
00870   {
00871     for (register int u = -centerX; u < centerX; ++u, ++depth_idx)
00872     {
00873       pcl::PointXYZI& pt = cloud->points[depth_idx];
00875       // Check for invalid measurements
00876       if (depth_map[depth_idx] == 0 ||
00877           depth_map[depth_idx] == depth_image->getNoSampleValue () ||
00878           depth_map[depth_idx] == depth_image->getShadowValue ())
00879       {
00880         pt.x = pt.y = pt.z = bad_point;
00881       }
00882       else
00883       {
00884         pt.z = depth_map[depth_idx] * 0.001f;
00885         pt.x = static_cast<float> (u) * pt.z * constant;
00886         pt.y = static_cast<float> (v) * pt.z * constant;
00887       }
00888 
00889       pt.data_c[0] = pt.data_c[1] = pt.data_c[2] = pt.data_c[3] = 0;
00890       pt.intensity = static_cast<float> (ir_map[depth_idx]);
00891     }
00892   }
00893   return (cloud);
00894 }
00895 
00897 // TODO: delete me?
00898 void
00899 pcl::OpenNIGrabber::updateModeMaps ()
00900 {
00901   XnMapOutputMode output_mode;
00902 
00903   output_mode.nXRes = XN_SXGA_X_RES;
00904   output_mode.nYRes = XN_SXGA_Y_RES;
00905   output_mode.nFPS = 15;
00906   config2xn_map_[OpenNI_SXGA_15Hz] = output_mode;
00907 
00908   output_mode.nXRes = XN_VGA_X_RES;
00909   output_mode.nYRes = XN_VGA_Y_RES;
00910   output_mode.nFPS = 25;
00911   config2xn_map_[OpenNI_VGA_25Hz] = output_mode;
00912   output_mode.nFPS = 30;
00913   config2xn_map_[OpenNI_VGA_30Hz] = output_mode;
00914 
00915   output_mode.nXRes = XN_QVGA_X_RES;
00916   output_mode.nYRes = XN_QVGA_Y_RES;
00917   output_mode.nFPS = 25;
00918   config2xn_map_[OpenNI_QVGA_25Hz] = output_mode;
00919   output_mode.nFPS = 30;
00920   config2xn_map_[OpenNI_QVGA_30Hz] = output_mode;
00921   output_mode.nFPS = 60;
00922   config2xn_map_[OpenNI_QVGA_60Hz] = output_mode;
00923 
00924   output_mode.nXRes = XN_QQVGA_X_RES;
00925   output_mode.nYRes = XN_QQVGA_Y_RES;
00926   output_mode.nFPS = 25;
00927   config2xn_map_[OpenNI_QQVGA_25Hz] = output_mode;
00928   output_mode.nFPS = 30;
00929   config2xn_map_[OpenNI_QQVGA_30Hz] = output_mode;
00930   output_mode.nFPS = 60;
00931   config2xn_map_[OpenNI_QQVGA_60Hz] = output_mode;
00932 }
00933 
00935 bool
00936 pcl::OpenNIGrabber::mapConfigMode2XnMode (int mode, XnMapOutputMode &xnmode) const
00937 {
00938   std::map<int, XnMapOutputMode>::const_iterator it = config2xn_map_.find (mode);
00939   if (it != config2xn_map_.end ())
00940   {
00941     xnmode = it->second;
00942     return (true);
00943   }
00944   else
00945   {
00946     return (false);
00947   }
00948 }
00949 
00951 std::vector<std::pair<int, XnMapOutputMode> >
00952 pcl::OpenNIGrabber::getAvailableDepthModes () const
00953 {
00954   XnMapOutputMode dummy;
00955   std::vector<std::pair<int, XnMapOutputMode> > result;
00956   for (std::map<int, XnMapOutputMode>::const_iterator it = config2xn_map_.begin (); it != config2xn_map_.end (); ++it)
00957   {
00958     if (device_->findCompatibleDepthMode (it->second, dummy))
00959       result.push_back (*it);
00960   }
00961 
00962   return (result);
00963 }
00964 
00966 std::vector<std::pair<int, XnMapOutputMode> >
00967 pcl::OpenNIGrabber::getAvailableImageModes () const
00968 {
00969   XnMapOutputMode dummy;
00970   std::vector<std::pair<int, XnMapOutputMode> > result;
00971   for (std::map<int, XnMapOutputMode>::const_iterator it = config2xn_map_.begin (); it != config2xn_map_.end (); ++it)
00972   {
00973     if (device_->findCompatibleImageMode (it->second, dummy))
00974       result.push_back (*it);
00975   }
00976 
00977   return (result);
00978 }
00979 
00981 float
00982 pcl::OpenNIGrabber::getFramesPerSecond () const
00983 {
00984   return (static_cast<float> (device_->getDepthOutputMode ().nFPS));
00985 }
00986 
00987 #endif


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:16:01