Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ransac.h
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
28 #ifndef _RANSAC_H_
29 #define _RANSAC_H_
30 
31 #include <set>
32 #include <vector>
33 #include <stdlib.h>
34 #include <cstring>
35 #include <math.h>
36 #include <ctime>
37 
38 #include "hugin_config.h"
39 #include <random>
40 #include <functional>
41 
42 //#include "ParameterEsitmator.h"
43 
44 //#define DEBUG_RANSAC
45 
75 class Ransac {
76 
77 public:
94  template<class Estimator, class S, class T>
95  static std::vector<const T*> compute(S & parameters,
96  std::vector<int> & inliers,
97  const Estimator & paramEstimator ,
98  const std::vector<T> &data,
99  double desiredProbabilityForNoOutliers,
100  double maximalOutlierPercentage);
101 
102 
125  template<class Estimator, class S, class T>
126  static std::vector<const T*> compute(S &parameters,
127  const Estimator & paramEstimator ,
128  const std::vector<T> &data);
129 
130 private:
131 
135  static unsigned int choose(unsigned int n, unsigned int m);
136 
137  template<class Estimator, class T>
138  static void computeAllChoices(const Estimator & paramEstimator,
139  const std::vector<T> &data,
140  int numForEstimate,
141  short *bestVotes, short *curVotes,
142  int &numVotesForBest, int startIndex,
143  int n, int k, int arrIndex, int *arr);
144 
145 
146  template<class Estimator, class T, class S>
147  static void estimate(const Estimator & paramEstimator, const std::vector<T> &data,
148  int numForEstimate,
149  short *bestVotes, short *curVotes,
150  int &numVotesForBest, int *arr);
151 
153  {
154  private:
155  int m_length;
156  public:
157  SubSetIndexComparator(int arrayLength) : m_length(arrayLength)
158  {}
159 
160  bool operator()(const int *arr1, const int *arr2) const
161  {
162  for(int i=0; i<m_length; i++)
163  if(arr1[i] < arr2[i])
164  return true;
165  return false;
166  }
167  };
168 
169 };
170 
171 
172 /*******************************RanSac Implementation*************************/
173 
174 template<class Estimator, class S, class T>
175 std::vector<const T *> Ransac::compute(S &parameters,
176  std::vector<int> & inliers,
177  const Estimator & paramEstimator,
178  const std::vector<T> &data,
179  double desiredProbabilityForNoOutliers,
180  double maximalOutlierPercentage)
181 {
182  unsigned int numDataObjects = (int) data.size();
183  unsigned int numForEstimate = paramEstimator.numForEstimate();
184  //there are less data objects than the minimum required for an exact fit, or
185  //all the data is outliers?
186  if(numDataObjects < numForEstimate || maximalOutlierPercentage>=1.0)
187  return std::vector<const T*>();
188 
189  std::vector<const T *> exactEstimateData;
190  std::vector<const T *> leastSquaresEstimateData;
191  S exactEstimateParameters;
192  int i, j, k, l, numVotesForBest, numVotesForCur, maxIndex, numTries;
193  short *bestVotes = new short[numDataObjects]; //one if data[i] agrees with the best model, otherwise zero
194  short *curVotes = new short[numDataObjects]; //one if data[i] agrees with the current model, otherwise zero
195  short *notChosen = new short[numDataObjects]; //not zero if data[i] is NOT chosen for computing the exact fit, otherwise zero
196  SubSetIndexComparator subSetIndexComparator(numForEstimate);
197  std::set<int *, SubSetIndexComparator > chosenSubSets(subSetIndexComparator);
198  int *curSubSetIndexes;
199  // double outlierPercentage = maximalOutlierPercentage;
200  double numerator = log(1.0-desiredProbabilityForNoOutliers);
201  double denominator = log(1- pow((double)(1.0-maximalOutlierPercentage), (double)(numForEstimate)));
202  int allTries = choose(numDataObjects,numForEstimate);
203 
204  //parameters.clear();
205 
206 
207  numVotesForBest = 0; //initalize with 0 so that the first computation which gives any type of fit will be set to best
208 
209  // intialize random generator
210  maxIndex = numDataObjects - 1;
211  std::mt19937 rng(static_cast<unsigned int>(std::time(0)));
212  std::uniform_int_distribution<> distribIndex(0, maxIndex);
213  auto randIndex=std::bind(distribIndex, rng);
214 
215 // srand((unsigned)time(NULL)); //seed random number generator
216  numTries = (int)(numerator/denominator + 0.5);
217 
218  //there are cases when the probablistic number of tries is greater than all possible sub-sets
219  numTries = numTries<allTries ? numTries : allTries;
220 
221  for(i=0; i<numTries; i++) {
222  //randomly select data for exact model fit ('numForEstimate' objects).
223  memset(notChosen,'1',numDataObjects*sizeof(short));
224  curSubSetIndexes = new int[numForEstimate];
225 
226  exactEstimateData.clear();
227 
228  maxIndex = numDataObjects-1;
229  for(l=0; l<(int)numForEstimate; l++) {
230  //selectedIndex is in [0,maxIndex]
231  unsigned int selectedIndex = randIndex();
232 // unsigned int selectedIndex = (unsigned int)(((float)rand()/(float)RAND_MAX)*maxIndex + 0.5);
233  for(j=-1,k=0; k<(int)numDataObjects && j<(int)selectedIndex; k++) {
234  if(notChosen[k])
235  j++;
236  }
237  k--;
238  exactEstimateData.push_back(&(data[k]));
239  notChosen[k] = 0;
240  maxIndex--;
241  }
242  //get the indexes of the chosen objects so we can check that this sub-set hasn't been
243  //chosen already
244  for(l=0, j=0; j<(int)numDataObjects; j++) {
245  if(!notChosen[j]) {
246  curSubSetIndexes[l] = j+1;
247  l++;
248  }
249  }
250 
251  //check that the sub set just chosen is unique
252  std::pair< std::set<int *, SubSetIndexComparator >::iterator, bool > res = chosenSubSets.insert(curSubSetIndexes);
253 
254  if(res.second == true) { //first time we chose this sub set
255  //use the selected data for an exact model parameter fit
256  if (!paramEstimator.estimate(exactEstimateData,exactEstimateParameters))
257  //selected data is a singular configuration (e.g. three colinear points for
258  //a circle fit)
259  continue;
260  //see how many agree on this estimate
261  numVotesForCur = 0;
262  memset(curVotes,'\0',numDataObjects*sizeof(short));
263  for(j=0; j<(int)numDataObjects; j++) {
264  if(paramEstimator.agree(exactEstimateParameters, data[j])) {
265  curVotes[j] = 1;
266  numVotesForCur++;
267  }
268  }
269  // debug output
270  #ifdef DEBUG_RANSAC
271  std::cerr << "RANSAC iter " << i << ": inliers: " << numVotesForCur << " parameters:";
272  for (int jj=0; jj < exactEstimateParameters.size(); jj++)
273  std::cerr << " " << exactEstimateParameters[jj];
274  std::cerr << std::endl;
275  #endif
276 
277  if(numVotesForCur > numVotesForBest) {
278  numVotesForBest = numVotesForCur;
279  memcpy(bestVotes,curVotes, numDataObjects*sizeof(short));
280  parameters = exactEstimateParameters;
281  }
282  /*
283  //update the estimate of outliers and the number of iterations we need
284  outlierPercentage = 1 - (double)numVotesForCur/(double)numDataObjects;
285  if(outlierPercentage < maximalOutlierPercentage) {
286  maximalOutlierPercentage = outlierPercentage;
287  denominator = log(1- pow((double)(1.0-maximalOutlierPercentage), (double)(numForEstimate)));
288  numTries = (int)(numerator/denominator + 0.5);
289  //there are cases when the probablistic number of tries is greater than all possible sub-sets
290  numTries = numTries<allTries ? numTries : allTries;
291  }
292  */
293  }
294  else { //this sub set already appeared, don't count this iteration
295  delete [] curSubSetIndexes;
296  i--;
297  }
298  }
299 
300  //release the memory
301  std::set<int *, SubSetIndexComparator >::iterator it = chosenSubSets.begin();
302  std::set<int *, SubSetIndexComparator >::iterator chosenSubSetsEnd = chosenSubSets.end();
303  while(it!=chosenSubSetsEnd) {
304  delete [] (*it);
305  it++;
306  }
307  chosenSubSets.clear();
308 
309  //compute the least squares estimate using the largest sub set
310  if(numVotesForBest > 0) {
311  for(j=0; j<(int)numDataObjects; j++) {
312  if(bestVotes[j]) {
313  leastSquaresEstimateData.push_back(&(data[j]));
314  inliers.push_back(j);
315  }
316  }
317  paramEstimator.leastSquaresEstimate(leastSquaresEstimateData,parameters);
318  }
319  delete [] bestVotes;
320  delete [] curVotes;
321  delete [] notChosen;
322 
323  return leastSquaresEstimateData;
324 }
325 /*****************************************************************************/
326 template<class Estimator, class S, class T>
327 std::vector<const T*> Ransac::compute(S &parameters,
328  const Estimator & paramEstimator,
329  const std::vector<T> &data)
330 {
331  unsigned int numForEstimate = paramEstimator.numForEstimate();
332  std::vector<T *> leastSquaresEstimateData;
333  int numDataObjects = data.size();
334  int numVotesForBest = 0;
335  int *arr = new int[numForEstimate];
336  short *curVotes = new short[numDataObjects]; //one if data[i] agrees with the current model, otherwise zero
337  short *bestVotes = new short[numDataObjects]; //one if data[i] agrees with the best model, otherwise zero
338 
339  //parameters.clear();
340 
341  //there are less data objects than the minimum required for an exact fit
342  if(numDataObjects < numForEstimate)
343  return 0;
344 
345  computeAllChoices(paramEstimator,data,numForEstimate,
346  bestVotes, curVotes, numVotesForBest, 0, data.size(), numForEstimate, 0, arr);
347 
348  //compute the least squares estimate using the largest sub set
349  if(numVotesForBest > 0) {
350  for(int j=0; j<numDataObjects; j++) {
351  if(bestVotes[j])
352  leastSquaresEstimateData.push_back(&(data[j]));
353  }
354  paramEstimator.leastSquaresEstimate(leastSquaresEstimateData,parameters);
355  }
356 
357  delete [] arr;
358  delete [] bestVotes;
359  delete [] curVotes;
360 
361  return leastSquaresEstimateData;
362 }
363 /*****************************************************************************/
364 template<class Estimator, class T>
365 void Ransac::computeAllChoices(const Estimator &paramEstimator, const std::vector<T> &data,
366  int numForEstimate,short *bestVotes, short *curVotes,
367  int &numVotesForBest, int startIndex, int n, int k,
368  int arrIndex, int *arr)
369 {
370  //we have a new choice of indexes
371  if(k==0) {
372  estimate(paramEstimator, data, numForEstimate, bestVotes, curVotes, numVotesForBest, arr);
373  return;
374  }
375 
376  //continue to recursivly generate the choice of indexes
377  int endIndex = n-k;
378  for(int i=startIndex; i<=endIndex; i++) {
379  arr[arrIndex] = i;
380  computeAllChoices(paramEstimator, data, numForEstimate, bestVotes, curVotes, numVotesForBest,
381  i+1, n, k-1, arrIndex+1, arr);
382  }
383 
384 }
385 /*****************************************************************************/
386 template<class Estimator, class T, class S>
387 void Ransac::estimate(const Estimator & paramEstimator, const std::vector<T> &data,
388  int numForEstimate, short *bestVotes, short *curVotes,
389  int &numVotesForBest, int *arr)
390 {
391  std::vector<T *> exactEstimateData;
392  std::vector<S> exactEstimateParameters;
393  int numDataObjects;
394  int numVotesForCur;//initalize with -1 so that the first computation will be set to best
395  int j;
396 
397  numDataObjects = data.size();
398  memset(curVotes,'\0',numDataObjects*sizeof(short));
399  numVotesForCur=0;
400 
401  for(j=0; j<numForEstimate; j++)
402  exactEstimateData.push_back(&(data[arr[j]]));
403  paramEstimator.estimate(exactEstimateData,exactEstimateParameters);
404  //singular data configuration
405  if(exactEstimateParameters.empty())
406  return;
407 
408  for(j=0; j<numDataObjects; j++) {
409  if(paramEstimator.agree(exactEstimateParameters, data[j])) {
410  curVotes[j] = 1;
411  numVotesForCur++;
412  }
413  }
414  if(numVotesForCur > numVotesForBest) {
415  numVotesForBest = numVotesForCur;
416  memcpy(bestVotes,curVotes, numDataObjects*sizeof(short));
417  }
418 }
419 /*****************************************************************************/
420 inline unsigned int Ransac::choose(unsigned int n, unsigned int m)
421 {
422  unsigned int denominatorEnd, numeratorStart, numerator,denominator;
423  if((n-m) > m) {
424  numeratorStart = n-m+1;
425  denominatorEnd = m;
426  }
427  else {
428  numeratorStart = m+1;
429  denominatorEnd = n-m;
430  }
431 
432  unsigned int i;
433  for(i=numeratorStart, numerator=1; i<=n; i++)
434  numerator*=i;
435  for(i=1, denominator=1; i<=denominatorEnd; i++)
436  denominator*=i;
437  return numerator/denominator;
438 
439 }
440 
441 
442 #endif //_RANSAC_H_
static std::vector< const T * > compute(S &parameters, std::vector< int > &inliers, const Estimator &paramEstimator, const std::vector< T > &data, double desiredProbabilityForNoOutliers, double maximalOutlierPercentage)
Estimate the model parameters using the RanSac framework.
Definition: ransac.h:175
SubSetIndexComparator(int arrayLength)
Definition: ransac.h:157
float pow(float a, double b)
Definition: utils.h:181
static void estimate(const Estimator &paramEstimator, const std::vector< T > &data, int numForEstimate, short *bestVotes, short *curVotes, int &numVotesForBest, int *arr)
Definition: ransac.h:387
bool operator()(const int *arr1, const int *arr2) const
Definition: ransac.h:160
static void computeAllChoices(const Estimator &paramEstimator, const std::vector< T > &data, int numForEstimate, short *bestVotes, short *curVotes, int &numVotesForBest, int startIndex, int n, int k, int arrIndex, int *arr)
Definition: ransac.h:365
vigra::RGBValue< T, RIDX, GIDX, BIDX > log(vigra::RGBValue< T, RIDX, GIDX, BIDX > const &v)
component-wise logarithm
Definition: utils.h:209
static unsigned int choose(unsigned int n, unsigned int m)
Compute n choose m [ n!/(m!*(n-m)!)].
Definition: ransac.h:420
This class implements the Random Sample Consensus (RanSac) framework, a framework for robust paramete...
Definition: ransac.h:75
options wxIntPtr wxIntPtr sortData std::vector< PanoInfo > * data