Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
icp.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of Willow Garage, Inc. nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id: icp.hpp 5980 2012-06-24 16:07:14Z rusu $
38  *
39  */
40 
41 #include <boost/unordered_map.hpp>
42 
44 template <typename PointSource, typename PointTarget> void
45 pcl::IterativeClosestPoint<PointSource, PointTarget>::computeTransformation (PointCloudSource &output, const Eigen::Matrix4f &guess)
46 {
47  // Allocate enough space to hold the results
48  std::vector<int> nn_indices (1);
49  std::vector<float> nn_dists (1);
50 
51  // Point cloud containing the correspondences of each point in <input, indices>
52  PointCloudTarget input_corresp;
53  input_corresp.points.resize (indices_->size ());
54 
55  nr_iterations_ = 0;
56  converged_ = false;
57  double dist_threshold = corr_dist_threshold_ * corr_dist_threshold_;
58 
59  // If the guessed transformation is non identity
60  if (guess != Eigen::Matrix4f::Identity ())
61  {
62  // Initialise final transformation to the guessed one
63  final_transformation_ = guess;
64  // Apply guessed transformation prior to search for neighbours
65  transformPointCloud (output, output, guess);
66  }
67 
68  // Resize the vector of distances between correspondences
69  std::vector<float> previous_correspondence_distances (indices_->size ());
70  correspondence_distances_.resize (indices_->size ());
71 
72  while (!converged_) // repeat until convergence
73  {
74  // Save the previously estimated transformation
75  previous_transformation_ = transformation_;
76  // And the previous set of distances
77  previous_correspondence_distances = correspondence_distances_;
78 
79  int cnt = 0;
80  std::vector<int> source_indices (indices_->size ());
81  std::vector<int> target_indices (indices_->size ());
82 
83  // Iterating over the entire index vector and find all correspondences
84  for (size_t idx = 0; idx < indices_->size (); ++idx)
85  {
86  if (!this->searchForNeighbors (output, (*indices_)[idx], nn_indices, nn_dists))
87  {
88  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]);
89  return;
90  }
91 
92  // Check if the distance to the nearest neighbor is smaller than the user imposed threshold
93  if (nn_dists[0] < dist_threshold)
94  {
95  source_indices[cnt] = (*indices_)[idx];
96  target_indices[cnt] = nn_indices[0];
97  cnt++;
98  }
99 
100  // Save the nn_dists[0] to a global vector of distances
101  correspondence_distances_[(*indices_)[idx]] = std::min (nn_dists[0], static_cast<float> (dist_threshold));
102  }
103  if (cnt < min_number_correspondences_)
104  {
105  PCL_ERROR ("[pcl::%s::computeTransformation] Not enough correspondences found. Relax your threshold parameters.\n", getClassName ().c_str ());
106  converged_ = false;
107  return;
108  }
109 
110  // Resize to the actual number of valid correspondences
111  source_indices.resize (cnt); target_indices.resize (cnt);
112 
113  std::vector<int> source_indices_good;
114  std::vector<int> target_indices_good;
115  {
116  // From the set of correspondences found, attempt to remove outliers
117  // Create the registration model
118  typedef typename SampleConsensusModelRegistration<PointSource>::Ptr SampleConsensusModelRegistrationPtr;
119  SampleConsensusModelRegistrationPtr model;
120  model.reset (new SampleConsensusModelRegistration<PointSource> (output.makeShared (), source_indices));
121  // Pass the target_indices
122  model->setInputTarget (target_, target_indices);
123  // Create a RANSAC model
124  RandomSampleConsensus<PointSource> sac (model, inlier_threshold_);
125  sac.setMaxIterations (ransac_iterations_);
126 
127  // Compute the set of inliers
128  if (!sac.computeModel ())
129  {
130  source_indices_good = source_indices;
131  target_indices_good = target_indices;
132  }
133  else
134  {
135  std::vector<int> inliers;
136  // Get the inliers
137  sac.getInliers (inliers);
138  source_indices_good.resize (inliers.size ());
139  target_indices_good.resize (inliers.size ());
140 
141  boost::unordered_map<int, int> source_to_target;
142  for (unsigned int i = 0; i < source_indices.size(); ++i)
143  source_to_target[source_indices[i]] = target_indices[i];
144 
145  // Copy just the inliers
146  std::copy(inliers.begin(), inliers.end(), source_indices_good.begin());
147  for (size_t i = 0; i < inliers.size (); ++i)
148  target_indices_good[i] = source_to_target[inliers[i]];
149  }
150  }
151 
152  // Check whether we have enough correspondences
153  cnt = static_cast<int> (source_indices_good.size ());
154  if (cnt < min_number_correspondences_)
155  {
156  PCL_ERROR ("[pcl::%s::computeTransformation] Not enough correspondences found. Relax your threshold parameters.\n", getClassName ().c_str ());
157  converged_ = false;
158  return;
159  }
160 
161  PCL_DEBUG ("[pcl::%s::computeTransformation] Number of correspondences %d [%f%%] out of %zu points [100.0%%], RANSAC rejected: %zu [%f%%].\n",
162  getClassName ().c_str (),
163  cnt,
164  (static_cast<float> (cnt) * 100.0f) / static_cast<float> (indices_->size ()),
165  indices_->size (),
166  source_indices.size () - cnt,
167  static_cast<float> (source_indices.size () - cnt) * 100.0f / static_cast<float> (source_indices.size ()));
168 
169  // Estimate the transform
170  //rigid_transformation_estimation_(output, source_indices_good, *target_, target_indices_good, transformation_);
171  transformation_estimation_->estimateRigidTransformation (output, source_indices_good, *target_, target_indices_good, transformation_);
172 
173  // Tranform the data
174  transformPointCloud (output, output, transformation_);
175 
176  // Obtain the final transformation
177  final_transformation_ = transformation_ * final_transformation_;
178 
179  nr_iterations_++;
180 
181  // Update the vizualization of icp convergence
182  if (update_visualizer_ != 0)
183  update_visualizer_(output, source_indices_good, *target_, target_indices_good );
184 
185  // Various/Different convergence termination criteria
186  // 1. Number of iterations has reached the maximum user imposed number of iterations (via
187  // setMaximumIterations)
188  // 2. The epsilon (difference) between the previous transformation and the current estimated transformation
189  // is smaller than an user imposed value (via setTransformationEpsilon)
190  // 3. The sum of Euclidean squared errors is smaller than a user defined threshold (via
191  // setEuclideanFitnessEpsilon)
192 
193  if (nr_iterations_ >= max_iterations_ ||
194  (transformation_ - previous_transformation_).array ().abs ().sum () < transformation_epsilon_ ||
195  fabs (this->getFitnessScore (correspondence_distances_, previous_correspondence_distances)) <= euclidean_fitness_epsilon_
196  )
197  {
198  converged_ = true;
199  PCL_DEBUG ("[pcl::%s::computeTransformation] Convergence reached. Number of iterations: %d out of %d. Transformation difference: %f\n",
200  getClassName ().c_str (), nr_iterations_, max_iterations_, (transformation_ - previous_transformation_).array ().abs ().sum ());
201 
202  PCL_DEBUG ("nr_iterations_ (%d) >= max_iterations_ (%d)\n", nr_iterations_, max_iterations_);
203  PCL_DEBUG ("(transformation_ - previous_transformation_).array ().abs ().sum () (%f) < transformation_epsilon_ (%f)\n",
204  (transformation_ - previous_transformation_).array ().abs ().sum (), transformation_epsilon_);
205  PCL_DEBUG ("fabs (getFitnessScore (correspondence_distances_, previous_correspondence_distances)) (%f) <= euclidean_fitness_epsilon_ (%f)\n",
206  fabs (this->getFitnessScore (correspondence_distances_, previous_correspondence_distances)),
207  euclidean_fitness_epsilon_);
208 
209  }
210  }
211 }
212