openni_pcd_recorder.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) 2012, Sudarshan Srinivasan <sudarshan85@gmail.com>
00006  *  Copyright (c) 2012-, Open Perception, Inc.
00007  * 
00008  *  All rights reserved.
00009  *
00010  *  Redistribution and use in source and binary forms, with or without
00011  *  modification, are permitted provided that the following conditions
00012  *  are met:
00013  *
00014  *   * Redistributions of source code must retain the above copyright
00015  *     notice, this list of conditions and the following disclaimer.
00016  *   * Redistributions in binary form must reproduce the above
00017  *     copyright notice, this list of conditions and the following
00018  *     disclaimer in the documentation and/or other materials provided
00019  *     with the distribution.
00020  * 
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  */
00035 
00036 #include <pcl/point_cloud.h>
00037 #include <pcl/point_types.h>
00038 #include <pcl/io/openni_grabber.h>
00039 #include <boost/thread/condition.hpp>
00040 #include <boost/circular_buffer.hpp>
00041 #include <csignal>
00042 #include <limits>
00043 #include <pcl/io/pcd_io.h>
00044 #include <pcl/console/print.h>
00045 #include <pcl/console/parse.h>
00046 #include <pcl/common/time.h> //fps calculations
00047 
00048 using namespace std;
00049 using namespace pcl;
00050 using namespace pcl::console;
00051 
00052 bool is_done = false;
00053 boost::mutex io_mutex;
00054 
00055 #if defined(__linux__) || defined (TARGET_OS_MAC)
00056 #include <unistd.h>
00057 // Get the available memory size on Linux/BSD systems
00058 
00059 size_t 
00060 getTotalSystemMemory ()
00061 {
00062   uint64_t pages = sysconf (_SC_AVPHYS_PAGES);
00063   uint64_t page_size = sysconf (_SC_PAGE_SIZE);
00064   print_info ("Total available memory size: %lluMB.\n", (pages * page_size) / 1048576);
00065   if (pages * page_size > uint64_t (std::numeric_limits<size_t>::max ()))
00066   {
00067     return std::numeric_limits<size_t>::max ();
00068   }
00069   else
00070   {
00071     return size_t (pages * page_size);
00072   }
00073 }
00074 
00075 const int BUFFER_SIZE = int (getTotalSystemMemory () / (640 * 480));
00076 #else
00077 
00078 const int BUFFER_SIZE = 200;
00079 #endif
00080 
00082 template <typename PointT>
00083 class PCDBuffer
00084 {
00085   public:
00086     PCDBuffer () {}
00087 
00088     bool 
00089     pushBack (typename PointCloud<PointT>::ConstPtr); // thread-save wrapper for push_back() method of ciruclar_buffer
00090 
00091     typename PointCloud<PointT>::ConstPtr 
00092     getFront (); // thread-save wrapper for front() method of ciruclar_buffer
00093 
00094     inline bool 
00095     isFull ()
00096     {
00097       boost::mutex::scoped_lock buff_lock (bmutex_);
00098       return (buffer_.full ());
00099     }
00100 
00101     inline bool
00102     isEmpty ()
00103     {
00104       boost::mutex::scoped_lock buff_lock (bmutex_);
00105       return (buffer_.empty ());
00106     }
00107 
00108     inline int 
00109     getSize ()
00110     {
00111       boost::mutex::scoped_lock buff_lock (bmutex_);
00112       return (int (buffer_.size ()));
00113     }
00114 
00115     inline int 
00116     getCapacity ()
00117     {
00118       return (int (buffer_.capacity ()));
00119     }
00120 
00121     inline void 
00122     setCapacity (int buff_size)
00123     {
00124       boost::mutex::scoped_lock buff_lock (bmutex_);
00125       buffer_.set_capacity (buff_size);
00126     }
00127 
00128   private:
00129     PCDBuffer (const PCDBuffer&); // Disabled copy constructor
00130     PCDBuffer& operator =(const PCDBuffer&); // Disabled assignment operator
00131 
00132     boost::mutex bmutex_;
00133     boost::condition_variable buff_empty_;
00134     boost::circular_buffer<typename PointCloud<PointT>::ConstPtr> buffer_;
00135 };
00136 
00138 template <typename PointT> bool 
00139 PCDBuffer<PointT>::pushBack (typename PointCloud<PointT>::ConstPtr cloud)
00140 {
00141   bool retVal = false;
00142   {
00143     boost::mutex::scoped_lock buff_lock (bmutex_);
00144     if (!buffer_.full ())
00145       retVal = true;
00146     buffer_.push_back (cloud);
00147   }
00148   buff_empty_.notify_one ();
00149   return (retVal);
00150 }
00151 
00153 template <typename PointT> typename PointCloud<PointT>::ConstPtr 
00154 PCDBuffer<PointT>::getFront ()
00155 {
00156   typename PointCloud<PointT>::ConstPtr cloud;
00157   {
00158     boost::mutex::scoped_lock buff_lock (bmutex_);
00159     while (buffer_.empty ())
00160     {
00161       if (is_done)
00162         break;
00163       {
00164         boost::mutex::scoped_lock io_lock (io_mutex);
00165         //cerr << "No data in buffer_ yet or buffer is empty." << endl;
00166       }
00167       buff_empty_.wait (buff_lock);
00168     }
00169     cloud = buffer_.front ();
00170     buffer_.pop_front ();
00171   }
00172   return (cloud);
00173 }
00174 
00175 #define FPS_CALC(_WHAT_, buff) \
00176 do \
00177 { \
00178     static unsigned count = 0;\
00179     static double last = getTime ();\
00180     double now = getTime (); \
00181     ++count; \
00182     if (now - last >= 1.0) \
00183     { \
00184       cerr << "Average framerate("<< _WHAT_ << "): " << double(count)/double(now - last) << " Hz. Queue size: " << buff.getSize () << "\n"; \
00185       count = 0; \
00186       last = now; \
00187     } \
00188 }while(false)
00189 
00191 // Producer thread class
00192 template <typename PointT>
00193 class Producer
00194 {
00195   private:
00197     void 
00198     grabberCallBack (const typename PointCloud<PointT>::ConstPtr& cloud)
00199     {
00200       if (!buf_.pushBack (cloud))
00201       {
00202         {
00203           boost::mutex::scoped_lock io_lock (io_mutex);
00204           print_warn ("Warning! Buffer was full, overwriting data!\n");
00205         }
00206       }
00207       FPS_CALC ("cloud callback.", buf_);
00208     }
00209 
00211     void 
00212     grabAndSend ()
00213     {
00214       OpenNIGrabber* grabber = new OpenNIGrabber ();
00215       grabber->getDevice ()->setDepthOutputFormat (depth_mode_);
00216 
00217       Grabber* interface = grabber;
00218       boost::function<void (const typename PointCloud<PointT>::ConstPtr&)> f = boost::bind (&Producer::grabberCallBack, this, _1);
00219       interface->registerCallback (f);
00220       interface->start ();
00221 
00222       while (true)
00223       {
00224         if (is_done)
00225           break;
00226         boost::this_thread::sleep (boost::posix_time::seconds (1));
00227       }
00228       interface->stop ();
00229     }
00230 
00231   public:
00232     Producer (PCDBuffer<PointT> &buf, openni_wrapper::OpenNIDevice::DepthMode depth_mode)
00233       : buf_ (buf),
00234         depth_mode_ (depth_mode)
00235     {
00236       thread_.reset (new boost::thread (boost::bind (&Producer::grabAndSend, this)));
00237     }
00238 
00240     void
00241     stop ()
00242     {
00243       thread_->join ();
00244       boost::mutex::scoped_lock io_lock (io_mutex);
00245       print_highlight ("Producer done.\n");
00246     }
00247 
00248   private:
00249     PCDBuffer<PointT> &buf_;
00250     openni_wrapper::OpenNIDevice::DepthMode depth_mode_;
00251     boost::shared_ptr<boost::thread> thread_;
00252 };
00253 
00255 // Consumer thread class
00256 template <typename PointT>
00257 class Consumer
00258 {
00259   private:
00261     void 
00262     writeToDisk (const typename PointCloud<PointT>::ConstPtr& cloud)
00263     {
00264       stringstream ss;
00265       std::string time = boost::posix_time::to_iso_string (boost::posix_time::microsec_clock::local_time ());
00266       ss << "frame-" << time << ".pcd";
00267       writer_.writeBinaryCompressed (ss.str (), *cloud);
00268       FPS_CALC ("cloud write.", buf_);
00269     }
00270 
00272     // Consumer thread function
00273     void 
00274     receiveAndProcess ()
00275     {
00276       while (true)
00277       {
00278         if (is_done)
00279           break;
00280         writeToDisk (buf_.getFront ());
00281       }
00282 
00283       {
00284         boost::mutex::scoped_lock io_lock (io_mutex);
00285         print_info ("Writing remaing %ld clouds in the buffer to disk...\n", buf_.getSize ());
00286       }
00287       while (!buf_.isEmpty ())
00288         writeToDisk (buf_.getFront ());
00289     }
00290 
00291   public:
00292     Consumer (PCDBuffer<PointT> &buf)
00293       : buf_ (buf)
00294     {
00295       thread_.reset (new boost::thread (boost::bind (&Consumer::receiveAndProcess, this)));
00296     }
00297 
00299     void
00300     stop ()
00301     {
00302       thread_->join ();
00303       boost::mutex::scoped_lock io_lock (io_mutex);
00304       print_highlight ("Consumer done.\n");
00305     }
00306 
00307   private:
00308     PCDBuffer<PointT> &buf_;
00309     boost::shared_ptr<boost::thread> thread_;
00310     PCDWriter writer_;
00311 };
00312 
00314 void 
00315 ctrlC (int)
00316 {
00317   boost::mutex::scoped_lock io_lock (io_mutex);
00318   print_info ("\nCtrl-C detected, exit condition set to true.\n");
00319   is_done = true;
00320 }
00321 
00323 int 
00324 main (int argc, char** argv)
00325 {
00326   print_highlight ("PCL OpenNI Recorder for saving buffered PCD (binary compressed to disk). See %s -h for options.\n", argv[0]);
00327 
00328   int buff_size = BUFFER_SIZE;
00329   
00330   if (find_switch (argc, argv, "-h") || find_switch (argc, argv, "--help"))
00331   {
00332     print_info ("Options are: \n"
00333               "             -xyz    = save only XYZ data, even if the device is RGB capable\n"
00334               "             -shift  = use OpenNI shift values rather than 12-bit depth\n"
00335               "             -buf X  = use a buffer size of X frames (default: "); 
00336     print_value ("%d", buff_size); print_info (")\n");
00337     return (0);
00338   }
00339 
00340 
00341   bool just_xyz = find_switch (argc, argv, "-xyz");
00342   openni_wrapper::OpenNIDevice::DepthMode depth_mode = openni_wrapper::OpenNIDevice::OpenNI_12_bit_depth;
00343   if (find_switch (argc, argv, "-shift"))
00344     depth_mode = openni_wrapper::OpenNIDevice::OpenNI_shift_values;
00345 
00346   if (parse_argument (argc, argv, "-buf", buff_size) != -1)
00347     print_highlight ("Setting buffer size to %d frames.\n", buff_size);
00348   else
00349     print_highlight ("Using default buffer size of %d frames.\n", buff_size);
00350 
00351   print_highlight ("Starting the producer and consumer threads... Press Cltr+C to end\n");
00352  
00353   OpenNIGrabber grabber ("");
00354   if (grabber.providesCallback<OpenNIGrabber::sig_cb_openni_point_cloud_rgba> () && 
00355       !just_xyz)
00356   {
00357     print_highlight ("PointXYZRGBA enabled.\n");
00358     PCDBuffer<PointXYZRGBA> buf;
00359     buf.setCapacity (buff_size);
00360     Producer<PointXYZRGBA> producer (buf, depth_mode);
00361     boost::this_thread::sleep (boost::posix_time::seconds (2));
00362     Consumer<PointXYZRGBA> consumer (buf);
00363 
00364     signal (SIGINT, ctrlC);
00365     producer.stop ();
00366     consumer.stop ();
00367   }
00368   else
00369   {
00370     print_highlight ("PointXYZ enabled.\n");
00371     PCDBuffer<PointXYZ> buf;
00372     buf.setCapacity (buff_size);
00373     Producer<PointXYZ> producer (buf, depth_mode);
00374     boost::this_thread::sleep (boost::posix_time::seconds (2));
00375     Consumer<PointXYZ> consumer (buf);
00376 
00377     signal (SIGINT, ctrlC);
00378     producer.stop ();
00379     consumer.stop ();
00380   }
00381   return (0);
00382 }
00383 


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:26:52