Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
COSAC.hh
1 /* This file is part of the BIAS library (Basic ImageAlgorithmS).
2 
3  Copyright (C) 2003, 2004 (see file CONTACTS for details)
4  Multimediale Systeme der Informationsverarbeitung
5  Institut fuer Informatik
6  Christian-Albrechts-Universitaet Kiel
7 
8  BIAS is free software; you can redistribute it and/or modify
9  it under the terms of the GNU Lesser General Public License as published by
10  the Free Software Foundation; either version 2.1 of the License, or
11  (at your option) any later version.
12 
13  BIAS is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU Lesser General Public License for more details.
17 
18  You should have received a copy of the GNU Lesser General Public License
19  along with BIAS; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
21 #ifndef __COSAC_hh__
22 #define __COSAC_hh__
23 
24 #include <bias_config.h>
25 #include <Base/Common/BIASpragmaStart.hh>
26 
27 #include <Base/Debug/Debug.hh>
28 #include <Base/Debug/Error.hh>
29 #include <Base/Debug/Exception.hh>
30 #include <Base/Math/BinomialCoefficient.hh>
31 #include <MathAlgo/RANSACEvaluatorInterface.hh>
32 
33 #include <vector>
34 #include <list>
35 #include <limits>
36 #include <cmath>
37 
38 #ifndef NAN
39 # define NAN sqrt(-1.0)
40 #endif
41 
42 #define COSAC_TOO_MANY_SOLUTIONS -5
43 #define COSAC_NOT_ENOUGH_MEASUREMENTS -4
44 #define COSAC_NO_SOLUTION_LEFT -3
45 #define COSAC_INVALID_ARGUMENTS -2
46 #define COSAC_NO_SOLUTIONS -1
47 #define COSAC_OK 0
48 #define COSAC_NOT_ENOUGH_INLIERS 1
49 #define COSAC_SCORE_TOO_BIG 2
50 
51 namespace BIAS {
52 
53  /** @class COSAC
54  @brief Complete Sampling Consesus
55 
56  Samples the space of possible solutions completely. The algorithm
57  (complete sampling and evaluation) is decoupled from the problem
58  (for example HMatrix estimation) using a common interface class, the
59  RANSACEvaluatorInterace. To use this class it is therefore necessary to
60  derive from RANSACEvaluatorInterface and overload the functions:
61 
62  bool IsInlier(const SolutionType& solution,
63  const unsigned data_index,
64  double& score) = 0;
65 
66  int GetSampleSolutions(const std::vector<unsigned> &which_samples,
67  std::vector<SolutionType> &solutions)= 0;
68 
69  bool RefineSolution(const std::vector<bool>& inliers,
70  SolutionType& solution) = 0;
71 
72  Afterwards instantiate COSAC with a pointer to the sibling of
73  RANSACEvaluatorInterface as argment to the constructor and call
74 
75  SolveMaster()
76 
77  @author woelk 01/2010 (c) www.vision-n.de */
78  template <class SolutionType>
79  class COSAC : public Debug
80  {
81  public:
82  /// c'tor
84 
85  /// d'tor
86  virtual ~COSAC() {};
87 
88  /** @returns COSAC_OK when a solution could be found,
89  a positive number when a solution could be found which did not met the
90  minimum qulaity criteria (i.e. min_num_inliers and maximum score)
91  and a negative number when absolutly no solution could be found */
92  int SolveMaster(const double inlying_data_fraction, const double max_score,
93  SolutionType &solution, std::vector<bool> &inliers,
94  unsigned &num_inliers, double& score);
95 
96  inline void SetRefineSolutions(const unsigned refine_solutions)
97  { _bRefineSolutions = refine_solutions; }
98 
99  protected:
100  /// the helper class for solution computation and sample evaluation
102  /// the number of samples needed by GetSampleSolutions
103  unsigned _uiSampleSize;
104  /// the number of data for evaluation
105  unsigned _uiDataSize;
106  /// should the solutions be refined?
108 
109  struct SolStruct {
110  SolutionType solution;
111  /// evaluation of the solution has taken place up to eval_index
112  unsigned eval_index;
113  // the accumulated score of the so-far evaluated datas
114  double score;
115  // the number of inliers of the so-far evaluated datas
116  unsigned num_inliers;
117  /** inlier indicator for the data in the order given by _EvaluationOrder
118  i.e. inliers[i] indicates if data[i] is an inlier*/
119  std::vector<bool> inliers;
120  /// has a refined version of this solution already been added?
121  bool refined;
122  };
123 
124  /// all solutions
125  std::list<SolStruct> _Solutions;
126 
127  /** returns the number of generated solution */
128  int GenerateSolutions_(const unsigned sample_size,
129  const unsigned data_size);
130 
131  /** returns the number of succesfully refined solutions */
132  int GenerateRefinedSolutions_(const unsigned data_size);
133 
134  /** evaluates the solutions */
135  void EvaluateSolutions_(const unsigned data_size);
136 
137  /** Returns the next combination of samples from which a solution can be
138  computed. Returns false when all combinations have been returned.
139  The argument vector which_samples must be empty on initial call */
140  bool GetNextCombination_(const unsigned sample_size,
141  const unsigned data_size,
142  std::vector<unsigned> &which_samples);
143 
144  int GetSolution_(const unsigned min_num_inliers, const double max_score,
145  SolutionType& solution, std::vector<bool>& inliers,
146  unsigned& num_inliers, double & score) const;
147 
148  bool IsInlier_(typename std::list<SolStruct>::iterator solution,
149  const unsigned eval_index, double& score);
150 
151  const struct SolStruct *
152  GetSolutionMaxInliers_(const unsigned min_num_inliers,
153  const double max_score) const
154  {
155  SolStruct const *best = NULL;
156  unsigned max_inliers = 0;
157  double min_score = std::numeric_limits<double>::max();
158  typename std::list<SolStruct>::const_iterator it;
159  for (it=_Solutions.begin(); it!=_Solutions.end();it++){
160  BCDOUT(D_COSAC_GetSolution, "solution: "<<it->solution<<std::endl);
161  if (it->num_inliers>max_inliers){
162  max_inliers = it->num_inliers;
163  min_score = it->score;
164  BCDOUT(D_COSAC_GetSolution, " is best (num inliers "<<max_inliers
165  <<", score "<<min_score<<")"<<std::endl);
166  best = &(*it);
167  } else {
168  BCDOUT(D_COSAC_GetSolution, " (num inliers "<<max_inliers
169  <<", score "<<min_score<<")"<<std::endl);
170  }
171  if (it->num_inliers==max_inliers && it->score < min_score){
172  min_score = it->score;
173  best = &(*it);
174  BCDOUT(D_COSAC_GetSolution, " new best score "<<min_score
175  <<std::endl);
176  }
177  }
178 
179  return best;
180  }
181 
182  const struct SolStruct *
183  GetSolutionMinScore_(const unsigned min_num_inliers,
184  const double max_score) const
185  {
186  SolStruct const *best = NULL;
187  double min_score = std::numeric_limits<double>::max();
188  typename std::list<SolStruct>::const_iterator it;
189  for (it=_Solutions.begin(); it!=_Solutions.end(); it++){
190  BCDOUT(D_COSAC_GetSolution, "solution: "<<it->solution
191  <<std::endl);
192  if (it->score < min_score){
193  min_score = it->score;
194  best = &(*it);
195  BCDOUT(D_COSAC_GetSolution, " is best (min_score "<<min_score
196  <<" / num inliers: "<<it->num_inliers<<" )"<<std::endl);
197  } else {
198  BCDOUT(D_COSAC_GetSolution, " score: "<<it->score
199  <<" / num inliers: "<<it->num_inliers<<std::endl);
200  }
201  }
202  return best;
203  }
204 
205  }; // class
206 
207  ////////////////////////////////////////////////////////////////////////////
208  // implementation
209  ///////////////////////////////////////////////////////////////////////////
210 
211  template <class SolutionType>
214  : RANSACEvaluator_(shi), _uiSampleSize(0), _uiDataSize(0),
215  _bRefineSolutions(true), _Solutions()
216  {
217  if (!RANSACEvaluator_){
218  BEXCEPTION("COSAC::COSAC(): Invalid (null) argument.");
219  }
220  _uiSampleSize = RANSACEvaluator_->GetMinNumSamplesForSolutionComputation();
221 
222  NewDebugLevel("D_COSAC_Inlier");
223  NewDebugLevel("D_COSAC_GetSolution");
224  NewDebugLevel("D_COSAC_SolveMaster");
225  NewDebugLevel("D_COSAC_Evaluate");
226  }
227 
228 
229  template <class SolutionType>
231  SolveMaster(const double inlying_data_fraction, const double max_score,
232  SolutionType &solution, std::vector<bool> &inliers,
233  unsigned &num_inliers, double& score)
234  {
235  _uiDataSize = RANSACEvaluator_->GetNumMeasurements();
236  if (_uiDataSize < _uiSampleSize){
237  return COSAC_NOT_ENOUGH_MEASUREMENTS;
238  }
239  _Solutions.clear();
240 
241  try {
242  unsigned num_solutions =
243  BinomialCoefficient::Compute(_uiDataSize, _uiSampleSize);
244  const unsigned max_num_solutions = 5000;
245  if (num_solutions>max_num_solutions){
246  BIASERR("COSAC::SolveMaster(): The number of solutions is very big "
247  <<"(>"
248  <<max_num_solutions<<") and evaluation of every solution "
249  <<"might take a very long time. The usage of "
250  <<"PreemptiveRANSAC instead of COSAC is suggested for this"
251  <<" case.");
252  return COSAC_TOO_MANY_SOLUTIONS;
253  }
254  } catch (BaseException &ex){
255  BIASERR("COSAC::SolveMaster(): The number of solutions is very big (>"
256  <<std::numeric_limits<unsigned>::max()
257  <<") and evaluation of every solution "
258  <<"might take a very long time. The usage of "
259  <<"PreemptiveRANSAC instead of COSAC is suggested for this"
260  <<" case."<<ex.What());
261  return COSAC_TOO_MANY_SOLUTIONS;
262  }
263 
264  if (inlying_data_fraction<0.0 || inlying_data_fraction>1.0){
265  return COSAC_INVALID_ARGUMENTS;
266  }
267  GenerateSolutions_(_uiSampleSize, _uiDataSize);
268  if (_Solutions.empty()){
269  return COSAC_NO_SOLUTIONS;
270  }
271 
272  EvaluateSolutions_(_uiDataSize);
273 
274  if (_bRefineSolutions){
275  GenerateRefinedSolutions_(_uiDataSize);
276  if (_Solutions.empty()){
277  return COSAC_NO_SOLUTIONS;
278  }
279 
280  EvaluateSolutions_(_uiDataSize);
281  }
282 
283  const unsigned min_num_inliers =
284  (unsigned)floor(inlying_data_fraction*_uiDataSize);
285  BIASASSERT(min_num_inliers<=_uiDataSize);
286  int res = GetSolution_(min_num_inliers, max_score,
287  solution, inliers, num_inliers, score);
288 
289  return res;
290  }
291 
292 
293  template <class SolutionType>
295  GenerateSolutions_(const unsigned sample_size, const unsigned data_size)
296  {
297  unsigned num_solutions = 0;
298  std::vector<unsigned> which_samples;
299  std::vector<SolutionType> solutions;
300  SolStruct st;
301  st.refined = false;
302  st.eval_index = 0;
303  st.score = 0.0;
304  st.num_inliers = 0;
305  st.inliers.resize(data_size);
306  while (GetNextCombination_(sample_size, data_size, which_samples)){
307  int res = RANSACEvaluator_->GetSampleSolutions(which_samples, solutions);
308  if (res == 0){
309  for (unsigned sol_idx=0; sol_idx<solutions.size(); sol_idx++){
310  st.solution = solutions[sol_idx];
311  BIASASSERT(st.inliers.size()==data_size);
312  _Solutions.push_back(st);
313  num_solutions++;
314  }
315  }
316  }
317  return num_solutions;
318  }
319 
320 
321  template <class SolutionType>
323  GenerateRefinedSolutions_(const unsigned data_size)
324  {
325  typename std::list<SolStruct>::iterator it;
326  SolStruct st;
327  st.refined = true;
328  st.eval_index = 0;
329  st.score = 0.0;
330  st.num_inliers = 0;
331  st.inliers.resize(data_size);
332  unsigned num_refined = 0;
333  for (it = _Solutions.begin(); it !=_Solutions.end(); it++){
334  st.solution = it->solution;
335  bool res = RANSACEvaluator_->RefineSolution(it->inliers, st.solution);
336  if (res){
337  BIASASSERT(st.inliers.size()==data_size);
338  _Solutions.push_back(st);
339  num_refined++;
340  }
341  }
342  return num_refined;
343  }
344 
345 
346  template <class SolutionType>
348  EvaluateSolutions_(const unsigned data_size)
349  {
350  typename std::list<SolStruct>::iterator it;
351  double score = 0.0;
352  for (unsigned data_idx=0; data_idx<data_size; data_idx++){
353  for (it=_Solutions.begin(); it!=_Solutions.end(); it++){
354  IsInlier_(it, data_idx, score);
355  }
356 // bool rejet_solutions =
357 // ((data_idx%_uiEvaluationBlockSize)==0) && (data_idx!=0);
358 // if (reject_solutions){
359 // RejectSolutions_(data);
360 // }
361  }
362  }
363 
364 
365 // template <class SolutionType>
366 // int COSAC<SolutionType>::
367 // RejectSolutions_(const unsigned eval_index)
368 // {
369 // // always keep the better half
370 // std::vector<double> scores;
371 // typename std::list<SolStruct>::iterator it;
372 // for (it=_Solutions.begin(); it!=_Solutions.end(); it++){
373 // if (it->eval_index>eval_index+1) { continue; }
374 // scores.push_back(it->score);
375 // }
376 // if (scores.empty()) {
377 // BCDOUT(D_COSAC_Evaluate, "no solutions left to evaluate\n");
378 // return 0;
379 // }
380 // Median1D<double> med;
381 // med.Compute(scores);
382 // const double thresh = med.GetMedian();
383 // BCDOUT(D_COSAC_Evaluate, "score threshold = "<<thresh<<std::endl);
384 // int num_rejected=0;
385 // for (it=_Solutions.begin(); it!=_Solutions.end();){
386 // if (it->score > thresh){
387 // it = _Solutions.erase(it);
388 // BCDOUT(D_COSAC_Evaluate, "*");
389 // num_rejected++;
390 // } else {
391 // it++;
392 // BCDOUT(D_COSAC_Evaluate, ".");
393 // }
394 // }
395 // BCDOUT(D_COSAC_Evaluate, std::endl);
396 // BCDOUT(D_COSAC_Evaluate, _Solutions.size()<<" solutions remaining\n");
397 
398 // return num_rejected;
399 // }
400 
401 
402  template <class SolutionType>
404  IsInlier_(typename std::list<SolStruct>::iterator solution,
405  const unsigned eval_index, double& score)
406  {
407  BCDOUT(D_COSAC_Inlier, "eval_index: "<<eval_index<<" ");
408  BCDOUT(D_COSAC_Inlier, "solution->eval_index: "<<solution->eval_index);
409  if (solution->eval_index<=eval_index){
410  // cannot leave indices unevaluated
411  if (solution->inliers.size()<=eval_index){
412  std::cout << "eval_index: "<<eval_index<<"\ninliers.size(): "
413  <<solution->inliers.size()<<std::endl;
414  }
415  BIASASSERT(solution->eval_index==eval_index);
416  BIASASSERT(solution->inliers.size()>eval_index);
417  BCDOUT(D_COSAC_Inlier, " (new score) "<<std::endl);
418  solution->inliers[eval_index] =
419  RANSACEvaluator_->IsInlier(solution->solution, eval_index, score);
420  solution->score += score;
421  if (solution->inliers[eval_index]){
422  solution->num_inliers++;
423  }
424  solution->eval_index++;
425  } else {
426  BCDOUT(D_COSAC_Inlier, " (already scored) "<<std::endl);
427  score = NAN;
428  }
429  BCDOUT(D_COSAC_Inlier, "inlier: "<<std::boolalpha
430  <<solution->inliers[eval_index]<<std::endl);
431  return solution->inliers[eval_index];
432  }
433 
434 
435  template <class SolutionType>
437  GetSolution_(const unsigned min_num_inliers, const double max_score,
438  SolutionType& solution, std::vector<bool>& inliers,
439  unsigned& num_inliers, double & score) const
440  {
441  if (_Solutions.empty()) {
442  return COSAC_NO_SOLUTION_LEFT;
443  }
444 
445  const SolStruct *best_sol =
446  GetSolutionMinScore_(min_num_inliers, max_score);
447  //GetSolutionMaxInliers_(min_num_inliers, max_score);
448 
449  if (best_sol){
450  score = best_sol->score;
451  num_inliers = best_sol->num_inliers;
452  solution = best_sol->solution;
453  BCDOUT(D_COSAC_GetSolution, "\nbest solution is: "
454  <<solution<<" score: "<<score<<" / num inliers: "
455  <<num_inliers<<std::endl);
456  inliers = best_sol->inliers;
457  bool enough_inliers = (best_sol->num_inliers >= min_num_inliers);
458  bool score_smaller_than_max_score = (best_sol->score <= max_score);
459  if (enough_inliers && score_smaller_than_max_score){
460  BCDOUT(D_COSAC_GetSolution, "num_inliers: "<<num_inliers
461  <<"\nscore: "<<score<<"\n");
462  return COSAC_OK;
463  } else {
464  int res = 0;
465  BCDOUT(D_COSAC_GetSolution, "minimum quality criteria not met "
466  "(max_score: "<<max_score<<" / min inliers "<<min_num_inliers
467  <<")\n");
468  if (!enough_inliers){
469  BCDOUT(D_COSAC_GetSolution, "not enough inliers "
470  <<"(found: "<<best_sol->num_inliers<<" / expected: "
471  <<min_num_inliers<<")\n");
472  res = res | COSAC_NOT_ENOUGH_INLIERS;
473  }
474  if (!score_smaller_than_max_score){
475  BCDOUT(D_COSAC_GetSolution, "score too big "
476  <<"(found: "<<best_sol->score<<" / expected: "
477  <<max_score<<")\n");
478  res = res | COSAC_SCORE_TOO_BIG;
479  }
480  return res;
481  }
482  } else {
483  BIASERR("no best solution returned");
484  BIASABORT;
485  }
486 
487  return COSAC_NO_SOLUTION_LEFT;
488  }
489 
490 
491  template <class SolutionType>
493  GetNextCombination_(const unsigned sample_size,
494  const unsigned data_size,
495  std::vector<unsigned> &which_samples)
496  {
497  if (data_size<sample_size) {
498  return false;
499  }
500  if (sample_size<=0) { return false; }
501  if (which_samples.empty()){
502  for (unsigned i=0; i<sample_size; i++){
503  which_samples.push_back(i);
504  }
505  return true;
506  }
507  BIASASSERT(which_samples.size()==sample_size);
508 
509  for (int i=0; i<(int)sample_size; i++){
510  int index = sample_size-i-1;
511  if (which_samples[index]+1 < data_size-i){
512  which_samples[index]++;
513  BIASASSERT(which_samples[index]<data_size);
514  for (int k=index+1; k<(int)sample_size; k++){
515  which_samples[k] = which_samples[index]+k-index;
516  BIASASSERT(which_samples[k]<data_size);
517  }
518  return true;
519  }
520  }
521  return false;
522  }
523 
524 
525 } //namespace
526 
527 #endif // __COSAC_hh__
528 
Interface for computation of solutions and evaluation of measurements.
SolutionType solution
Definition: COSAC.hh:110
static long long unsigned Compute(const unsigned n, const unsigned k)
Computation of the binomial coefficient &quot;n over k&quot; The function throws an exception when overflow occ...
std::list< SolStruct > _Solutions
all solutions
Definition: COSAC.hh:125
bool refined
has a refined version of this solution already been added?
Definition: COSAC.hh:121
void EvaluateSolutions_(const unsigned data_size)
evaluates the solutions
Definition: COSAC.hh:348
Complete Sampling Consesus.
Definition: COSAC.hh:79
bool GetNextCombination_(const unsigned sample_size, const unsigned data_size, std::vector< unsigned > &which_samples)
Returns the next combination of samples from which a solution can be computed.
Definition: COSAC.hh:493
int SolveMaster(const double inlying_data_fraction, const double max_score, SolutionType &solution, std::vector< bool > &inliers, unsigned &num_inliers, double &score)
Definition: COSAC.hh:231
bool IsInlier_(typename std::list< SolStruct >::iterator solution, const unsigned eval_index, double &score)
Definition: COSAC.hh:404
std::vector< bool > inliers
inlier indicator for the data in the order given by _EvaluationOrder i.e.
Definition: COSAC.hh:119
unsigned num_inliers
Definition: COSAC.hh:116
COSAC(RANSACEvaluatorInterface< SolutionType > *shi)
c&#39;tor
Definition: COSAC.hh:213
struct SolStruct * GetSolutionMinScore_(const unsigned min_num_inliers, const double max_score) const
Definition: COSAC.hh:183
unsigned _uiDataSize
the number of data for evaluation
Definition: COSAC.hh:105
unsigned eval_index
evaluation of the solution has taken place up to eval_index
Definition: COSAC.hh:112
bool _bRefineSolutions
should the solutions be refined?
Definition: COSAC.hh:107
long int NewDebugLevel(const std::string &name)
creates a new debuglevel
Definition: Debug.hh:474
struct SolStruct * GetSolutionMaxInliers_(const unsigned min_num_inliers, const double max_score) const
Definition: COSAC.hh:152
void SetRefineSolutions(const unsigned refine_solutions)
Definition: COSAC.hh:96
RANSACEvaluatorInterface< SolutionType > * RANSACEvaluator_
the helper class for solution computation and sample evaluation
Definition: COSAC.hh:101
int GenerateSolutions_(const unsigned sample_size, const unsigned data_size)
returns the number of generated solution
Definition: COSAC.hh:295
virtual ~COSAC()
d&#39;tor
Definition: COSAC.hh:86
int GenerateRefinedSolutions_(const unsigned data_size)
returns the number of succesfully refined solutions
Definition: COSAC.hh:323
int GetSolution_(const unsigned min_num_inliers, const double max_score, SolutionType &solution, std::vector< bool > &inliers, unsigned &num_inliers, double &score) const
Definition: COSAC.hh:437
unsigned _uiSampleSize
the number of samples needed by GetSampleSolutions
Definition: COSAC.hh:103
generic exception
Definition: Exception.hh:77
virtual const std::string & What() const
Definition: Exception.hh:95