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 
00037 
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   
00097   qRegisterMetaType <pcl::ihs::InHandScanner::RunningMode> ("RunningMode");
00098 
00099   Base::setScalingFactor (0.01);
00100 
00101   
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   
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_); 
00306 
00307   boost::mutex::scoped_lock lock (mutex_);
00308   if (destructor_called_) return;
00309 
00310   pcl::StopWatch sw;
00311 
00312   
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   
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   
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"); 
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   
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   
00462 
00463   Base::paintEvent (event);
00464   this->drawText (); 
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   
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