ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
loransac.h
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #pragma once
9 
10 #include <cfloat>
11 #include <random>
12 #include <stdexcept>
13 #include <vector>
14 
15 #include "optim/random_sampler.h"
16 #include "optim/ransac.h"
18 #include "util/alignment.h"
19 #include "util/logging.h"
20 
21 namespace colmap {
22 
23 // Implementation of LO-RANSAC (Locally Optimized RANSAC).
24 //
25 // "Locally Optimized RANSAC" Ondrej Chum, Jiri Matas, Josef Kittler, DAGM 2003.
26 template <typename Estimator,
27  typename LocalEstimator,
28  typename SupportMeasurer = InlierSupportMeasurer,
29  typename Sampler = RandomSampler>
30 class LORANSAC : public RANSAC<Estimator, SupportMeasurer, Sampler> {
31 public:
33 
34  explicit LORANSAC(const RANSACOptions& options);
35 
36  // Robustly estimate model with RANSAC (RANdom SAmple Consensus).
37  //
38  // @param X Independent variables.
39  // @param Y Dependent variables.
40  //
41  // @return The report with the results of the estimation.
42  Report Estimate(const std::vector<typename Estimator::X_t>& X,
43  const std::vector<typename Estimator::Y_t>& Y);
44 
45  // Objects used in RANSAC procedure.
47  LocalEstimator local_estimator;
50 
51 private:
53 };
54 
56 // Implementation
58 
59 template <typename Estimator,
60  typename LocalEstimator,
61  typename SupportMeasurer,
62  typename Sampler>
64  const RANSACOptions& options)
65  : RANSAC<Estimator, SupportMeasurer, Sampler>(options) {}
66 
67 template <typename Estimator,
68  typename LocalEstimator,
69  typename SupportMeasurer,
70  typename Sampler>
73  const std::vector<typename Estimator::X_t>& X,
74  const std::vector<typename Estimator::Y_t>& Y) {
75  CHECK_EQ(X.size(), Y.size());
76 
77  const size_t num_samples = X.size();
78 
80  report.success = false;
81  report.num_trials = 0;
82 
83  if (num_samples < Estimator::kMinNumSamples) {
84  return report;
85  }
86 
87  typename SupportMeasurer::Support best_support;
88  typename Estimator::M_t best_model;
89  bool best_model_is_local = false;
90 
91  bool abort = false;
92 
93  const double max_residual = options_.max_error * options_.max_error;
94 
95  std::vector<double> residuals;
96  std::vector<double> best_local_residuals;
97 
98  std::vector<typename LocalEstimator::X_t> X_inlier;
99  std::vector<typename LocalEstimator::Y_t> Y_inlier;
100 
101  std::vector<typename Estimator::X_t> X_rand(Estimator::kMinNumSamples);
102  std::vector<typename Estimator::Y_t> Y_rand(Estimator::kMinNumSamples);
103 
104  sampler.Initialize(num_samples);
105 
106  size_t max_num_trials = options_.max_num_trials;
107  max_num_trials = std::min<size_t>(max_num_trials, sampler.MaxNumSamples());
108  size_t dyn_max_num_trials = max_num_trials;
109 
110  for (report.num_trials = 0; report.num_trials < max_num_trials;
111  ++report.num_trials) {
112  if (abort) {
113  report.num_trials += 1;
114  break;
115  }
116 
117  sampler.SampleXY(X, Y, &X_rand, &Y_rand);
118 
119  // Estimate model for current subset.
120  const std::vector<typename Estimator::M_t> sample_models =
121  estimator.Estimate(X_rand, Y_rand);
122 
123  // Iterate through all estimated models
124  for (const auto& sample_model : sample_models) {
125  estimator.Residuals(X, Y, sample_model, &residuals);
126  CHECK_EQ(residuals.size(), num_samples);
127 
128  const auto support =
129  support_measurer.Evaluate(residuals, max_residual);
130 
131  // Do local optimization if better than all previous subsets.
132  if (support_measurer.Compare(support, best_support)) {
133  best_support = support;
134  best_model = sample_model;
135  best_model_is_local = false;
136 
137  // Estimate locally optimized model from inliers.
138  if (support.num_inliers > Estimator::kMinNumSamples &&
139  support.num_inliers >= LocalEstimator::kMinNumSamples) {
140  // Recursive local optimization to expand inlier set.
141  const size_t kMaxNumLocalTrials = 10;
142  for (size_t local_num_trials = 0;
143  local_num_trials < kMaxNumLocalTrials;
144  ++local_num_trials) {
145  X_inlier.clear();
146  Y_inlier.clear();
147  X_inlier.reserve(num_samples);
148  Y_inlier.reserve(num_samples);
149  for (size_t i = 0; i < residuals.size(); ++i) {
150  if (residuals[i] <= max_residual) {
151  X_inlier.push_back(X[i]);
152  Y_inlier.push_back(Y[i]);
153  }
154  }
155 
156  const std::vector<typename LocalEstimator::M_t>
157  local_models = local_estimator.Estimate(
158  X_inlier, Y_inlier);
159 
160  const size_t prev_best_num_inliers =
161  best_support.num_inliers;
162 
163  for (const auto& local_model : local_models) {
164  local_estimator.Residuals(X, Y, local_model,
165  &residuals);
166  CHECK_EQ(residuals.size(), num_samples);
167 
168  const auto local_support =
169  support_measurer.Evaluate(residuals,
170  max_residual);
171 
172  // Check if locally optimized model is better.
173  if (support_measurer.Compare(local_support,
174  best_support)) {
175  best_support = local_support;
176  best_model = local_model;
177  best_model_is_local = true;
178  std::swap(residuals, best_local_residuals);
179  }
180  }
181 
182  // Only continue recursive local optimization, if the
183  // inlier set size increased and we thus have a chance
184  // to further improve.
185  if (best_support.num_inliers <= prev_best_num_inliers) {
186  break;
187  }
188 
189  // Swap back the residuals, so we can extract the best
190  // inlier set in the next recursion of local
191  // optimization.
192  std::swap(residuals, best_local_residuals);
193  }
194  }
195 
196  dyn_max_num_trials =
199  best_support.num_inliers, num_samples,
200  options_.confidence,
201  options_.dyn_num_trials_multiplier);
202  }
203 
204  if (report.num_trials >= dyn_max_num_trials &&
205  report.num_trials >= options_.min_num_trials) {
206  abort = true;
207  break;
208  }
209  }
210  }
211 
212  report.support = best_support;
213  report.model = best_model;
214 
215  // No valid model was found
216  if (report.support.num_inliers < estimator.kMinNumSamples) {
217  return report;
218  }
219 
220  report.success = true;
221 
222  // Determine inlier mask. Note that this calculates the residuals for the
223  // best model twice, but saves to copy and fill the inlier mask for each
224  // evaluated model. Some benchmarking revealed that this approach is faster.
225 
226  if (best_model_is_local) {
227  local_estimator.Residuals(X, Y, report.model, &residuals);
228  } else {
229  estimator.Residuals(X, Y, report.model, &residuals);
230  }
231 
232  CHECK_EQ(residuals.size(), num_samples);
233 
234  report.inlier_mask.resize(num_samples);
235  for (size_t i = 0; i < residuals.size(); ++i) {
236  report.inlier_mask[i] = residuals[i] <= max_residual;
237  }
238 
239  return report;
240 }
241 
242 } // namespace colmap
void * X
Definition: SmallVector.cpp:45
LORANSAC(const RANSACOptions &options)
Definition: loransac.h:63
Report Estimate(const std::vector< typename Estimator::X_t > &X, const std::vector< typename Estimator::Y_t > &Y)
Definition: loransac.h:72
LocalEstimator local_estimator
Definition: loransac.h:47
static size_t ComputeNumTrials(const size_t num_inliers, const size_t num_samples, const double confidence, const double num_trials_multiplier)
Definition: ransac.h:136
void swap(cloudViewer::core::SmallVectorImpl< T > &LHS, cloudViewer::core::SmallVectorImpl< T > &RHS)
Implement std::swap in terms of SmallVector swap.
Definition: SmallVector.h:1370
static const int kMinNumSamples
std::vector< char > inlier_mask
Definition: ransac.h:69
Estimator::M_t model
Definition: ransac.h:72
SupportMeasurer::Support support
Definition: ransac.h:66