Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ia_ransac.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-2012, Willow Garage, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of Willow Garage, Inc. nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $Id: ia_ransac.hpp 5066 2012-03-14 06:42:21Z rusu $
37  *
38  */
39 
40 #ifndef IA_RANSAC_HPP_
41 #define IA_RANSAC_HPP_
42 
43 #include <pcl/common/distances.h>
44 
46 template <typename PointSource, typename PointTarget, typename FeatureT> void
48 {
49  if (features == NULL || features->empty ())
50  {
51  PCL_ERROR ("[pcl::%s::setSourceFeatures] Invalid or empty point cloud dataset given!\n", getClassName ().c_str ());
52  return;
53  }
54  input_features_ = features;
55 }
56 
58 template <typename PointSource, typename PointTarget, typename FeatureT> void
60 {
61  if (features == NULL || features->empty ())
62  {
63  PCL_ERROR ("[pcl::%s::setTargetFeatures] Invalid or empty point cloud dataset given!\n", getClassName ().c_str ());
64  return;
65  }
66  target_features_ = features;
67  feature_tree_->setInputCloud (target_features_);
68 }
69 
71 template <typename PointSource, typename PointTarget, typename FeatureT> void
73  const PointCloudSource &cloud, int nr_samples, float min_sample_distance,
74  std::vector<int> &sample_indices)
75 {
76  if (nr_samples > static_cast<int> (cloud.points.size ()))
77  {
78  PCL_ERROR ("[pcl::%s::selectSamples] ", getClassName ().c_str ());
79  PCL_ERROR ("The number of samples (%d) must not be greater than the number of points (%zu)!\n",
80  nr_samples, cloud.points.size ());
81  return;
82  }
83 
84  // Iteratively draw random samples until nr_samples is reached
85  int iterations_without_a_sample = 0;
86  int max_iterations_without_a_sample = static_cast<int> (3 * cloud.points.size ());
87  sample_indices.clear ();
88  while (static_cast<int> (sample_indices.size ()) < nr_samples)
89  {
90  // Choose a sample at random
91  int sample_index = getRandomIndex (static_cast<int> (cloud.points.size ()));
92 
93  // Check to see if the sample is 1) unique and 2) far away from the other samples
94  bool valid_sample = true;
95  for (size_t i = 0; i < sample_indices.size (); ++i)
96  {
97  float distance_between_samples = euclideanDistance (cloud.points[sample_index], cloud.points[sample_indices[i]]);
98 
99  if (sample_index == sample_indices[i] || distance_between_samples < min_sample_distance)
100  {
101  valid_sample = false;
102  break;
103  }
104  }
105 
106  // If the sample is valid, add it to the output
107  if (valid_sample)
108  {
109  sample_indices.push_back (sample_index);
110  iterations_without_a_sample = 0;
111  }
112  else
113  {
114  ++iterations_without_a_sample;
115  }
116 
117  // If no valid samples can be found, relax the inter-sample distance requirements
118  if (iterations_without_a_sample >= max_iterations_without_a_sample)
119  {
120  PCL_WARN ("[pcl::%s::selectSamples] ", getClassName ().c_str ());
121  PCL_WARN ("No valid sample found after %d iterations. Relaxing min_sample_distance_ to %f\n",
122  iterations_without_a_sample, 0.5*min_sample_distance);
123 
124  min_sample_distance_ *= 0.5f;
125  min_sample_distance = min_sample_distance_;
126  iterations_without_a_sample = 0;
127  }
128  }
129 
130 }
131 
133 template <typename PointSource, typename PointTarget, typename FeatureT> void
135  const FeatureCloud &input_features, const std::vector<int> &sample_indices,
136  std::vector<int> &corresponding_indices)
137 {
138  std::vector<int> nn_indices (k_correspondences_);
139  std::vector<float> nn_distances (k_correspondences_);
140 
141  corresponding_indices.resize (sample_indices.size ());
142  for (size_t i = 0; i < sample_indices.size (); ++i)
143  {
144  // Find the k features nearest to input_features.points[sample_indices[i]]
145  feature_tree_->nearestKSearch (input_features, sample_indices[i], k_correspondences_, nn_indices, nn_distances);
146 
147  // Select one at random and add it to corresponding_indices
148  int random_correspondence = getRandomIndex (k_correspondences_);
149  corresponding_indices[i] = nn_indices[random_correspondence];
150  }
151 }
152 
154 template <typename PointSource, typename PointTarget, typename FeatureT> float
156  const PointCloudSource &cloud, float)
157 {
158  std::vector<int> nn_index (1);
159  std::vector<float> nn_distance (1);
160 
161  const ErrorFunctor & compute_error = *error_functor_;
162  float error = 0;
163 
164  for (int i = 0; i < static_cast<int> (cloud.points.size ()); ++i)
165  {
166  // Find the distance between cloud.points[i] and its nearest neighbor in the target point cloud
167  tree_->nearestKSearch (cloud, i, 1, nn_index, nn_distance);
168 
169  // Compute the error
170  error += compute_error (nn_distance[0]);
171  }
172  return (error);
173 }
174 
176 template <typename PointSource, typename PointTarget, typename FeatureT> void
178 {
179  if (!input_features_)
180  {
181  PCL_ERROR ("[pcl::%s::computeTransformation] ", getClassName ().c_str ());
182  PCL_ERROR ("No source features were given! Call setSourceFeatures before aligning.\n");
183  return;
184  }
185  if (!target_features_)
186  {
187  PCL_ERROR ("[pcl::%s::computeTransformation] ", getClassName ().c_str ());
188  PCL_ERROR ("No target features were given! Call setTargetFeatures before aligning.\n");
189  return;
190  }
191 
192  if (!error_functor_)
193  {
194  error_functor_.reset (new TruncatedError (static_cast<float> (corr_dist_threshold_)));
195  }
196 
197  std::vector<int> sample_indices (nr_samples_);
198  std::vector<int> corresponding_indices (nr_samples_);
199  PointCloudSource input_transformed;
200  float error, lowest_error (0);
201 
202  final_transformation_ = guess;
203  int i_iter = 0;
204  if (!guess.isApprox(Eigen::Matrix4f::Identity (), 0.01f))
205  { //If guess is not the Identity matrix we check it.
206  transformPointCloud (*input_, input_transformed, final_transformation_);
207  lowest_error = computeErrorMetric (input_transformed, static_cast<float> (corr_dist_threshold_));
208  i_iter = 1;
209  }
210 
211  for (; i_iter < max_iterations_; ++i_iter)
212  {
213  // Draw nr_samples_ random samples
214  selectSamples (*input_, nr_samples_, min_sample_distance_, sample_indices);
215 
216  // Find corresponding features in the target cloud
217  findSimilarFeatures (*input_features_, sample_indices, corresponding_indices);
218 
219  // Estimate the transform from the samples to their corresponding points
220  transformation_estimation_->estimateRigidTransformation (*input_, sample_indices, *target_, corresponding_indices, transformation_);
221 
222  // Tranform the data and compute the error
223  transformPointCloud (*input_, input_transformed, transformation_);
224  error = computeErrorMetric (input_transformed, static_cast<float> (corr_dist_threshold_));
225 
226  // If the new error is lower, update the final transformation
227  if (i_iter == 0 || error < lowest_error)
228  {
229  lowest_error = error;
230  final_transformation_ = transformation_;
231  }
232  }
233 
234  // Apply the final transformation
235  transformPointCloud (*input_, output, final_transformation_);
236 }
237 
238 #endif //#ifndef IA_RANSAC_HPP_
239