GteApprQuery.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
10 #include <GTEngineDEF.h>
11 #include <algorithm>
12 #include <random>
13 #include <vector>
14 
15 // Class ApprQuery supports the RANSAC algorithm for fitting and uses the
16 // Curiously Recurring Template Pattern. The ModelType must be a class or
17 // struct with the following interfaces:
18 //
19 // // The minimum number of observations required to fit the model.
20 // int ModelType::GetMinimumRequired() const;
21 //
22 // // Compute the model error for the specified observation for the current
23 // // model parameters.
24 // Real Error(ObservationType const& observation) const;
25 //
26 // // Estimate the model parameters for all observations specified by the
27 // // indices. The three Fit() functions of ApprQuery manipulate their
28 // // inputs in order to pass them to ModelType::Fit().
29 // ModelType::Fit(std::vector<ObservationType> const& observations,
30 // std::vector<size_t> const& indices);
31 
32 namespace gte
33 {
34 
35 template <typename Real, typename ModelType, typename ObservationType>
36 class ApprQuery
37 {
38 public:
39  // Estimate the model parameters for all observations.
40  bool Fit(std::vector<ObservationType> const& observations);
41 
42  // Estimate the model parameters for a contiguous subset of observations.
43  bool Fit(std::vector<ObservationType> const& observations,
44  int const imin, int const imax);
45 
46  // Estimate the model parameters for the subset of observations specified
47  // by the indices and the number of indices that is possibly smaller than
48  // indices.size().
49  bool Fit(std::vector<ObservationType> const& observations,
50  std::vector<int> const& indices, int const numIndices);
51 
52  // Apply the RANdom SAmple Consensus algorithm for fitting a model to
53  // observations.
54  static bool RANSAC(
55  ModelType& candidateModel,
56  std::vector<ObservationType> const& observations,
57  int const numRequiredForGoodFit, Real const maxErrorForGoodFit,
58  int const numIterations, std::vector<int>& bestConsensus,
59  ModelType& bestModel);
60 };
61 
62 
63 template <typename Real, typename ModelType, typename ObservationType>
65  std::vector<ObservationType> const& observations)
66 {
67  std::vector<int> indices(observations.size());
68  int i = 0;
69  for (auto& index : indices)
70  {
71  index = i++;
72  }
73 
74  return ((ModelType*)this)->Fit(observations, indices);
75 }
76 
77 template <typename Real, typename ModelType, typename ObservationType>
79  std::vector<ObservationType> const& observations,
80  int const imin, int const imax)
81 {
82  if (imin <= imax)
83  {
84  int numIndices = imax - imin + 1;
85  std::vector<int> indices(numIndices);
86  int i = imin;
87  for (auto& index : indices)
88  {
89  index = i++;
90  }
91 
92  return ((ModelType*)this)->Fit(observations, indices);
93  }
94  else
95  {
96  return false;
97  }
98 }
99 
100 template <typename Real, typename ModelType, typename ObservationType>
102  std::vector<ObservationType> const& observations,
103  std::vector<int> const& indices, int const numIndices)
104 {
105  int imax = std::min(numIndices, static_cast<int>(observations.size()));
106  std::vector<int> localindices(imax);
107  int i = 0;
108  for (auto& index : localindices)
109  {
110  index = indices[i++];
111  }
112 
113  return ((ModelType*)this)->Fit(observations, indices);
114 }
115 
116 template <typename Real, typename ModelType, typename ObservationType>
118  ModelType& candidateModel,
119  std::vector<ObservationType> const& observations,
120  int const numRequiredForGoodFit, Real const maxErrorForGoodFit,
121  int const numIterations, std::vector<int>& bestConsensus,
122  ModelType& bestModel)
123 {
124  int const numObservations = static_cast<int>(observations.size());
125  int const minRequired = candidateModel.GetMinimumRequired();
126  if (numObservations < minRequired)
127  {
128  // Too few observations for model fitting.
129  return false;
130  }
131 
132  // The first part of the array will store the consensus set, initially
133  // filled with the minimumu number of indices that correspond to the
134  // candidate inliers. The last part will store the remaining indices.
135  // These points are tested against the model and are added to the
136  // consensus set when they fit. All the index manipulation is done
137  // in place. Initially, the candidates are the identity permutation.
138  std::vector<int> candidates(numObservations);
139  int j = 0;
140  for (auto& c : candidates)
141  {
142  c = j++;
143  }
144 
145  if (numObservations == minRequired)
146  {
147  // We have the minimum number of observations to generate the model,
148  // so RANSAC cannot be used. Compute the model with the entire set
149  // of observations.
150  bestConsensus = candidates;
151  return bestModel.Fit(observations);
152  }
153 
154  int bestNumFittedObservations = minRequired;
155 
156  for (int i = 0; i < numIterations; ++i)
157  {
158  // Randomly permute the previous candidates, partitioning the array
159  // into GetMinimumRequired() indices (the candidate inliers) followed
160  // by the remaining indices (candidates for testing against the
161  // model).
162  std::shuffle(candidates.begin(), candidates.end(),
163  std::default_random_engine());
164 
165  // Fit the model to the inliers.
166  if (candidateModel.Fit(observations, candidates, minRequired))
167  {
168  // Test each remaining observation whether it fits the model. If
169  // it does, include it in the consensus set.
170  int numFittedObservations = minRequired;
171  for (j = minRequired; j < numObservations; ++j)
172  {
173  if (candidateModel.Error(observations[candidates[j]])
174  <= maxErrorForGoodFit)
175  {
176  std::swap(candidates[j],
177  candidates[numFittedObservations]);
178  ++numFittedObservations;
179  }
180  }
181 
182  if (numFittedObservations >= numRequiredForGoodFit)
183  {
184  // We have observations that fit the model. Update the best
185  // model using the consensus set.
186  candidateModel.Fit(observations, candidates,
187  numFittedObservations);
188  if (numFittedObservations > bestNumFittedObservations)
189  {
190  // The consensus set is larger than the previous consensus
191  // set, so its model becomes the best one.
192  bestModel = candidateModel;
193  bestConsensus.resize(numFittedObservations);
194  std::copy(candidates.begin(),
195  candidates.begin() + numFittedObservations,
196  bestConsensus.begin());
197  bestNumFittedObservations = numFittedObservations;
198  }
199  }
200  }
201  }
202 
203  return bestNumFittedObservations >= numRequiredForGoodFit;
204 }
205 
206 
207 }
bool Fit(std::vector< ObservationType > const &observations)
Definition: GteApprQuery.h:64
static bool RANSAC(ModelType &candidateModel, std::vector< ObservationType > const &observations, int const numRequiredForGoodFit, Real const maxErrorForGoodFit, int const numIterations, std::vector< int > &bestConsensus, ModelType &bestModel)
Definition: GteApprQuery.h:117
const GLubyte * c
Definition: glext.h:11671
GLsizei GLenum const void * indices
Definition: glcorearb.h:401
GLuint index
Definition: glcorearb.h:781


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59