Point Cloud Library (PCL)  1.6.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
prosac.hpp
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage, Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Id: prosac.hpp 5026 2012-03-12 02:51:44Z rusu $
35  *
36  */
37 
38 #ifndef PCL_SAMPLE_CONSENSUS_IMPL_PROSAC_H_
39 #define PCL_SAMPLE_CONSENSUS_IMPL_PROSAC_H_
40 
41 #include <boost/math/distributions/binomial.hpp>
43 
45 // Variable naming uses capital letters to make the comparison with the original paper easier
46 template<typename PointT> bool
48 {
49  // Warn and exit if no threshold was set
50  if (threshold_ == DBL_MAX)
51  {
52  PCL_ERROR ("[pcl::ProgressiveSampleConsensus::computeModel] No threshold set!\n");
53  return (false);
54  }
55 
56  // Initialize some PROSAC constants
57  const int T_N = 200000;
58  const size_t N = sac_model_->indices_->size ();
59  const size_t m = sac_model_->getSampleSize ();
60  float T_n = static_cast<float> (T_N);
61  for (unsigned int i = 0; i < m; ++i)
62  T_n *= static_cast<float> (m - i) / static_cast<float> (N - i);
63  float T_prime_n = 1.0f;
64  size_t I_N_best = 0;
65  float n = static_cast<float> (m);
66 
67  // Define the n_Start coefficients from Section 2.2
68  float n_star = static_cast<float> (N);
69  float epsilon_n_star = 0.0;
70  size_t k_n_star = T_N;
71 
72  // Compute the I_n_star_min of Equation 8
73  std::vector<unsigned int> I_n_star_min (N);
74 
75  // Initialize the usual RANSAC parameters
76  iterations_ = 0;
77 
78  std::vector<int> inliers;
79  std::vector<int> selection;
80  Eigen::VectorXf model_coefficients;
81 
82  // We will increase the pool so the indices_ vector can only contain m elements at first
83  std::vector<int> index_pool;
84  index_pool.reserve (N);
85  for (unsigned int i = 0; i < n; ++i)
86  index_pool.push_back (sac_model_->indices_->operator[](i));
87 
88  // Iterate
89  while (static_cast<unsigned int> (iterations_) < k_n_star)
90  {
91  // Choose the samples
92 
93  // Step 1
94  // According to Equation 5 in the text text, not the algorithm
95  if ((iterations_ == T_prime_n) && (n < n_star))
96  {
97  // Increase the pool
98  ++n;
99  if (n >= N)
100  break;
101  index_pool.push_back (sac_model_->indices_->at(static_cast<unsigned int> (n - 1)));
102  // Update other variables
103  float T_n_minus_1 = T_n;
104  T_n *= (static_cast<float>(n) + 1.0f) / (static_cast<float>(n) + 1.0f - static_cast<float>(m));
105  T_prime_n += ceilf (T_n - T_n_minus_1);
106  }
107 
108  // Step 2
109  sac_model_->indices_->swap (index_pool);
110  selection.clear ();
111  sac_model_->getSamples (iterations_, selection);
112  if (T_prime_n < iterations_)
113  {
114  selection.pop_back ();
115  selection.push_back (sac_model_->indices_->at(static_cast<unsigned int> (n - 1)));
116  }
117 
118  // Make sure we use the right indices for testing
119  sac_model_->indices_->swap (index_pool);
120 
121  if (selection.empty ())
122  {
123  PCL_ERROR ("[pcl::ProgressiveSampleConsensus::computeModel] No samples could be selected!\n");
124  break;
125  }
126 
127  // Search for inliers in the point cloud for the current model
128  if (!sac_model_->computeModelCoefficients (selection, model_coefficients))
129  {
130  ++iterations_;
131  continue;
132  }
133 
134  // Select the inliers that are within threshold_ from the model
135  inliers.clear ();
136  sac_model_->selectWithinDistance (model_coefficients, threshold_, inliers);
137 
138  size_t I_N = inliers.size ();
139 
140  // If we find more inliers than before
141  if (I_N > I_N_best)
142  {
143  I_N_best = I_N;
144 
145  // Save the current model/inlier/coefficients selection as being the best so far
146  inliers_ = inliers;
147  model_ = selection;
148  model_coefficients_ = model_coefficients;
149 
150  // We estimate I_n_star for different possible values of n_star by using the inliers
151  std::sort (inliers.begin (), inliers.end ());
152 
153  // Try to find a better n_star
154  // We minimize k_n_star and therefore maximize epsilon_n_star = I_n_star / n_star
155  size_t possible_n_star_best = N, I_possible_n_star_best = I_N;
156  float epsilon_possible_n_star_best = static_cast<float>(I_possible_n_star_best) / static_cast<float>(possible_n_star_best);
157 
158  // We only need to compute possible better epsilon_n_star for when _n is just about to be removed an inlier
159  size_t I_possible_n_star = I_N;
160  for (std::vector<int>::const_reverse_iterator last_inlier = inliers.rbegin (),
161  inliers_end = inliers.rend ();
162  last_inlier != inliers_end;
163  ++last_inlier, --I_possible_n_star)
164  {
165  // The best possible_n_star for a given I_possible_n_star is the index of the last inlier
166  unsigned int possible_n_star = (*last_inlier) + 1;
167  if (possible_n_star <= m)
168  break;
169 
170  // If we find a better epsilon_n_star
171  float epsilon_possible_n_star = static_cast<float>(I_possible_n_star) / static_cast<float>(possible_n_star);
172  // Make sure we have a better epsilon_possible_n_star
173  if ((epsilon_possible_n_star > epsilon_n_star) && (epsilon_possible_n_star > epsilon_possible_n_star_best))
174  {
175  using namespace boost::math;
176  // Typo in Equation 7, not (n-m choose i-m) but (n choose i-m)
177  size_t I_possible_n_star_min = m
178  + static_cast<size_t> (ceil (quantile (complement (binomial_distribution<float>(static_cast<float> (possible_n_star), 0.1f), 0.05))));
179  // If Equation 9 is not verified, exit
180  if (I_possible_n_star < I_possible_n_star_min)
181  break;
182 
183  possible_n_star_best = possible_n_star;
184  I_possible_n_star_best = I_possible_n_star;
185  epsilon_possible_n_star_best = epsilon_possible_n_star;
186  }
187  }
188 
189  // Check if we get a better epsilon
190  if (epsilon_possible_n_star_best > epsilon_n_star)
191  {
192  // update the best value
193  epsilon_n_star = epsilon_possible_n_star_best;
194 
195  // Compute the new k_n_star
196  float bottom_log = 1 - std::pow (epsilon_n_star, static_cast<float>(m));
197  if (bottom_log == 0)
198  k_n_star = 1;
199  else if (bottom_log == 1)
200  k_n_star = T_N;
201  else
202  k_n_star = static_cast<int> (ceil (log (0.05) / log (bottom_log)));
203  // It seems weird to have very few iterations, so do have a few (totally empirical)
204  k_n_star = (std::max)(k_n_star, 2 * m);
205  }
206  }
207 
208  ++iterations_;
209  if (debug_verbosity_level > 1)
210  PCL_DEBUG ("[pcl::ProgressiveSampleConsensus::computeModel] Trial %d out of %d: %d inliers (best is: %d so far).\n", iterations_, k_n_star, I_N, I_N_best);
211  if (iterations_ > max_iterations_)
212  {
213  if (debug_verbosity_level > 0)
214  PCL_DEBUG ("[pcl::ProgressiveSampleConsensus::computeModel] RANSAC reached the maximum number of trials.\n");
215  break;
216  }
217  }
218 
219  if (debug_verbosity_level > 0)
220  PCL_DEBUG ("[pcl::ProgressiveSampleConsensus::computeModel] Model: %zu size, %d inliers.\n", model_.size (), I_N_best);
221 
222  if (model_.empty ())
223  {
224  inliers_.clear ();
225  return (false);
226  }
227 
228  // Get the set of inliers that correspond to the best model found so far
229  //sac_model_->selectWithinDistance (model_coefficients_, threshold_, inliers_);
230  return (true);
231 }
232 
233 #define PCL_INSTANTIATE_ProgressiveSampleConsensus(T) template class PCL_EXPORTS pcl::ProgressiveSampleConsensus<T>;
234 
235 #endif // PCL_SAMPLE_CONSENSUS_IMPL_PROSAC_H_