in_hand_scanner.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-2012, Willow Garage, Inc.
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  *  * Neither the name of the copyright holder(s) nor the names of its
00021  *    contributors may be used to endorse or promote products derived
00022  *    from this software without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00027  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00028  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00029  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00030  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00031  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00032  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00033  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00034  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00035  * POSSIBILITY OF SUCH DAMAGE.
00036  *
00037  * $Id$
00038  *
00039  */
00040 
00041 #include <pcl/apps/in_hand_scanner/in_hand_scanner.h>
00042 
00043 #include <QApplication>
00044 #include <QtCore>
00045 #include <QKeyEvent>
00046 #include <QPainter>
00047 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
00048 #include <QtConcurrent/QtConcurrent>
00049 #endif
00050 
00051 
00052 #include <pcl/conversions.h>
00053 #include <pcl_conversions/pcl_conversions.h>
00054 #include <pcl/PCLPointCloud2.h>
00055 
00056 #include <pcl/exceptions.h>
00057 #include <pcl/common/time.h>
00058 #include <pcl/common/transforms.h>
00059 #include <pcl/io/openni_grabber.h>
00060 #include <pcl/io/ply_io.h>
00061 #include <pcl/io/vtk_io.h>
00062 #include <pcl/io/obj_io.h>
00063 #include <pcl/geometry/mesh_base.h>
00064 #include <pcl/geometry/get_boundary.h>
00065 #include <pcl/geometry/mesh_conversion.h>
00066 #include <pcl/apps/in_hand_scanner/icp.h>
00067 #include <pcl/apps/in_hand_scanner/input_data_processing.h>
00068 #include <pcl/apps/in_hand_scanner/integration.h>
00069 #include <pcl/apps/in_hand_scanner/mesh_processing.h>
00070 
00071 #include <ros/ros.h>
00072 #include "sensor_msgs/PointCloud2.h"
00073 
00074 #include <iostream>
00075 
00077 
00078 pcl::ihs::InHandScanner::InHandScanner (Base* parent)
00079   : Base                   (parent),
00080     mutex_                 (),
00081     computation_fps_       (),
00082     visualization_fps_     (),
00083     running_mode_          (RM_UNPROCESSED),
00084     iteration_             (0),
00085     grabber_               (),
00086     starting_grabber_      (false),
00087     new_data_connection_   (),
00088     input_data_processing_ (new InputDataProcessing ()),
00089     icp_                   (new ICP ()),
00090     transformation_        (Eigen::Matrix4f::Identity ()),
00091     integration_           (new Integration ()),
00092     mesh_processing_       (new MeshProcessing ()),
00093     mesh_model_            (new Mesh ()),
00094     destructor_called_     (false)
00095 {
00096   // http://doc.qt.digia.com/qt/qmetatype.html#qRegisterMetaType
00097   qRegisterMetaType <pcl::ihs::InHandScanner::RunningMode> ("RunningMode");
00098 
00099   Base::setScalingFactor (0.01);
00100 
00101   // Initialize the pivot
00102   const float x_min = input_data_processing_->getXMin ();
00103   const float x_max = input_data_processing_->getXMax ();
00104   const float y_min = input_data_processing_->getYMin ();
00105   const float y_max = input_data_processing_->getYMax ();
00106   const float z_min = input_data_processing_->getZMin ();
00107   const float z_max = input_data_processing_->getZMax ();
00108 
00109   Base::setPivot (Eigen::Vector3d ((x_min + x_max) / 2., (y_min + y_max) / 2., (z_min + z_max) / 2.));
00110 
00111   cloud_ptr_xyzrgba.reset(new pcl::PointCloud<pcl::PointXYZRGBA>());
00112 }
00113 
00115 
00116 pcl::ihs::InHandScanner::~InHandScanner ()
00117 {
00118   boost::mutex::scoped_lock lock (mutex_);
00119   destructor_called_ = true;
00120 
00121   if (grabber_ && grabber_->isRunning ()) grabber_->stop ();
00122   if (new_data_connection_.connected ())  new_data_connection_.disconnect ();
00123 }
00124 
00126 
00127 void
00128 pcl::ihs::InHandScanner::startGrabber ()
00129 {
00130   QtConcurrent::run (boost::bind (&pcl::ihs::InHandScanner::startGrabberImpl, this));
00131 }
00132 
00134 
00135 void
00136 pcl::ihs::InHandScanner::showUnprocessedData ()
00137 {
00138   boost::mutex::scoped_lock lock (mutex_);
00139   if (destructor_called_) return;
00140 
00141   std::cerr << "Showing the unprocessed input data.\n";
00142   Base::setDrawBox (false);
00143   Base::setColoring (Base::COL_RGB);
00144 
00145   running_mode_ = RM_UNPROCESSED;
00146   emit runningModeChanged (running_mode_);
00147 }
00148 
00150 
00151 void
00152 pcl::ihs::InHandScanner::showProcessedData ()
00153 {
00154   boost::mutex::scoped_lock lock (mutex_);
00155   if (destructor_called_) return;
00156 
00157   std::cerr << "Showing the processed input data.\n";
00158   Base::setDrawBox (true);
00159   Base::setColoring (Base::COL_RGB);
00160 
00161   running_mode_ = RM_PROCESSED;
00162   emit runningModeChanged (running_mode_);
00163 }
00164 
00166 
00167 void
00168 pcl::ihs::InHandScanner::registerContinuously ()
00169 {
00170   boost::mutex::scoped_lock lock (mutex_);
00171   if (destructor_called_) return;
00172 
00173   std::cerr << "Continuous registration.\n";
00174   Base::setDrawBox (true);
00175   Base::setColoring (Base::COL_VISCONF);
00176 
00177   running_mode_ = RM_REGISTRATION_CONT;
00178   emit runningModeChanged (running_mode_);
00179 }
00180 
00182 
00183 void
00184 pcl::ihs::InHandScanner::registerOnce ()
00185 {
00186   boost::mutex::scoped_lock lock (mutex_);
00187   if (destructor_called_) return;
00188 
00189   std::cerr << "Single registration.\n";
00190   Base::setDrawBox (true);
00191 
00192   running_mode_ = RM_REGISTRATION_SINGLE;
00193   emit runningModeChanged (running_mode_);
00194 }
00195 
00197 
00198 void
00199 pcl::ihs::InHandScanner::showModel ()
00200 {
00201   boost::mutex::scoped_lock lock (mutex_);
00202   if (destructor_called_) return;
00203 
00204   std::cerr << "Show the model\n";
00205   Base::setDrawBox (false);
00206 
00207   running_mode_ = RM_SHOW_MODEL;
00208   emit runningModeChanged (running_mode_);
00209 }
00210 
00212 
00213 void
00214 pcl::ihs::InHandScanner::removeUnfitVertices ()
00215 {
00216   boost::mutex::scoped_lock lock (mutex_);
00217   if (destructor_called_) return;
00218 
00219   std::cerr << "Removing unfit vertices ...\n";
00220 
00221   integration_->removeUnfitVertices (mesh_model_);
00222   if (mesh_model_->emptyVertices ())
00223   {
00224     std::cerr << "Mesh got empty -> Reset\n";
00225     lock.unlock ();
00226     this->reset ();
00227   }
00228   else
00229   {
00230     lock.unlock ();
00231     this->showModel ();
00232   }
00233 }
00234 
00236 
00237 void
00238 pcl::ihs::InHandScanner::reset ()
00239 {
00240   boost::mutex::scoped_lock lock (mutex_);
00241   if (destructor_called_) return;
00242 
00243   std::cerr << "Reset the scanning pipeline.\n";
00244 
00245   mesh_model_->clear ();
00246   Base::removeAllMeshes ();
00247 
00248   iteration_      = 0;
00249   transformation_ = Eigen::Matrix4f::Identity ();
00250 
00251   lock.unlock ();
00252   this->showUnprocessedData ();
00253 }
00254 
00256 
00257 void
00258 pcl::ihs::InHandScanner::saveAs (const std::string& filename, const FileType& filetype)
00259 {
00260   boost::mutex::scoped_lock lock (mutex_);
00261   if (destructor_called_) return;
00262 
00263   pcl::PolygonMesh pm;
00264   pcl::geometry::toFaceVertexMesh (*mesh_model_, pm);
00265 
00266   switch (filetype)
00267   {
00268     case FT_PLY: pcl::io::savePLYFile (filename, pm, 10); break;
00269     case FT_VTK: pcl::io::saveVTKFile (filename, pm, 10); break;
00270     case FT_OBJ: pcl::io::saveOBJFile (filename, pm, 10); break;
00271     default:                                          break;
00272   }
00273 }
00274 
00276 
00277 void
00278 pcl::ihs::InHandScanner::keyPressEvent (QKeyEvent* event)
00279 {
00280   // Don't allow keyboard callbacks while the grabber is starting up.
00281   if (starting_grabber_)  return;
00282   if (destructor_called_) return;
00283 
00284   switch (event->key ())
00285   {
00286     case Qt::Key_1: this->showUnprocessedData ();      break;
00287     case Qt::Key_2: this->showProcessedData ();        break;
00288     case Qt::Key_3: this->registerContinuously ();     break;
00289     case Qt::Key_4: this->registerOnce ();             break;
00290     case Qt::Key_5: this->showModel ();                break;
00291     case Qt::Key_6: this->removeUnfitVertices ();      break;
00292     case Qt::Key_0: this->reset ();                    break;
00293     case Qt::Key_C: Base::resetCamera ();              break;
00294     case Qt::Key_K: Base::toggleColoring ();           break;
00295     case Qt::Key_S: Base::toggleMeshRepresentation (); break;
00296     default:                                           break;
00297   }
00298 }
00299 
00301 
00302 void
00303 pcl::ihs::InHandScanner::newDataCallback (const CloudXYZRGBAConstPtr& cloud_in)
00304 {
00305   Base::calcFPS (computation_fps_); // Must come before the lock!
00306 
00307   boost::mutex::scoped_lock lock (mutex_);
00308   if (destructor_called_) return;
00309 
00310   pcl::StopWatch sw;
00311 
00312   // Input data processing
00313   CloudXYZRGBNormalPtr cloud_data;
00314   CloudXYZRGBNormalPtr cloud_discarded;
00315   if (running_mode_ == RM_SHOW_MODEL)
00316   {
00317     cloud_data = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ());
00318   }
00319   else if (running_mode_ == RM_UNPROCESSED)
00320   {
00321     if (!input_data_processing_->calculateNormals (cloud_in, cloud_data))
00322       return;
00323   }
00324   else if (running_mode_ >= RM_PROCESSED)
00325   {
00326     if (!input_data_processing_->segment (cloud_in, cloud_data, cloud_discarded))
00327       return;
00328   }
00329 
00330   double time_input_data_processing = sw.getTime ();
00331 
00332   // Registration & integration
00333   if (running_mode_ >= RM_REGISTRATION_CONT)
00334   {
00335     std::cerr << "\nGlobal iteration " << iteration_ << "\n";
00336     std::cerr << "Input data processing:\n"
00337               << "  - time                           : "
00338               << std::setw (8) << std::right << time_input_data_processing << " ms\n";
00339 
00340     if (iteration_ == 0)
00341     {
00342       transformation_ = Eigen::Matrix4f::Identity ();
00343 
00344       sw.reset ();
00345       integration_->reconstructMesh (cloud_data, mesh_model_);
00346       std::cerr << "Integration:\n"
00347                 << "  - time reconstruct mesh          : "
00348                 << std::setw (8) << std::right << sw.getTime () << " ms\n";
00349 
00350       cloud_data = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ());
00351       ++iteration_;
00352     }
00353     else
00354     {
00355       Eigen::Matrix4f T_final = Eigen::Matrix4f::Identity ();
00356       if (icp_->findTransformation (mesh_model_, cloud_data, transformation_, T_final))
00357       {
00358         transformation_ = T_final;
00359 
00360         sw.reset ();
00361         integration_->merge (cloud_data, mesh_model_, transformation_);
00362         std::cerr << "Integration:\n"
00363                   << "  - time merge                     : "
00364                   << std::setw (8) << std::right << sw.getTime () << " ms\n";
00365 
00366         sw.reset ();
00367         integration_->age (mesh_model_);
00368         std::cerr << "  - time age                       : "
00369                   << std::setw (8) << std::right << sw.getTime () << " ms\n";
00370 
00371         sw.reset ();
00372         std::vector <Mesh::HalfEdgeIndices> boundary_collection;
00373         pcl::geometry::getBoundBoundaryHalfEdges (*mesh_model_, boundary_collection, 1000);
00374         std::cerr << "  - time compute boundary          : "
00375                   << std::setw (8) << std::right << sw.getTime () << " ms\n";
00376 
00377         sw.reset ();
00378         mesh_processing_->processBoundary (*mesh_model_, boundary_collection);
00379         std::cerr << "  - time mesh processing           : "
00380                   << std::setw (8) << std::right << sw.getTime () << " ms\n";
00381 
00382         cloud_data = CloudXYZRGBNormalPtr (new CloudXYZRGBNormal ());
00383         ++iteration_;
00384       }
00385     }
00386   }
00387 
00388   // Visualization & copy back some variables
00389   double time_model = 0;
00390   double time_data  = 0;
00391 
00392   if (mesh_model_->empty ()) Base::setPivot ("data");
00393   else                       Base::setPivot ("model");
00394 
00395   sw.reset ();
00396   Base::addMesh (mesh_model_, "model", Eigen::Isometry3d (transformation_.inverse ().cast <double> ()));
00397   time_model = sw.getTime ();
00398 
00399   sw.reset ();
00400   if (cloud_data->width > 0 && cloud_data->height > 0)
00401 
00402   {
00403 
00404     Base::addMesh (cloud_data , "data"); // Converts to a mesh for visualization
00405 
00406   }
00407 
00408   else
00409 
00410   {
00411 
00412     Base::removeMesh ("data");
00413 
00414   }
00415 
00416   if (running_mode_ < RM_REGISTRATION_CONT && cloud_discarded)
00417   {
00418     Base::addMesh (cloud_discarded, "cloud_discarded");
00419   }
00420   else
00421   {
00422     Base::removeMesh ("cloud_discarded");
00423   }
00424   time_data = sw.getTime ();
00425 
00426   if (running_mode_ >= RM_REGISTRATION_CONT)
00427   {
00428     std::cerr << "Copy to visualization thread:\n"
00429               << "  - time model                     : "
00430               << std::setw (8) << std::right << time_model << " ms\n"
00431               << "  - time data                      : "
00432               << std::setw (8) << std::right << time_data << " ms\n";
00433   }
00434 
00435   if (running_mode_ == RM_REGISTRATION_SINGLE)
00436   {
00437     lock.unlock ();
00438     this->showProcessedData ();
00439   }
00440 }
00441 
00443 
00444 void
00445 pcl::ihs::InHandScanner::paintEvent (QPaintEvent* event)
00446 {
00447   // boost::mutex::scoped_lock lock (mutex_);
00448   if (destructor_called_) return;
00449 
00450   Base::calcFPS (visualization_fps_);
00451   Base::BoxCoefficients coeffs (input_data_processing_->getXMin (),
00452                                 input_data_processing_->getXMax (),
00453                                 input_data_processing_->getYMin (),
00454                                 input_data_processing_->getYMax (),
00455                                 input_data_processing_->getZMin (),
00456                                 input_data_processing_->getZMax (),
00457                                 Eigen::Isometry3d::Identity ());
00458   Base::setBoxCoefficients (coeffs);
00459 
00460   Base::setVisibilityConfidenceNormalization (static_cast <float> (integration_->getMinDirections ()));
00461   // lock.unlock ();
00462 
00463   Base::paintEvent (event);
00464   this->drawText (); // NOTE: Must come AFTER the opengl calls
00465 }
00466 
00468 
00469 void
00470 pcl::ihs::InHandScanner::drawText ()
00471 {
00472   QPainter painter (this);
00473   painter.setPen (Qt::white);
00474   QFont font;
00475 
00476   if (starting_grabber_)
00477   {
00478     font.setPointSize (this->width () / 20);
00479     painter.setFont (font);
00480     painter.drawText (0, 0, this->width (), this->height (), Qt::AlignHCenter | Qt::AlignVCenter, "Starting the grabber.\n Please wait.");
00481   }
00482   else
00483   {
00484     std::string vis_fps ("Visualization: "), comp_fps ("Computation: ");
00485 
00486     vis_fps.append  (visualization_fps_.str ()).append (" fps");
00487     comp_fps.append (computation_fps_.str   ()).append (" fps");
00488 
00489     const std::string str = std::string (comp_fps).append ("\n").append (vis_fps);
00490 
00491     font.setPointSize (this->width () / 50);
00492 
00493     painter.setFont (font);
00494     painter.drawText (0, 0, this->width (), this->height (), Qt::AlignBottom | Qt::AlignLeft, str.c_str ());
00495   }
00496 }
00497 
00498 void pcl::ihs::InHandScanner::grab_pc(const sensor_msgs::PointCloud2::ConstPtr &msg)
00499 {
00500 
00501 
00502     pcl_conversions::toPCL(*msg,pcl_pc2);
00503     pcl::fromPCLPointCloud2(pcl_pc2,*cloud_ptr_xyzrgba);
00504 
00505     pcl::ihs::InHandScanner::newDataCallback(cloud_ptr_xyzrgba);
00506      
00507 }
00508 
00510 
00511 void
00512 pcl::ihs::InHandScanner::startGrabberImpl ()
00513 {
00514 
00515   if (destructor_called_) return;
00516 
00517   //added ROS stuff
00518 
00519   ros::NodeHandle n;
00520 
00521   ros::Subscriber sub = n.subscribe("/camera/depth_registered/points", 50, &pcl::ihs::InHandScanner::grab_pc, this);
00522   starting_grabber_ = false;
00523   ros::spin();
00524 
00525 }
00526 


ros_in_hand_scanner
Author(s):
autogenerated on Thu Jun 6 2019 20:39:38