Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RANSACPreKnowledge.hh
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #ifndef __RANSACPREKNOWLEDGE_hh__
27 #define __RANSACPREKNOWLEDGE_hh__
28 
29 #include "RANSAC.hh"
30 
31 namespace BIAS {
32 
33  /** @class RANSACPreKnowledge
34  @ingroup g_mathalgo
35  @brief Extension of RANSAC algorithm: user-supplied guesses are evaluated
36  and refined using RANSAC criterions before actually starting the
37  RANSAC algorithm
38 
39  @author koeser 11/2003 */
40 
41  template <class SolutionType>
42  class /*BIASMathAlgo_EXPORT*/ RANSACPreKnowledge : public RANSAC<SolutionType>
43  {
44  public:
59 
60  RANSACPreKnowledge() : RANSAC<SolutionType>()
61  { Debug::NewDebugLevel("D_RANSAC_PRE_KNOWLEDGE"); };
62 
63  /** Construct a RANSAC object that takes samples of size sample_size,
64  returning at most max_solutions_per_sample solutions each time.
65  If the refine_solution flag is true, a routine has been supplied to
66  refine the initial fits before evaluation. */
67  RANSACPreKnowledge(unsigned int sample_size,
68  unsigned int max_solutions_per_sample = 1,
69  bool refine_solution = false):
70  RANSAC<SolutionType>(sample_size, max_solutions_per_sample,
71  refine_solution)
72  { Debug::NewDebugLevel("D_RANSAC_PRE_KNOWLEDGE"); };
73 
74  /** @brief default destructor does nothing */
75  virtual ~RANSACPreKnowledge() { };
76 
77  /** @brief add some guessed solutions which are tested by RANSAC later */
78  virtual inline void AddGoodGuesses(const std::vector<SolutionType> &Guesses) {
79  UserGuesses_.reserve(UserGuesses_.size() + Guesses.size());
80  for (typename std::vector<SolutionType>::const_iterator
81  it = Guesses.begin(); it!=Guesses.end(); it++)
82  UserGuesses_.push_back(*it);
83  }
84 
85  /** @brief clear all guesses */
86  virtual inline void ClearGuesses() {
87  UserGuesses_.clear();
88  }
89 
90  /** @brief checks UserGuesses and calls RANSAC::SolveMaster
91  @author koeser */
92  virtual inline int SolveMaster(double inlying_data_fraction,
93  SolutionType &solution,
94  std::vector<bool> &inliers);
95 
96  protected:
97  /// vector of guesses to be checked, which were manually supplied by user
98  std::vector<SolutionType> UserGuesses_;
99 
100  };
101 
102  template <class SolutionType> inline int
103  RANSACPreKnowledge<SolutionType>::SolveMaster(double inlying_data_fraction,
104  SolutionType &solution,
105  std::vector<bool> &inliers) {
106  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,
107  "RANSACPreKnowledge::SolveMaster() -----------------------------"
108  "-----------------\n");
109  BCDOUT(D_RANSAC_SAMPLE_QUALITY, "|||||||||||||||||||||\n\n");
110  // in order to do a real RANSAC run without high thresholds of
111  // pre-guesses, we clean up everything
112  _iBestSampleAcceptCount = -1;
113  _dBestSampleEvaluateScore = -1;
114  _iBestInlierAcceptCount = -1;
115  _dBestInlierEvaluateScore = -1;
116  _got_solution_flag = false;
117 
118  // offsets of samples for current solution
119  std::vector<unsigned int> which_samples;
120 
121  // vector indicating which ssamples are inliers
122  std::vector<bool> inlier_set(_uiDataSize, false);
123 
124  // number of inliers for current solution
125  int sample_accept_count;
126 
127  // score for sample set(resp. current solution), is set by EvaluateSolution
128  double sample_evaluate_score;
129 
130  // found a solution that good that we can finish, set by EvaluateSolution
131  bool ok_to_terminate_flag;
132 
133  // current solution is accepted by EvaluateSolution
134  bool good_flag;
135 
136  // number of inliers for current solution after refinement
137  int inlier_accept_count;
138 
139  // score for current solution after refinement
140  double inlier_evaluate_score;
141 
142  // indicates that the current is the best solution so far
143  bool best_so_far_flag;
144 
145  // if ok_to_terminate is set true, fast termination is enabled if
146  // termination_check_active_flag is true.
147  bool termination_check_active_flag = false;
148 
149  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,"checking "<<UserGuesses_.size()<<
150  " user guesses\n");
151  // run over all user guesses and evaluate using RANSAC criterions:
152  for (typename std::vector<SolutionType>::iterator
153  it = UserGuesses_.begin(); it!=UserGuesses_.end(); it++) {
154 
155 
156  ok_to_terminate_flag = false;
157  sample_evaluate_score = DBL_MAX;
158  good_flag = this->EvaluateSolution(*it, _got_solution_flag,
159  inlier_set, sample_accept_count,
160  sample_evaluate_score,
161  ok_to_terminate_flag);
162 
163  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,"PreGuess. "
164  <<" solution: "<<(*it)
165  <<" inliers: " <<sample_accept_count<<"/"<<_uiDataSize
166  <<" score: "<< sample_evaluate_score<<std::endl);
167 
168  inlier_accept_count=-1;
169  inlier_evaluate_score = 1e20;
170  if (good_flag && _bRefineSolution) {
171  // backup linear solution in case refining doesnt improve results
172  SolutionType samplesolution = *it;
173  bool ok_to_terminate_with_linear = ok_to_terminate_flag;
174 
175  which_samples.clear();
176  for (unsigned int i=0; i<_uiDataSize; i++)
177  if (inlier_set[i]) which_samples.push_back(i);
178  if (this->RefineSolution(which_samples, *it,
179  inlier_set)){
180  if (_got_solution_flag)
181  inlier_accept_count = _iBestInlierAcceptCount;
182  good_flag =
183  this->EvaluateSolution (*it, _got_solution_flag,
184  inlier_set, inlier_accept_count,
185  inlier_evaluate_score, ok_to_terminate_flag);
186  if (good_flag) {
187  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,
188  "RANSACPreKnowledge: minimal/refined "
189  <<sample_accept_count<<"/"
190  <<inlier_accept_count<<" "<<sample_evaluate_score<<"/"
191  <<inlier_evaluate_score<<std::endl);
192  }
193  } else {
194  // RefineSolution did not succeed, we do not use the solution
195  good_flag = false;
196  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,
197  "RANSACPreKnowledge: (note) refine_solution returned false"
198  <<std::endl);
199  }
200 
201  // refining didnt improve results, use linear solution:
202  if (!good_flag || (inlier_accept_count < sample_accept_count)) {
203  BCDOUT(D_RANSAC_SOLVE_MASTER, "RANSAC: (note) Linear solution"
204  <<" overrides refined !!! \n");
205  good_flag = true;
206  inlier_accept_count = sample_accept_count;
207  inlier_evaluate_score = sample_evaluate_score;
208  *it = samplesolution;
209  ok_to_terminate_flag = ok_to_terminate_with_linear;
210  }
211  } else { // if (good_flag && _bRefineSolution) {
212  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,
213  "RANSACPreKnowledge: (note) either good_flag=false or "
214  <<"_bRefineSolution=false"<<std::endl);
215  }
216 
217  // the criteria for deciding the best solution is the following -
218  // (a) if the accept_count is higher than the previous best, take it,
219  // (b) if the accept_count is equal to the previous best, and
220  // the evaluate score is smaller than the previous best, take it.
221  if (good_flag) {
222  BCDOUT(D_RANSAC_SAMPLE_QUALITY, "."<<std::flush);
223  best_so_far_flag = false;
224 
225  if (!_got_solution_flag) {
226  _got_solution_flag = true;
227  best_so_far_flag = true;
228  } else {
229  if (!_bRefineSolution) {
230  if (sample_accept_count > _iBestSampleAcceptCount ||
231  (sample_accept_count == _iBestSampleAcceptCount &&
232  sample_evaluate_score < _dBestSampleEvaluateScore))
233  best_so_far_flag = true;
234  } else {
235  if (inlier_accept_count > _iBestInlierAcceptCount ||
236  (inlier_accept_count == _iBestInlierAcceptCount &&
237  inlier_evaluate_score < _dBestInlierEvaluateScore))
238  best_so_far_flag = true;
239  }
240  }
241 
242  // save all the scores associated with this result.
243  // future evaluations will be tested against these accept scores.
244  if (best_so_far_flag) {
245  _iBestSampleAcceptCount = sample_accept_count;
246  _dBestSampleEvaluateScore =
247  (sample_evaluate_score<inlier_evaluate_score) ?
248  sample_evaluate_score : inlier_evaluate_score;
249  _iBestInlierAcceptCount = inlier_accept_count;
250  _dBestInlierEvaluateScore = inlier_evaluate_score;
251 
252  // save inliers and solution
253  inliers = inlier_set;
254  solution = *it;
255 
256  if (_bRefineSolution){
257  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,"RANSACPreKnowledge: PreGuess "
258  <<" is best so far. " << "Inliers/score "
259  <<_iBestInlierAcceptCount << "/"
260  <<_dBestInlierEvaluateScore<<": "<<solution<<std::endl);
261  } else {
262  BCDOUT(D_RANSAC_PRE_KNOWLEDGE, "RANSACPreKnowledge: PreGuess "
263  <<" is best so far. " << "Inliers/score "
264  << _iBestSampleAcceptCount << "/"
265  <<_dBestSampleEvaluateScore<<": "<<solution<<std::endl);
266  }
267 
268  if (ok_to_terminate_flag){
269  termination_check_active_flag = true;
270  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,
271  "RANSACPreKnowledge: termination_check_active_flag = true");
272  break; // do not evaluate the remaining solutions
273  }
274  } // if (best_so_far_flag) {
275  } else { // if (good_flag) {
276  BCDOUT(D_RANSAC_SAMPLE_QUALITY, "*"<<std::flush);
277  }
278  } // Guesses
279 
280  // check whether our guesses yielded a good solution ...
281  if (termination_check_active_flag) {
282  BCDOUT(D_RANSAC_SAMPLE_QUALITY, "P" << std::endl);
283  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,
284  "VERY GOOD preguess! Skipping RANSAC." << std::endl);
285  return 0;
286  }
287 
288  BCDOUT(D_RANSAC_PRE_KNOWLEDGE,
289  "RANSACPreKnowledge: No good preguess. Calling RANSAC without "
290  "preknowledge.");
291  // ok, we have no really good solution, call RANSAC algorithm:
292  return RANSAC<SolutionType>::SolveMaster(inlying_data_fraction,
293  solution, inliers);
294  }
295 
296 } // end namespace
297 
298 #endif // header defined
virtual void ClearGuesses()
clear all guesses
RANSACPreKnowledge(unsigned int sample_size, unsigned int max_solutions_per_sample=1, bool refine_solution=false)
Construct a RANSAC object that takes samples of size sample_size, returning at most max_solutions_per...
virtual int SolveMaster(double inlying_data_fraction, SolutionType &solution, std::vector< bool > &inliers)
Main computation function called by user.
Definition: RANSAC.hh:378
Extension of RANSAC algorithm: user-supplied guesses are evaluated and refined using RANSAC criterion...
virtual void AddGoodGuesses(const std::vector< SolutionType > &Guesses)
add some guessed solutions which are tested by RANSAC later
virtual int SolveMaster(double inlying_data_fraction, SolutionType &solution, std::vector< bool > &inliers)
checks UserGuesses and calls RANSAC::SolveMaster
virtual ~RANSACPreKnowledge()
default destructor does nothing
long int NewDebugLevel(const std::string &name)
creates a new debuglevel
Definition: Debug.hh:474
Generic abstract base class for RANSAC (RANdom SAmple Consensus) estimators.
Definition: RANSAC.hh:80
std::vector< SolutionType > UserGuesses_
vector of guesses to be checked, which were manually supplied by user