icp.hpp
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) 2010-2011, 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 Willow Garage, Inc. 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: icp.hpp 5980 2012-06-24 16:07:14Z rusu $
00038  *
00039  */
00040 
00041 #include <boost/unordered_map.hpp>
00042 
00044 template <typename PointSource, typename PointTarget> void
00045 pcl::IterativeClosestPoint<PointSource, PointTarget>::computeTransformation (PointCloudSource &output, const Eigen::Matrix4f &guess)
00046 {
00047   // Allocate enough space to hold the results
00048   std::vector<int> nn_indices (1);
00049   std::vector<float> nn_dists (1);
00050 
00051   // Point cloud containing the correspondences of each point in <input, indices>
00052   PointCloudTarget input_corresp;
00053   input_corresp.points.resize (indices_->size ());
00054 
00055   nr_iterations_ = 0;
00056   converged_ = false;
00057   double dist_threshold = corr_dist_threshold_ * corr_dist_threshold_;
00058 
00059   // If the guessed transformation is non identity
00060   if (guess != Eigen::Matrix4f::Identity ())
00061   {
00062     // Initialise final transformation to the guessed one
00063     final_transformation_ = guess;
00064     // Apply guessed transformation prior to search for neighbours
00065     transformPointCloud (output, output, guess);
00066   }
00067 
00068   // Resize the vector of distances between correspondences 
00069   std::vector<float> previous_correspondence_distances (indices_->size ());
00070   correspondence_distances_.resize (indices_->size ());
00071 
00072   while (!converged_)           // repeat until convergence
00073   {
00074     // Save the previously estimated transformation
00075     previous_transformation_ = transformation_;
00076     // And the previous set of distances
00077     previous_correspondence_distances = correspondence_distances_;
00078 
00079     int cnt = 0;
00080     std::vector<int> source_indices (indices_->size ());
00081     std::vector<int> target_indices (indices_->size ());
00082 
00083     // Iterating over the entire index vector and  find all correspondences
00084     for (size_t idx = 0; idx < indices_->size (); ++idx)
00085     {
00086       if (!this->searchForNeighbors (output, (*indices_)[idx], nn_indices, nn_dists))
00087       {
00088         PCL_ERROR ("[pcl::%s::computeTransformation] Unable to find a nearest neighbor in the target dataset for point %d in the source!\n", getClassName ().c_str (), (*indices_)[idx]);
00089         return;
00090       }
00091 
00092       // Check if the distance to the nearest neighbor is smaller than the user imposed threshold
00093       if (nn_dists[0] < dist_threshold)
00094       {
00095         source_indices[cnt] = (*indices_)[idx];
00096         target_indices[cnt] = nn_indices[0];
00097         cnt++;
00098       }
00099 
00100       // Save the nn_dists[0] to a global vector of distances
00101       correspondence_distances_[(*indices_)[idx]] = std::min (nn_dists[0], static_cast<float> (dist_threshold));
00102     }
00103     if (cnt < min_number_correspondences_)
00104     {
00105       PCL_ERROR ("[pcl::%s::computeTransformation] Not enough correspondences found. Relax your threshold parameters.\n", getClassName ().c_str ());
00106       converged_ = false;
00107       return;
00108     }
00109 
00110     // Resize to the actual number of valid correspondences
00111     source_indices.resize (cnt); target_indices.resize (cnt);
00112 
00113     std::vector<int> source_indices_good;
00114     std::vector<int> target_indices_good;
00115     {
00116       // From the set of correspondences found, attempt to remove outliers
00117       // Create the registration model
00118       typedef typename SampleConsensusModelRegistration<PointSource>::Ptr SampleConsensusModelRegistrationPtr;
00119       SampleConsensusModelRegistrationPtr model;
00120       model.reset (new SampleConsensusModelRegistration<PointSource> (output.makeShared (), source_indices));
00121       // Pass the target_indices
00122       model->setInputTarget (target_, target_indices);
00123       // Create a RANSAC model
00124       RandomSampleConsensus<PointSource> sac (model, inlier_threshold_);
00125       sac.setMaxIterations (ransac_iterations_);
00126 
00127       // Compute the set of inliers
00128       if (!sac.computeModel ())
00129       {
00130         source_indices_good = source_indices;
00131         target_indices_good = target_indices;
00132       }
00133       else
00134       {
00135         std::vector<int> inliers;
00136         // Get the inliers
00137         sac.getInliers (inliers);
00138         source_indices_good.resize (inliers.size ());
00139         target_indices_good.resize (inliers.size ());
00140 
00141         boost::unordered_map<int, int> source_to_target;
00142         for (unsigned int i = 0; i < source_indices.size(); ++i)
00143           source_to_target[source_indices[i]] = target_indices[i];
00144 
00145         // Copy just the inliers
00146         std::copy(inliers.begin(), inliers.end(), source_indices_good.begin());
00147         for (size_t i = 0; i < inliers.size (); ++i)
00148           target_indices_good[i] = source_to_target[inliers[i]];
00149       }
00150     }
00151 
00152     // Check whether we have enough correspondences
00153     cnt = static_cast<int> (source_indices_good.size ());
00154     if (cnt < min_number_correspondences_)
00155     {
00156       PCL_ERROR ("[pcl::%s::computeTransformation] Not enough correspondences found. Relax your threshold parameters.\n", getClassName ().c_str ());
00157       converged_ = false;
00158       return;
00159     }
00160 
00161     PCL_DEBUG ("[pcl::%s::computeTransformation] Number of correspondences %d [%f%%] out of %zu points [100.0%%], RANSAC rejected: %zu [%f%%].\n", 
00162         getClassName ().c_str (), 
00163         cnt, 
00164         (static_cast<float> (cnt) * 100.0f) / static_cast<float> (indices_->size ()), 
00165         indices_->size (), 
00166         source_indices.size () - cnt, 
00167         static_cast<float> (source_indices.size () - cnt) * 100.0f / static_cast<float> (source_indices.size ()));
00168   
00169     // Estimate the transform
00170     //rigid_transformation_estimation_(output, source_indices_good, *target_, target_indices_good, transformation_);
00171     transformation_estimation_->estimateRigidTransformation (output, source_indices_good, *target_, target_indices_good, transformation_);
00172 
00173     // Tranform the data
00174     transformPointCloud (output, output, transformation_);
00175 
00176     // Obtain the final transformation    
00177     final_transformation_ = transformation_ * final_transformation_;
00178 
00179     nr_iterations_++;
00180 
00181     // Update the vizualization of icp convergence
00182     if (update_visualizer_ != 0)
00183       update_visualizer_(output, source_indices_good, *target_, target_indices_good );
00184 
00185     // Various/Different convergence termination criteria
00186     // 1. Number of iterations has reached the maximum user imposed number of iterations (via 
00187     //    setMaximumIterations)
00188     // 2. The epsilon (difference) between the previous transformation and the current estimated transformation 
00189     //    is smaller than an user imposed value (via setTransformationEpsilon)
00190     // 3. The sum of Euclidean squared errors is smaller than a user defined threshold (via 
00191     //    setEuclideanFitnessEpsilon)
00192 
00193     if (nr_iterations_ >= max_iterations_ ||
00194         (transformation_ - previous_transformation_).array ().abs ().sum () < transformation_epsilon_ ||
00195         fabs (this->getFitnessScore (correspondence_distances_, previous_correspondence_distances)) <= euclidean_fitness_epsilon_
00196        )
00197     {
00198       converged_ = true;
00199       PCL_DEBUG ("[pcl::%s::computeTransformation] Convergence reached. Number of iterations: %d out of %d. Transformation difference: %f\n",
00200                  getClassName ().c_str (), nr_iterations_, max_iterations_, (transformation_ - previous_transformation_).array ().abs ().sum ());
00201 
00202       PCL_DEBUG ("nr_iterations_ (%d) >= max_iterations_ (%d)\n", nr_iterations_, max_iterations_);
00203       PCL_DEBUG ("(transformation_ - previous_transformation_).array ().abs ().sum () (%f) < transformation_epsilon_ (%f)\n",
00204                  (transformation_ - previous_transformation_).array ().abs ().sum (), transformation_epsilon_);
00205       PCL_DEBUG ("fabs (getFitnessScore (correspondence_distances_, previous_correspondence_distances)) (%f) <= euclidean_fitness_epsilon_ (%f)\n",
00206                  fabs (this->getFitnessScore (correspondence_distances_, previous_correspondence_distances)),
00207                  euclidean_fitness_epsilon_);
00208 
00209     }
00210   }
00211 }
00212 


pcl
Author(s): Open Perception
autogenerated on Mon Oct 6 2014 03:15:25