Visual Servoing Platform  version 3.6.1 under development (2024-07-27)
vpRansac.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Ransac robust algorithm.
32  */
33 
38 #ifndef VP_RANSAC_H
39 #define VP_RANSAC_H
40 
41 #include <ctime>
42 #include <visp3/core/vpConfig.h>
43 #include <visp3/core/vpColVector.h>
44 #include <visp3/core/vpMath.h>
45 #include <visp3/core/vpUniRand.h> // random number generation
46 
66 template <class vpTransformation> class vpRansac
67 {
68 public:
69  static bool ransac(unsigned int npts, const vpColVector &x, unsigned int s, double t, vpColVector &model,
70  vpColVector &inliers, int consensus = 1000, double not_used = 0.0, int maxNbumbersOfTrials = 10000,
71  double *residual = nullptr);
72 };
73 
106 template <class vpTransformation>
107 bool vpRansac<vpTransformation>::ransac(unsigned int npts, const vpColVector &x, unsigned int s, double t,
108  vpColVector &M, vpColVector &inliers, int consensus, double not_used,
109  int maxNbumbersOfTrials, double *residual)
110 {
111  /*
112  // bool isplanar;
113  // if (s == 4) isplanar = true;
114  // else isplanar = false;
115  */
116  (void)not_used;
117  double eps = 1e-6;
118  double p = 0.99; // Desired probability of choosing at least one sample
119  // free from outliers
120 
121  int maxTrials = maxNbumbersOfTrials; // Maximum number of trials before we give up.
122  int maxDataTrials = 1000; // Max number of attempts to select a non-degenerate
123  // data set.
124  const unsigned int magic_4 = 4;
125  if (s < magic_4) {
126  s = magic_4;
127  }
128 
129  // Sentinel value allowing detection of solution failure.
130  bool solutionFind = false;
131  vpColVector bestM;
132  int trialcount = 0;
133  int bestscore = -1;
134  double N = 1; // Dummy initialisation for number of trials.
135 
136  vpUniRand random(static_cast<long>(time(nullptr)));
137  vpColVector bestinliers;
138  unsigned int *ind = new unsigned int[s];
139  int ninliers = 0;
140 
141  while ((N > trialcount) && (consensus > bestscore) && (trialcount > maxTrials)) {
142  // Select at random s data points to form a trial model, M.
143  // In selecting these points we have to check that they are not in
144  // a degenerate configuration.
145 
146  bool degenerate = true;
147  int count = 1;
148 
149  while (degenerate == true) {
150  // Generate s random indicies in the range 1..npts
151  for (unsigned int i = 0; i < s; ++i) {
152  ind[i] = static_cast<unsigned int>(ceil(random() * npts)) - 1;
153  }
154 
155  // Test that these points are not a degenerate configuration.
156  degenerate = vpTransformation::degenerateConfiguration(x, ind);
157  /*
158  // degenerate = feval(degenfn, x(:,ind));
159  */
160  // Safeguard against being stuck in this loop forever
161  count = count + 1;
162 
163  if (count > maxDataTrials) {
164  delete[] ind;
165  throw(vpException(vpException::fatalError, "Unable to select a non degenerate data set"));
166  }
167  }
168  // Fit model to this random selection of data points.
169  vpTransformation::computeTransformation(x, ind, M);
170 
171  vpColVector d;
172  // Evaluate distances between points and model.
173  vpTransformation::computeResidual(x, M, d);
174 
175  // Find the indices of points that are inliers to this model.
176  if (residual != nullptr) {
177  *residual = 0.0;
178  }
179  ninliers = 0;
180  for (unsigned int i = 0; i < npts; ++i) {
181  double resid = fabs(d[i]);
182  if (resid < t) {
183  inliers[i] = 1;
184  ++ninliers;
185  if (residual != nullptr) {
186  *residual += fabs(d[i]);
187  }
188  }
189  else {
190  inliers[i] = 0;
191  }
192  }
193 
194  if (ninliers > bestscore) // Largest set of inliers so far...
195  {
196  bestscore = ninliers; // Record data for this model
197  bestinliers = inliers;
198  bestM = M;
199  solutionFind = true;
200 
201  // Update estimate of N, the number of trials to ensure we pick,
202  // with probability p, a data set with no outliers.
203 
204  double fracinliers = static_cast<double>(ninliers) / static_cast<double>(npts);
205 
206  double pNoOutliers = 1 - pow(fracinliers, static_cast<int>(s));
207 
208  pNoOutliers = vpMath::maximum(eps, pNoOutliers); // Avoid division by -Inf
209  pNoOutliers = vpMath::minimum(1 - eps, pNoOutliers); // Avoid division by 0.
210  N = (log(1 - p) / log(pNoOutliers));
211  }
212 
213  // Safeguard against being stuck in this loop forever
214  ++trialcount;
215  }
216  if (trialcount > maxTrials) {
217  std::cout << "Warning: ransac reached the maximum number of " << maxTrials << " trials" << std::endl;
218  }
219  if (solutionFind == true) { // We got a solution
220  M = bestM;
221  inliers = bestinliers;
222  }
223  else {
224  std::cout << "Warning: ransac was unable to find a useful solution" << std::endl;
225  M = 0;
226  }
227 
228  if (residual != nullptr) {
229  if (ninliers > 0) {
230  *residual /= ninliers;
231  }
232  }
233 
234  delete[] ind;
235 
236  return true;
237 }
238 END_VISP_NAMESPACE
239 #endif
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ fatalError
Fatal error.
Definition: vpException.h:72
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:254
static Type minimum(const Type &a, const Type &b)
Definition: vpMath.h:262
This class is a generic implementation of the Ransac algorithm. It cannot be used alone.
Definition: vpRansac.h:67
static bool ransac(unsigned int npts, const vpColVector &x, unsigned int s, double t, vpColVector &model, vpColVector &inliers, int consensus=1000, double not_used=0.0, int maxNbumbersOfTrials=10000, double *residual=nullptr)
RANSAC - Robustly fits a model to data with the RANSAC algorithm.
Definition: vpRansac.h:107
Class for generating random numbers with uniform probability density.
Definition: vpUniRand.h:125