Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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>
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
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);
00090
00091 typename PointCloud<PointT>::ConstPtr
00092 getFront ();
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&);
00130 PCDBuffer& operator =(const PCDBuffer&);
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
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
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
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
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