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