openni_device.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) 2009-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 #include <pcl/pcl_config.h>
00038 #ifdef HAVE_OPENNI
00039 
00040 #include <pcl/io/openni_camera/openni_driver.h>
00041 #include <pcl/io/openni_camera/openni_device.h>
00042 #include <pcl/io/openni_camera/openni_depth_image.h>
00043 #include <pcl/io/openni_camera/openni_ir_image.h>
00044 #include <iostream>
00045 #include <limits>
00046 #include <sstream>
00047 #include <map>
00048 #include <vector>
00049 #include "XnVersion.h"
00050 
00051 using namespace std;
00052 using namespace boost;
00053 
00055 openni_wrapper::OpenNIDevice::OpenNIDevice (
00056     xn::Context& context, 
00057     const xn::NodeInfo& device_node, 
00058     const xn::NodeInfo& image_node, 
00059     const xn::NodeInfo& depth_node, 
00060     const xn::NodeInfo& ir_node) 
00061   : image_callback_ (),
00062     depth_callback_ (),
00063     ir_callback_ (),
00064     available_image_modes_ (),
00065     available_depth_modes_ (),
00066     context_ (context),
00067     device_node_info_ (device_node),
00068     depth_generator_ (),
00069     image_generator_ (),
00070     ir_generator_ (),
00071     depth_callback_handle_ (),
00072     image_callback_handle_ (),
00073     ir_callback_handle_ (),
00074     depth_focal_length_SXGA_ (),
00075     baseline_ (),
00076     // This magic value is taken from a calibration routine.
00077     rgb_focal_length_SXGA_ (1050),
00078     shadow_value_ (),
00079     no_sample_value_ (),
00080     image_callback_handle_counter_ (),
00081     depth_callback_handle_counter_ (),
00082     ir_callback_handle_counter_ (),
00083     quit_ (),
00084     image_mutex_ (), depth_mutex_ (), ir_mutex_ (),
00085     image_condition_ (), depth_condition_ (), ir_condition_ (), 
00086     image_thread_ (), depth_thread_ (), ir_thread_ ()
00087 {
00088 // workaround for MAC from Alex Ichim
00089 #ifdef __APPLE__
00090   XnStatus rc;
00091 
00092   xn::EnumerationErrors errors;
00093   rc = context_.InitFromXmlFile ("/etc/openni/SamplesConfig.xml", &errors);
00094   if (rc == XN_STATUS_NO_NODE_PRESENT)
00095   {
00096     XnChar strError[1024];
00097     errors.ToString(strError, 1024);
00098     printf ("%s\n", strError);
00099   }
00100   else if (rc != XN_STATUS_OK)
00101   {
00102     printf ("Open failed: %s\n", xnGetStatusString(rc));
00103   }
00104 
00105   XnStatus status = context_.FindExistingNode(XN_NODE_TYPE_DEPTH, depth_generator_);
00106   if (status != XN_STATUS_OK)
00107     cerr << "node depth problems" << endl;
00108   status = context_.FindExistingNode(XN_NODE_TYPE_IMAGE, image_generator_);
00109   if (status != XN_STATUS_OK)
00110     cerr << "node image problems" << endl;
00111   status = context_.FindExistingNode(XN_NODE_TYPE_IR, ir_generator_);
00112     if (status != XN_STATUS_OK)
00113       cerr << "node ir problems" << endl;
00114 
00115 #else
00116 
00117 #if (XN_MINOR_VERSION >= 3)
00118 // create the production nodes
00119   XnStatus status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(depth_node), depth_generator_);
00120   if (status != XN_STATUS_OK)
00121     THROW_OPENNI_EXCEPTION ("creating depth generator failed. Reason: %s", xnGetStatusString (status));
00122 
00123   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(image_node), image_generator_);
00124   if (status != XN_STATUS_OK)
00125     THROW_OPENNI_EXCEPTION ("creating image generator failed. Reason: %s", xnGetStatusString (status));
00126 
00127   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(ir_node), ir_generator_);
00128   if (status != XN_STATUS_OK)
00129     THROW_OPENNI_EXCEPTION ("creating IR generator failed. Reason: %s", xnGetStatusString (status));
00130 #else
00131   XnStatus status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(depth_node));
00132   if (status != XN_STATUS_OK)
00133     THROW_OPENNI_EXCEPTION ("creating depth generator failed. Reason: %s", xnGetStatusString (status));
00134 
00135   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(image_node));
00136   if (status != XN_STATUS_OK)
00137     THROW_OPENNI_EXCEPTION ("creating image generator failed. Reason: %s", xnGetStatusString (status));
00138 
00139   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(ir_node));
00140   if (status != XN_STATUS_OK)
00141     THROW_OPENNI_EXCEPTION ("creating IR generator failed. Reason: %s", xnGetStatusString (status));
00142 
00143   // get production node instances
00144   status = depth_node.GetInstance (depth_generator_);
00145   if (status != XN_STATUS_OK)
00146     THROW_OPENNI_EXCEPTION ("creating depth generator instance failed. Reason: %s", xnGetStatusString (status));
00147 
00148   status = image_node.GetInstance (image_generator_);
00149   if (status != XN_STATUS_OK)
00150     THROW_OPENNI_EXCEPTION ("creating image generator instance failed. Reason: %s", xnGetStatusString (status));
00151 
00152   status = ir_node.GetInstance (ir_generator_);
00153   if (status != XN_STATUS_OK)
00154     THROW_OPENNI_EXCEPTION ("creating IR generator instance failed. Reason: %s", xnGetStatusString (status));
00155 #endif // (XN_MINOR_VERSION >= 3)
00156   ir_generator_.RegisterToNewDataAvailable (static_cast<xn::StateChangedHandler> (NewIRDataAvailable), this, ir_callback_handle_);
00157 #endif // __APPLE__
00158 
00159   depth_generator_.RegisterToNewDataAvailable (static_cast<xn::StateChangedHandler> (NewDepthDataAvailable), this, depth_callback_handle_);
00160   image_generator_.RegisterToNewDataAvailable (static_cast<xn::StateChangedHandler> (NewImageDataAvailable), this, image_callback_handle_);
00161 
00162   Init ();
00163 }
00164 
00166 openni_wrapper::OpenNIDevice::OpenNIDevice (xn::Context& context, const xn::NodeInfo& device_node, const xn::NodeInfo& depth_node, const xn::NodeInfo& ir_node)
00167   : image_callback_ (),
00168     depth_callback_ (),
00169     ir_callback_ (),
00170     available_image_modes_ (),
00171     available_depth_modes_ (),
00172     context_ (context),
00173     device_node_info_ (device_node),
00174     depth_generator_ (),
00175     image_generator_ (),
00176     ir_generator_ (),
00177     depth_callback_handle_ (),
00178     image_callback_handle_ (),
00179     ir_callback_handle_ (),
00180     depth_focal_length_SXGA_ (),
00181     baseline_ (),
00182     // This magic value is taken from a calibration routine.
00183     rgb_focal_length_SXGA_ (1050),
00184     shadow_value_ (),
00185     no_sample_value_ (),
00186     image_callback_handle_counter_ (),
00187     depth_callback_handle_counter_ (),
00188     ir_callback_handle_counter_ (),
00189     quit_ (),
00190     image_mutex_ (), depth_mutex_ (), ir_mutex_ (),
00191     image_condition_ (), depth_condition_ (), ir_condition_ (), 
00192     image_thread_ (), depth_thread_ (), ir_thread_ ()
00193 {
00194 // workaround for MAC from Alex Ichim
00195 #ifdef __APPLE__
00196   cerr << "Creating OpenNIDevice" << endl;
00197   XnStatus rc;
00198 
00199     xn::EnumerationErrors errors;
00200     rc = context_.InitFromXmlFile("/etc/primesense/SamplesConfig.xml", &errors);
00201     if (rc == XN_STATUS_NO_NODE_PRESENT)
00202     {
00203             XnChar strError[1024];
00204             errors.ToString(strError, 1024);
00205             printf("%s\n", strError);
00206     }
00207     else if (rc != XN_STATUS_OK)
00208     {
00209             printf("Open failed: %s\n", xnGetStatusString(rc));
00210     }
00211 
00212   XnStatus status = context_.FindExistingNode(XN_NODE_TYPE_DEPTH, depth_generator_);
00213   if (status != XN_STATUS_OK)
00214     cerr << "node depth problems" << endl;
00215   status = context_.FindExistingNode(XN_NODE_TYPE_IR, ir_generator_);
00216     if (status != XN_STATUS_OK)
00217       cerr << "node ir problems" << endl;
00218 
00219 #else
00220   XnStatus status;
00221 #if (XN_MINOR_VERSION >=3)
00222   // create the production nodes
00223   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(depth_node), depth_generator_);
00224   if (status != XN_STATUS_OK)
00225     THROW_OPENNI_EXCEPTION ("creating depth generator failed. Reason: %s", xnGetStatusString (status));
00226 
00227   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(ir_node), ir_generator_);
00228   if (status != XN_STATUS_OK)
00229     THROW_OPENNI_EXCEPTION ("creating IR generator failed. Reason: %s", xnGetStatusString (status));
00230 #else
00231   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(depth_node));
00232   if (status != XN_STATUS_OK)
00233     THROW_OPENNI_EXCEPTION ("creating depth generator failed. Reason: %s", xnGetStatusString (status));
00234 
00235   status = context_.CreateProductionTree (const_cast<xn::NodeInfo&>(ir_node));
00236   if (status != XN_STATUS_OK)
00237     THROW_OPENNI_EXCEPTION ("creating IR generator failed. Reason: %s", xnGetStatusString (status));
00238   // get production node instances
00239   status = depth_node.GetInstance (depth_generator_);
00240   if (status != XN_STATUS_OK)
00241     THROW_OPENNI_EXCEPTION ("creating depth generator instance failed. Reason: %s", xnGetStatusString (status));
00242 
00243   status = ir_node.GetInstance (ir_generator_);
00244   if (status != XN_STATUS_OK)
00245     THROW_OPENNI_EXCEPTION ("creating IR generator instance failed. Reason: %s", xnGetStatusString (status));
00246 #endif // (XN_MINOR_VERSION >= 3)
00247   ir_generator_.RegisterToNewDataAvailable (static_cast<xn::StateChangedHandler> (NewIRDataAvailable), this, ir_callback_handle_);
00248 #endif // __APPLE__
00249 
00250   depth_generator_.RegisterToNewDataAvailable (static_cast <xn::StateChangedHandler> (NewDepthDataAvailable), this, depth_callback_handle_);
00251   // set up rest
00252   Init ();
00253 }
00254 
00256 // For ONI Player devices
00257 openni_wrapper::OpenNIDevice::OpenNIDevice (xn::Context& context)
00258   : image_callback_ (),
00259     depth_callback_ (),
00260     ir_callback_ (),
00261     available_image_modes_ (),
00262     available_depth_modes_ (),
00263     context_ (context),
00264     device_node_info_ (0),
00265     depth_generator_ (),
00266     image_generator_ (),
00267     ir_generator_ (),
00268     depth_callback_handle_ (),
00269     image_callback_handle_ (),
00270     ir_callback_handle_ (),
00271     depth_focal_length_SXGA_ (),
00272     baseline_ (),
00273     // This magic value is taken from a calibration routine.
00274     rgb_focal_length_SXGA_ (1050),
00275     shadow_value_ (),
00276     no_sample_value_ (),
00277     image_callback_handle_counter_ (),
00278     depth_callback_handle_counter_ (),
00279     ir_callback_handle_counter_ (),
00280     quit_ (),
00281     image_mutex_ (), depth_mutex_ (), ir_mutex_ (),
00282     image_condition_ (), depth_condition_ (), ir_condition_ (), 
00283     image_thread_ (), depth_thread_ (), ir_thread_ ()
00284 {
00285 }
00286 
00288 openni_wrapper::OpenNIDevice::~OpenNIDevice () throw ()
00289 {
00290   // stop streams
00291   if (image_generator_.IsValid() && image_generator_.IsGenerating ())
00292     image_generator_.StopGenerating ();
00293 
00294   if (depth_generator_.IsValid () && depth_generator_.IsGenerating ())
00295     depth_generator_.StopGenerating ();
00296 
00297   if (ir_generator_.IsValid () && ir_generator_.IsGenerating ())
00298     ir_generator_.StopGenerating ();
00299 
00300   // lock before changing running flag
00301   image_mutex_.lock ();
00302   depth_mutex_.lock ();
00303   ir_mutex_.lock ();
00304   quit_ = true;
00305 
00306   depth_condition_.notify_all ();
00307   image_condition_.notify_all ();
00308   ir_condition_.notify_all ();
00309   ir_mutex_.unlock ();
00310   depth_mutex_.unlock ();
00311   image_mutex_.unlock ();
00312 
00313   xn::Device deviceNode;
00314   device_node_info_.GetInstance(deviceNode);
00315   if (deviceNode.IsValid())
00316     deviceNode.Release ();
00317   
00318   if (hasImageStream ())
00319   {
00320     image_thread_.join ();
00321     image_generator_.Release ();
00322   }
00323   
00324   if (hasDepthStream ())
00325   {
00326     depth_thread_.join ();
00327     depth_generator_.Release ();
00328   }
00329   
00330   if (hasIRStream ())
00331   {
00332     ir_thread_.join ();
00333     ir_generator_.Release ();
00334   }
00335 }
00336 
00338 void 
00339 openni_wrapper::OpenNIDevice::Init ()
00340 {
00341   quit_ = false;
00342   XnDouble pixel_size;
00343 
00344   // set Depth resolution here only once... since no other mode for kinect is available -> deactivating setDepthResolution method!
00345   if (hasDepthStream ())
00346   {
00347     unique_lock<mutex> depth_lock (depth_mutex_);
00348     XnStatus status = depth_generator_.GetRealProperty ("ZPPS", pixel_size);
00349     if (status != XN_STATUS_OK)
00350       THROW_OPENNI_EXCEPTION ("reading the pixel size of IR camera failed. Reason: %s", xnGetStatusString (status));
00351 
00352     XnUInt64 depth_focal_length_SXGA;
00353     status = depth_generator_.GetIntProperty ("ZPD", depth_focal_length_SXGA);
00354     if (status != XN_STATUS_OK)
00355       THROW_OPENNI_EXCEPTION ("reading the focal length of IR camera failed. Reason: %s", xnGetStatusString (status));
00356 
00357     XnDouble baseline;
00358     status = depth_generator_.GetRealProperty ("LDDIS", baseline);
00359     if (status != XN_STATUS_OK)
00360       THROW_OPENNI_EXCEPTION ("reading the baseline failed. Reason: %s", xnGetStatusString (status));
00361 
00362     status = depth_generator_.GetIntProperty ("ShadowValue", shadow_value_);
00363     if (status != XN_STATUS_OK)
00364       THROW_OPENNI_EXCEPTION ("reading the value for pixels in shadow regions failed. Reason: %s", xnGetStatusString (status));
00365 
00366     status = depth_generator_.GetIntProperty ("NoSampleValue", no_sample_value_);
00367     if (status != XN_STATUS_OK)
00368       THROW_OPENNI_EXCEPTION ("reading the value for pixels with no depth estimation failed. Reason: %s", xnGetStatusString (status));
00369 
00370     // baseline from cm -> meters
00371     baseline_ = static_cast<float> (baseline * 0.01);
00372 
00373     //focal length from mm -> pixels (valid for 1280x1024)
00374     depth_focal_length_SXGA_ = static_cast<float> (static_cast<XnDouble> (depth_focal_length_SXGA) / pixel_size);
00375 
00376     depth_thread_ = boost::thread (&OpenNIDevice::DepthDataThreadFunction, this);
00377   }
00378 
00379   if (hasImageStream ())
00380   {
00381     lock_guard<mutex> image_lock (image_mutex_);
00382     image_thread_ = boost::thread (&OpenNIDevice::ImageDataThreadFunction, this);
00383   }
00384 
00385   if (hasIRStream ())
00386   {
00387     lock_guard<mutex> ir_lock (ir_mutex_);
00388     ir_thread_ = boost::thread (&OpenNIDevice::IRDataThreadFunction, this);
00389   }
00390 }
00391 
00393 void 
00394 openni_wrapper::OpenNIDevice::startImageStream ()
00395 {
00396   if (hasImageStream ())
00397   {
00398     lock_guard<mutex> image_lock (image_mutex_);
00399     if (!image_generator_.IsGenerating ())
00400     {
00401       XnStatus status = image_generator_.StartGenerating ();
00402       if (status != XN_STATUS_OK)
00403         THROW_OPENNI_EXCEPTION ("starting image stream failed. Reason: %s", xnGetStatusString (status));
00404     }
00405   }
00406   else
00407     THROW_OPENNI_EXCEPTION ("Device does not provide an image stream");
00408 }
00409 
00411 void 
00412 openni_wrapper::OpenNIDevice::stopImageStream ()
00413 {
00414   if (hasImageStream ())
00415   {
00416     lock_guard<mutex> image_lock (image_mutex_);
00417     if (image_generator_.IsGenerating ())
00418     {
00419       XnStatus status = image_generator_.StopGenerating ();
00420       if (status != XN_STATUS_OK)
00421         THROW_OPENNI_EXCEPTION ("stopping image stream failed. Reason: %s", xnGetStatusString (status));
00422     }
00423   }
00424   else
00425     THROW_OPENNI_EXCEPTION ("Device does not provide an image stream");
00426 }
00427 
00429 void 
00430 openni_wrapper::OpenNIDevice::startDepthStream ()
00431 {
00432   if (hasDepthStream ())
00433   {
00434     lock_guard<mutex> depth_lock (depth_mutex_);
00435     if (!depth_generator_.IsGenerating ())
00436     {
00437       XnStatus status = depth_generator_.StartGenerating ();
00438 
00439       if (status != XN_STATUS_OK)
00440         THROW_OPENNI_EXCEPTION ("starting depth stream failed. Reason: %s", xnGetStatusString (status));
00441     }
00442   }
00443   else
00444     THROW_OPENNI_EXCEPTION ("Device does not provide a depth stream");
00445 }
00446 
00448 void 
00449 openni_wrapper::OpenNIDevice::stopDepthStream ()
00450 {
00451   if (hasDepthStream ())
00452   {
00453     lock_guard<mutex> depth_lock (depth_mutex_);
00454     if (depth_generator_.IsGenerating ())
00455     {
00456       XnStatus status = depth_generator_.StopGenerating ();
00457 
00458       if (status != XN_STATUS_OK)
00459         THROW_OPENNI_EXCEPTION ("stopping depth stream failed. Reason: %s", xnGetStatusString (status));
00460     }
00461   }
00462   else
00463     THROW_OPENNI_EXCEPTION ("Device does not provide a depth stream");
00464 }
00465 
00467 void 
00468 openni_wrapper::OpenNIDevice::startIRStream ()
00469 {
00470   if (hasIRStream ())
00471   {
00472     lock_guard<mutex> ir_lock (ir_mutex_);
00473     if (!ir_generator_.IsGenerating ())
00474     {
00475       XnStatus status = ir_generator_.StartGenerating ();
00476 
00477       if (status != XN_STATUS_OK)
00478         THROW_OPENNI_EXCEPTION ("starting IR stream failed. Reason: %s", xnGetStatusString (status));
00479     }
00480   }
00481 #ifndef __APPLE__
00482   else
00483     THROW_OPENNI_EXCEPTION ("Device does not provide an IR stream");
00484 #endif
00485 }
00486 
00488 void 
00489 openni_wrapper::OpenNIDevice::stopIRStream ()
00490 {
00491   if (hasIRStream ())
00492   {
00493     lock_guard<mutex> ir_lock (ir_mutex_);
00494     if (ir_generator_.IsGenerating ())
00495     {
00496       XnStatus status = ir_generator_.StopGenerating ();
00497 
00498       if (status != XN_STATUS_OK)
00499         THROW_OPENNI_EXCEPTION ("stopping IR stream failed. Reason: %s", xnGetStatusString (status));
00500     }
00501   }
00502   else
00503     THROW_OPENNI_EXCEPTION ("Device does not provide an IR stream");
00504 }
00505 
00507 bool 
00508 openni_wrapper::OpenNIDevice::isImageStreamRunning () const throw ()
00509 {
00510   lock_guard<mutex> image_lock (image_mutex_);
00511   return (image_generator_.IsValid () && image_generator_.IsGenerating ());
00512 }
00513 
00515 bool 
00516 openni_wrapper::OpenNIDevice::isDepthStreamRunning () const throw ()
00517 {
00518   lock_guard<mutex> depth_lock (depth_mutex_);
00519   return (depth_generator_.IsValid () && depth_generator_.IsGenerating ());
00520 }
00521 
00523 bool 
00524 openni_wrapper::OpenNIDevice::isIRStreamRunning () const throw ()
00525 {
00526   lock_guard<mutex> ir_lock (ir_mutex_);
00527   return (ir_generator_.IsValid () && ir_generator_.IsGenerating ());
00528 }
00529 
00531 bool 
00532 openni_wrapper::OpenNIDevice::hasImageStream () const throw ()
00533 {
00534   lock_guard<mutex> lock (image_mutex_);
00535   return (image_generator_.IsValid () != 0);
00536   //return (available_image_modes_.size() != 0);
00537 }
00538 
00540 bool 
00541 openni_wrapper::OpenNIDevice::hasDepthStream () const throw ()
00542 {
00543   lock_guard<mutex> lock (depth_mutex_);
00544   return (depth_generator_.IsValid () != 0);
00545   //return (available_depth_modes_.size() != 0);
00546 }
00547 
00549 bool 
00550 openni_wrapper::OpenNIDevice::hasIRStream () const throw ()
00551 {
00552   lock_guard<mutex> ir_lock (ir_mutex_);
00553   return (ir_generator_.IsValid () != 0);
00554 }
00555 
00557 void 
00558 openni_wrapper::OpenNIDevice::setDepthRegistration (bool on_off)
00559 {
00560   if (hasDepthStream () && hasImageStream())
00561   {
00562     lock_guard<mutex> image_lock (image_mutex_);
00563     lock_guard<mutex> depth_lock (depth_mutex_);
00564     if (on_off && !depth_generator_.GetAlternativeViewPointCap ().IsViewPointAs (image_generator_))
00565     {
00566       if (depth_generator_.GetAlternativeViewPointCap ().IsViewPointSupported (image_generator_))
00567       {
00568         XnStatus status = depth_generator_.GetAlternativeViewPointCap ().SetViewPoint (image_generator_);
00569         if (status != XN_STATUS_OK)
00570           THROW_OPENNI_EXCEPTION ("turning registration on failed. Reason: %s", xnGetStatusString (status));
00571       }
00572       else
00573         THROW_OPENNI_EXCEPTION ("turning registration on failed. Reason: unsopported viewpoint");
00574     }
00575     else if (!on_off)
00576     {
00577       XnStatus status = depth_generator_.GetAlternativeViewPointCap ().ResetViewPoint ();
00578 
00579       if (status != XN_STATUS_OK)
00580         THROW_OPENNI_EXCEPTION ("turning registration off failed. Reason: %s", xnGetStatusString (status));
00581     }
00582   }
00583   else
00584     THROW_OPENNI_EXCEPTION ("Device does not provide image + depth stream");
00585 }
00586 
00588 bool 
00589 openni_wrapper::OpenNIDevice::isDepthRegistered () const throw ()
00590 {
00591   if (hasDepthStream () && hasImageStream() )
00592   {
00593     xn::DepthGenerator& depth_generator = const_cast<xn::DepthGenerator&>(depth_generator_);
00594     xn::ImageGenerator& image_generator = const_cast<xn::ImageGenerator&>(image_generator_);
00595 
00596     lock_guard<mutex> image_lock (image_mutex_);
00597     lock_guard<mutex> depth_lock (depth_mutex_);
00598     return (depth_generator.GetAlternativeViewPointCap ().IsViewPointAs (image_generator) != 0);
00599   }
00600   return (false);
00601 }
00602 
00604 bool 
00605 openni_wrapper::OpenNIDevice::isDepthRegistrationSupported () const throw ()
00606 {
00607   lock_guard<mutex> image_lock (image_mutex_);
00608   lock_guard<mutex> depth_lock (depth_mutex_);
00609   xn::ImageGenerator& image_generator = const_cast<xn::ImageGenerator&> (image_generator_);
00610   return (depth_generator_.IsValid() && image_generator_.IsValid() && depth_generator_.GetAlternativeViewPointCap().IsViewPointSupported(image_generator));
00611 }
00612 
00614 bool 
00615 openni_wrapper::OpenNIDevice::isSynchronizationSupported () const throw ()
00616 {
00617   lock_guard<mutex> image_lock (image_mutex_);
00618   lock_guard<mutex> depth_lock (depth_mutex_);
00619   return (depth_generator_.IsValid() && image_generator_.IsValid() && depth_generator_.IsCapabilitySupported (XN_CAPABILITY_FRAME_SYNC));
00620 }
00621 
00623 void 
00624 openni_wrapper::OpenNIDevice::setSynchronization (bool on_off)
00625 {
00626   if (hasDepthStream () && hasImageStream())
00627   {
00628     lock_guard<mutex> image_lock (image_mutex_);
00629     lock_guard<mutex> depth_lock (depth_mutex_);
00630     XnStatus status;
00631 
00632     if (on_off && !depth_generator_.GetFrameSyncCap ().IsFrameSyncedWith (image_generator_))
00633     {
00634       status = depth_generator_.GetFrameSyncCap ().FrameSyncWith (image_generator_);
00635       if (status != XN_STATUS_OK)
00636         THROW_OPENNI_EXCEPTION ("could not turn on frame synchronization. Reason: %s", xnGetStatusString (status));
00637     }
00638     else if (!on_off && depth_generator_.GetFrameSyncCap ().IsFrameSyncedWith (image_generator_))
00639     {
00640       status = depth_generator_.GetFrameSyncCap ().StopFrameSyncWith (image_generator_);
00641       if (status != XN_STATUS_OK)
00642         THROW_OPENNI_EXCEPTION ("could not turn off frame synchronization. Reason: %s", xnGetStatusString (status));
00643     }
00644   }
00645   else
00646     THROW_OPENNI_EXCEPTION ("Device does not provide image + depth stream");
00647 }
00648 
00650 bool 
00651 openni_wrapper::OpenNIDevice::isSynchronized () const throw ()
00652 {
00653   if (hasDepthStream () && hasImageStream())
00654   {
00655     lock_guard<mutex> image_lock (image_mutex_);
00656     lock_guard<mutex> depth_lock (depth_mutex_);
00657     xn::DepthGenerator& depth_generator = const_cast<xn::DepthGenerator&>(depth_generator_);
00658     xn::ImageGenerator& image_generator = const_cast<xn::ImageGenerator&>(image_generator_);
00659     return (depth_generator.GetFrameSyncCap ().CanFrameSyncWith (image_generator) && depth_generator.GetFrameSyncCap ().IsFrameSyncedWith (image_generator));
00660   }
00661   else
00662     return (false);
00663 }
00664 
00666 bool 
00667 openni_wrapper::OpenNIDevice::isDepthCroppingSupported () const throw ()
00668 {
00669   lock_guard<mutex> depth_lock (depth_mutex_);
00670   return (image_generator_.IsValid() && depth_generator_.IsCapabilitySupported (XN_CAPABILITY_CROPPING) );
00671 }
00672 
00674 bool 
00675 openni_wrapper::OpenNIDevice::isDepthCropped () const
00676 {
00677   if (hasDepthStream ())
00678   {
00679     lock_guard<mutex> depth_lock (depth_mutex_);
00680     XnCropping cropping;
00681     xn::DepthGenerator& depth_generator = const_cast<xn::DepthGenerator&>(depth_generator_);
00682     XnStatus status = depth_generator.GetCroppingCap ().GetCropping (cropping);
00683     if (status != XN_STATUS_OK)
00684       THROW_OPENNI_EXCEPTION ("could not read cropping information for depth stream. Reason: %s", xnGetStatusString (status));
00685 
00686     return (cropping.bEnabled != 0);
00687   }
00688   return (false);
00689 }
00690 
00692 void 
00693 openni_wrapper::OpenNIDevice::setDepthCropping (unsigned x, unsigned y, unsigned width, unsigned height)
00694 {
00695   if (hasDepthStream ())
00696   {
00697     lock_guard<mutex> depth_lock (depth_mutex_);
00698     XnCropping cropping;
00699     cropping.nXOffset = static_cast<XnUInt16> (x);
00700     cropping.nYOffset = static_cast<XnUInt16> (y);
00701     cropping.nXSize   = static_cast<XnUInt16> (width);
00702     cropping.nYSize   = static_cast<XnUInt16> (height);
00703     
00704     cropping.bEnabled = (width != 0 && height != 0);
00705     XnStatus status = depth_generator_.GetCroppingCap ().SetCropping (cropping);
00706     if (status != XN_STATUS_OK)
00707       THROW_OPENNI_EXCEPTION ("could not set cropping information for depth stream. Reason: %s", xnGetStatusString (status));
00708   }
00709   else
00710     THROW_OPENNI_EXCEPTION ("Device does not provide depth stream");
00711 }
00712 
00714 void 
00715 openni_wrapper::OpenNIDevice::ImageDataThreadFunction ()
00716 {
00717   while (true)
00718   {
00719     // lock before checking running flag
00720     unique_lock<mutex> image_lock (image_mutex_);
00721     if (quit_)
00722       return;
00723     image_condition_.wait (image_lock);
00724     if (quit_)
00725       return;
00726 
00727     image_generator_.WaitAndUpdateData ();
00728     //xn::ImageMetaData* image_data = boost::shared_ptr<xn::ImageMetaData>;
00729     boost::shared_ptr<xn::ImageMetaData> image_data (new xn::ImageMetaData);
00730     image_generator_.GetMetaData (*image_data);
00731     image_lock.unlock ();
00732 
00733     boost::shared_ptr<Image> image = getCurrentImage (image_data);
00734     for (map< OpenNIDevice::CallbackHandle, ActualImageCallbackFunction >::iterator callbackIt = image_callback_.begin (); callbackIt != image_callback_.end (); ++callbackIt)
00735     {
00736       callbackIt->second.operator()(image);
00737     }
00738   }
00739 }
00740 
00742 void 
00743 openni_wrapper::OpenNIDevice::DepthDataThreadFunction ()
00744 {
00745   while (true)
00746   {
00747     // lock before checking running flag
00748     unique_lock<mutex> depth_lock (depth_mutex_);
00749     if (quit_)
00750       return;
00751     depth_condition_.wait (depth_lock);
00752     if (quit_)
00753       return;
00754 
00755     depth_generator_.WaitAndUpdateData ();
00756     boost::shared_ptr<xn::DepthMetaData> depth_data (new xn::DepthMetaData);
00757     depth_generator_.GetMetaData (*depth_data);
00758     depth_lock.unlock ();
00759 
00760     boost::shared_ptr<DepthImage> depth_image ( new DepthImage (depth_data, baseline_, getDepthFocalLength (), shadow_value_, no_sample_value_) );
00761 
00762     for (map< OpenNIDevice::CallbackHandle, ActualDepthImageCallbackFunction >::iterator callbackIt = depth_callback_.begin ();
00763          callbackIt != depth_callback_.end (); ++callbackIt)
00764     {
00765       callbackIt->second.operator()(depth_image);
00766     }
00767   }
00768 }
00769 
00771 void 
00772 openni_wrapper::OpenNIDevice::IRDataThreadFunction ()
00773 {
00774   while (true)
00775   {
00776     // lock before checking running flag
00777     unique_lock<mutex> ir_lock (ir_mutex_);
00778     if (quit_)
00779       return;
00780     ir_condition_.wait (ir_lock);
00781     if (quit_)
00782       return;
00783 
00784     ir_generator_.WaitAndUpdateData ();
00785     boost::shared_ptr<xn::IRMetaData> ir_data (new xn::IRMetaData);
00786     ir_generator_.GetMetaData (*ir_data);
00787     ir_lock.unlock ();
00788 
00789     boost::shared_ptr<IRImage> ir_image ( new IRImage (ir_data) );
00790 
00791     for (map< OpenNIDevice::CallbackHandle, ActualIRImageCallbackFunction >::iterator callbackIt = ir_callback_.begin ();
00792          callbackIt != ir_callback_.end (); ++callbackIt)
00793     {
00794       callbackIt->second.operator()(ir_image);
00795     }
00796   }
00797 }
00798 
00800 void __stdcall 
00801 openni_wrapper::OpenNIDevice::NewDepthDataAvailable (xn::ProductionNode&, void* cookie) throw ()
00802 {
00803   OpenNIDevice* device = reinterpret_cast<OpenNIDevice*>(cookie);
00804   device->depth_condition_.notify_all ();
00805 }
00806 
00808 void __stdcall 
00809 openni_wrapper::OpenNIDevice::NewImageDataAvailable (xn::ProductionNode&, void* cookie) throw ()
00810 {
00811   OpenNIDevice* device = reinterpret_cast<OpenNIDevice*>(cookie);
00812   device->image_condition_.notify_all ();
00813 }
00814 
00816 void __stdcall 
00817 openni_wrapper::OpenNIDevice::NewIRDataAvailable (xn::ProductionNode&, void* cookie) throw ()
00818 {
00819   OpenNIDevice* device = reinterpret_cast<OpenNIDevice*>(cookie);
00820   device->ir_condition_.notify_all ();
00821 }
00822 
00824 openni_wrapper::OpenNIDevice::CallbackHandle 
00825 openni_wrapper::OpenNIDevice::registerImageCallback (const ImageCallbackFunction& callback, void* custom_data) throw ()
00826 {
00827   image_callback_[image_callback_handle_counter_] = boost::bind (callback, _1, custom_data);
00828   return (image_callback_handle_counter_++);
00829 }
00830 
00832 bool 
00833 openni_wrapper::OpenNIDevice::unregisterImageCallback (const OpenNIDevice::CallbackHandle& callbackHandle) throw ()
00834 {
00835   return (image_callback_.erase (callbackHandle) != 0);
00836 }
00837 
00839 openni_wrapper::OpenNIDevice::CallbackHandle 
00840 openni_wrapper::OpenNIDevice::registerDepthCallback (const DepthImageCallbackFunction& callback, void* custom_data) throw ()
00841 {
00842   depth_callback_[depth_callback_handle_counter_] = boost::bind (callback, _1, custom_data);
00843   return (depth_callback_handle_counter_++);
00844 }
00845 
00847 bool 
00848 openni_wrapper::OpenNIDevice::unregisterDepthCallback (const OpenNIDevice::CallbackHandle& callbackHandle) throw ()
00849 {
00850   return (depth_callback_.erase (callbackHandle) != 0);
00851 }
00852 
00854 openni_wrapper::OpenNIDevice::CallbackHandle 
00855 openni_wrapper::OpenNIDevice::registerIRCallback (const IRImageCallbackFunction& callback, void* custom_data) throw ()
00856 {
00857   ir_callback_[ir_callback_handle_counter_] = boost::bind (callback, _1, custom_data);
00858   return (ir_callback_handle_counter_++);
00859 }
00860 
00862 bool 
00863 openni_wrapper::OpenNIDevice::unregisterIRCallback (const OpenNIDevice::CallbackHandle& callbackHandle) throw ()
00864 {
00865   return (ir_callback_.erase (callbackHandle) != 0);
00866 }
00867 
00869 const char* 
00870 openni_wrapper::OpenNIDevice::getSerialNumber () const throw ()
00871 {
00872   return (device_node_info_.GetInstanceName ());
00873 }
00874 
00876 const char* 
00877 openni_wrapper::OpenNIDevice::getConnectionString () const throw ()
00878 {
00879   return (device_node_info_.GetCreationInfo ());
00880 }
00881 
00883 unsigned short 
00884 openni_wrapper::OpenNIDevice::getVendorID () const throw ()
00885 {
00886   unsigned short vendor_id;
00887   unsigned short product_id;
00888 
00889 #ifndef _WIN32
00890   unsigned char bus;
00891   unsigned char address;
00892 
00893   sscanf (device_node_info_.GetCreationInfo(), "%hx/%hx@%hhu/%hhu", &vendor_id, &product_id, &bus, &address);
00894 
00895 #else
00896   OpenNIDriver::getDeviceType (device_node_info_.GetCreationInfo(), vendor_id, product_id);
00897 #endif
00898   return (vendor_id);
00899 }
00900 
00902 unsigned short 
00903 openni_wrapper::OpenNIDevice::getProductID () const throw ()
00904 {
00905   unsigned short vendor_id;
00906   unsigned short product_id;
00907 #ifndef _WIN32
00908   unsigned char bus;
00909   unsigned char address;
00910   sscanf (device_node_info_.GetCreationInfo(), "%hx/%hx@%hhu/%hhu", &vendor_id, &product_id, &bus, &address);
00911 
00912 #else
00913   OpenNIDriver::getDeviceType (device_node_info_.GetCreationInfo(), vendor_id, product_id);
00914 #endif
00915   return (product_id);
00916 }
00917 
00919 unsigned char 
00920 openni_wrapper::OpenNIDevice::getBus () const throw ()
00921 {
00922   unsigned char bus = 0;
00923 #ifndef _WIN32
00924   unsigned short vendor_id;
00925   unsigned short product_id;
00926   unsigned char address;
00927   sscanf (device_node_info_.GetCreationInfo(), "%hx/%hx@%hhu/%hhu", &vendor_id, &product_id, &bus, &address);
00928 #endif
00929   return (bus);
00930 }
00931 
00933 unsigned char 
00934 openni_wrapper::OpenNIDevice::getAddress () const throw ()
00935 {
00936   unsigned char address = 0;
00937 #ifndef _WIN32
00938   unsigned short vendor_id;
00939   unsigned short product_id;
00940   unsigned char bus;
00941   sscanf (device_node_info_.GetCreationInfo(), "%hx/%hx@%hhu/%hhu", &vendor_id, &product_id, &bus, &address);
00942 #endif
00943   return (address);
00944 }
00945 
00947 const char* 
00948 openni_wrapper::OpenNIDevice::getVendorName () const throw ()
00949 {
00950   XnProductionNodeDescription& description = const_cast<XnProductionNodeDescription&>(device_node_info_.GetDescription ());
00951   return (description.strVendor);
00952 }
00953 
00955 const char* 
00956 openni_wrapper::OpenNIDevice::getProductName () const throw ()
00957 {
00958   XnProductionNodeDescription& description = const_cast<XnProductionNodeDescription&>(device_node_info_.GetDescription ());
00959   return (description.strName);
00960 }
00961 
00963 bool 
00964 openni_wrapper::OpenNIDevice::findCompatibleImageMode (const XnMapOutputMode& output_mode, XnMapOutputMode& mode) const throw ()
00965 {
00966   if (isImageModeSupported (output_mode))
00967   {
00968     mode = output_mode;
00969     return (true);
00970   }
00971   else
00972   {
00973     bool found = false;
00974     for (vector<XnMapOutputMode>::const_iterator modeIt = available_image_modes_.begin (); modeIt != available_image_modes_.end (); ++modeIt)
00975     {
00976       if (modeIt->nFPS == output_mode.nFPS && isImageResizeSupported (modeIt->nXRes, modeIt->nYRes, output_mode.nXRes, output_mode.nYRes))
00977       {
00978         if (found)
00979         { // check wheter the new mode is better -> smaller than the current one.
00980           if (mode.nXRes * mode.nYRes > modeIt->nXRes * modeIt->nYRes )
00981             mode = *modeIt;
00982         }
00983         else
00984         {
00985           mode = *modeIt;
00986           found = true;
00987         }
00988       }
00989     }
00990     return (found);
00991   }
00992 }
00993 
00995 bool 
00996 openni_wrapper::OpenNIDevice::findCompatibleDepthMode (const XnMapOutputMode& output_mode, XnMapOutputMode& mode) const throw ()
00997 {
00998   if (isDepthModeSupported (output_mode))
00999   {
01000     mode = output_mode;
01001     return (true);
01002   }
01003   else
01004   {
01005     bool found = false;
01006     for (vector<XnMapOutputMode>::const_iterator modeIt = available_depth_modes_.begin (); modeIt != available_depth_modes_.end (); ++modeIt)
01007     {
01008       if (modeIt->nFPS == output_mode.nFPS && isImageResizeSupported (modeIt->nXRes, modeIt->nYRes, output_mode.nXRes, output_mode.nYRes))
01009       {
01010         if (found)
01011         { // check wheter the new mode is better -> smaller than the current one.
01012           if (mode.nXRes * mode.nYRes > modeIt->nXRes * modeIt->nYRes )
01013             mode = *modeIt;
01014         }
01015         else
01016         {
01017           mode = *modeIt;
01018           found = true;
01019         }
01020       }
01021     }
01022     return (found);
01023   }
01024 }
01025 
01027 bool 
01028 openni_wrapper::OpenNIDevice::isImageModeSupported (const XnMapOutputMode& output_mode) const throw ()
01029 {
01030   for (vector<XnMapOutputMode>::const_iterator modeIt = available_image_modes_.begin (); modeIt != available_image_modes_.end (); ++modeIt)
01031   {
01032     if (modeIt->nFPS == output_mode.nFPS && modeIt->nXRes == output_mode.nXRes && modeIt->nYRes == output_mode.nYRes)
01033       return (true);
01034   }
01035   return (false);
01036 }
01037 
01039 bool 
01040 openni_wrapper::OpenNIDevice::isDepthModeSupported (const XnMapOutputMode& output_mode) const throw ()
01041 {
01042   for (vector<XnMapOutputMode>::const_iterator modeIt = available_depth_modes_.begin (); modeIt != available_depth_modes_.end (); ++modeIt)
01043   {
01044     if (modeIt->nFPS == output_mode.nFPS && modeIt->nXRes == output_mode.nXRes && modeIt->nYRes == output_mode.nYRes)
01045       return (true);
01046   }
01047   return (false);
01048 }
01049 
01051 const XnMapOutputMode& 
01052 openni_wrapper::OpenNIDevice::getDefaultImageMode () const throw ()
01053 {
01054   return (available_image_modes_[0]);
01055 }
01056 
01058 const XnMapOutputMode& 
01059 openni_wrapper::OpenNIDevice::getDefaultDepthMode () const throw ()
01060 {
01061   return (available_depth_modes_[0]);
01062 }
01063 
01065 const XnMapOutputMode& 
01066 openni_wrapper::OpenNIDevice::getDefaultIRMode () const throw ()
01067 {
01069   return (available_depth_modes_[0]);
01070 }
01071 
01073 void 
01074 openni_wrapper::OpenNIDevice::setImageOutputMode (const XnMapOutputMode& output_mode)
01075 {
01076   if (hasImageStream ())
01077   {
01078     lock_guard<mutex> image_lock (image_mutex_);
01079     XnStatus status = image_generator_.SetMapOutputMode (output_mode);
01080     if (status != XN_STATUS_OK)
01081       THROW_OPENNI_EXCEPTION ("Could not set image stream output mode to %dx%d@%d. Reason: %s", output_mode.nXRes, output_mode.nYRes, output_mode.nFPS, xnGetStatusString (status));
01082   }
01083   else
01084     THROW_OPENNI_EXCEPTION ("Device does not provide an image stream");
01085 }
01086 
01088 void 
01089 openni_wrapper::OpenNIDevice::setDepthOutputMode (const XnMapOutputMode& output_mode)
01090 {
01091   if (hasDepthStream ())
01092   {
01093     lock_guard<mutex> depth_lock (depth_mutex_);
01094     XnStatus status = depth_generator_.SetMapOutputMode (output_mode);
01095     if (status != XN_STATUS_OK)
01096       THROW_OPENNI_EXCEPTION ("Could not set depth stream output mode to %dx%d@%d. Reason: %s", output_mode.nXRes, output_mode.nYRes, output_mode.nFPS, xnGetStatusString (status));
01097   }
01098   else
01099     THROW_OPENNI_EXCEPTION ("Device does not provide a depth stream");
01100 }
01101 
01103 void 
01104 openni_wrapper::OpenNIDevice::setIROutputMode (const XnMapOutputMode& output_mode)
01105 {
01106   if (hasIRStream ())
01107   {
01108     lock_guard<mutex> ir_lock (ir_mutex_);
01109     XnStatus status = ir_generator_.SetMapOutputMode (output_mode);
01110     if (status != XN_STATUS_OK)
01111       THROW_OPENNI_EXCEPTION ("Could not set IR stream output mode to %dx%d@%d. Reason: %s", output_mode.nXRes, output_mode.nYRes, output_mode.nFPS, xnGetStatusString (status));
01112   }
01113 #ifndef __APPLE__
01114   else
01115     THROW_OPENNI_EXCEPTION ("Device does not provide an IR stream");
01116 #endif
01117 }
01118 
01120 XnMapOutputMode 
01121 openni_wrapper::OpenNIDevice::getImageOutputMode () const
01122 {
01123   if (!hasImageStream ())
01124     THROW_OPENNI_EXCEPTION ("Device does not provide an image stream");
01125 
01126   XnMapOutputMode output_mode;
01127   lock_guard<mutex> image_lock (image_mutex_);
01128   XnStatus status = image_generator_.GetMapOutputMode (output_mode);
01129   if (status != XN_STATUS_OK)
01130     THROW_OPENNI_EXCEPTION ("Could not get image stream output mode. Reason: %s", xnGetStatusString (status));
01131   return (output_mode);
01132 }
01133 
01135 XnMapOutputMode 
01136 openni_wrapper::OpenNIDevice::getDepthOutputMode () const
01137 {
01138   if (!hasDepthStream () )
01139     THROW_OPENNI_EXCEPTION ("Device does not provide a depth stream");
01140 
01141   XnMapOutputMode output_mode;
01142   lock_guard<mutex> depth_lock (depth_mutex_);
01143   XnStatus status = depth_generator_.GetMapOutputMode (output_mode);
01144   if (status != XN_STATUS_OK)
01145     THROW_OPENNI_EXCEPTION ("Could not get depth stream output mode. Reason: %s", xnGetStatusString (status));
01146   return (output_mode);
01147 }
01148 
01150 XnMapOutputMode 
01151 openni_wrapper::OpenNIDevice::getIROutputMode () const
01152 {
01153   if (!hasIRStream ())
01154     THROW_OPENNI_EXCEPTION ("Device does not provide an IR stream");
01155 
01156   XnMapOutputMode output_mode;
01157   lock_guard<mutex> ir_lock (ir_mutex_);
01158   XnStatus status = ir_generator_.GetMapOutputMode (output_mode);
01159   if (status != XN_STATUS_OK)
01160     THROW_OPENNI_EXCEPTION ("Could not get IR stream output mode. Reason: %s", xnGetStatusString (status));
01161   return (output_mode);
01162 }
01163 
01164 #endif //OPENNI


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