Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
MSAC.hh
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003, 2004 (see file CONTACTS 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 #ifndef __MSAC_hh__
26 #define __MSAC_hh__
27 
28 #include <Base/Common/BIASpragmaStart.hh>
29 
30 #include <Base/Debug/Debug.hh>
31 #include <Base/Math/Random.hh>
32 
33 #include <vector>
34 #include <iterator>
35 #include <limits>
36 
37 namespace BIAS {
38 
39 #define D_MSAC_SOLVEM 0x00000001
40 #define D_MSAC_SAMPLES 0x00000002
41 #define D_MSAC_INIT 0x00000004
42 
43 
44 /** @class MSAC
45  @ingroup g_mathalgo
46  @brief this class does something, but WHAT? Is it the M-Estimator SAmple Consensus ??
47  @author MIP
48 */
49 
50  template <class SolutionType>
51  class BIASMathAlgo_EXPORT MSAC : public virtual BIAS::Debug
52  {
53  public:
54  MSAC();
55  virtual ~MSAC();
56 
57  // sets terminate_score and solution_count automatically
58  int Init(int data_size);
59 
60  int Init(int data_size, double terminate_score, int solution_count);
61 
62  int SolveMaster(SolutionType &solution,
63  std::vector<bool> &inliers);
64 
65  virtual
66  int GetSampleSolution(std::vector<unsigned int> &which_samples,
67  SolutionType &solutions);
68 
69  virtual
70  bool EvaluateSolution(const SolutionType& solution,
71  std::vector<bool>& inlier, int& num_inliers,
72  double& evaluate_score);
73 
74  virtual
75  bool RefineSolution(std::vector<unsigned int>& which_samples,
76  SolutionType& solution,std::vector<bool>& new_inliers);
77 
78  virtual
79  bool GenerateSamples(int sample_index,
80  std::vector<unsigned int>& which_samples);
81 
82 
83  protected:
86  double _MSACSigmaFac;
89  int _iDataSize; // number of data
90  int _iSolutionCount; // number of solutions to evaluate
91  int _iSampleSize; // size of minimum data set needed to calc. sol
93 
94  bool _GenerateSamplesRandom(int sample_index,
95  std::vector<unsigned int>& which_samples);
96 
97  double _CalculateTerminateScore(double sigma,
98  double expected_inlier_fraction);
99 
100  int _CalculateSampleCount(double expected_inlier_fraction);
101 
102  }; // class
103 
104 
105 
106 
107 
108  //////////////////////////////////////////////////////////////////////////
109  // implementation
110  //////////////////////////////////////////////////////////////////////////
111 
112  template <class SolutionType>
114  : BIAS::Debug()
115  {
116  _MSACRefineSolution=false;
118  _MSACSigmaFac=1.96;
119  _iDataSize=0;
120  _iSolutionCount=1;
121  _iSampleSize=1;
122  _dTerminateScore=0.0;
123  _dExpectedSigma=0.0;
125  }
126 
127  template <class SolutionType>
129  {}
130 
131 
132  template <class SolutionType>
133  int MSAC<SolutionType>::Init(int data_size)
134  {
135  _iDataSize=data_size;
136  _dTerminateScore=_CalculateTerminateScore(_dExpectedSigma,
137  _dExpectedInlierFraction);
138  // BIASERR("fast termination disabled"); _dTerminateScore=0.0;
139  _iSolutionCount=_CalculateSampleCount(_dExpectedInlierFraction);
140 
141  return Init(data_size, _dTerminateScore, _iSolutionCount);
142  }
143 
144  template <class SolutionType>
145  int MSAC<SolutionType>::Init(int data_size, double terminate_score,
146  int solution_count)
147  {
148  _iDataSize=data_size;
149  _dTerminateScore=terminate_score;
150  //cout << "MSAC: aborting below score: "<<_dTerminateScore<<std::endl;
151  _iSolutionCount=solution_count;
152  //cout <<"MSAC: doing at most "<<_iSolutionCount<<" runs"<<std::endl;
153  BIASCDOUT(D_MSAC_INIT, _iDataSize<<" data points whereof "
154  <<_dExpectedInlierFraction*data_size<<" are expected to be "
155  <<"inliers.\n Inliers are assumed normal distributed with sigma "
156  <<_dExpectedSigma<<".\n Using confidence in solution of "
157  <<_MSACConfidenceThresh
158  <<" % with sample set size "<<_iSampleSize<<" leads to at most "
159  <<_iSolutionCount
160  <<" solutions to be evaluated.\n MSAC will abort on score below "
161  <<_dTerminateScore<<"\n");
162  BIASASSERT(_iDataSize>=_iSampleSize);
163  return 0;
164  }
165 
166 
167  template <class SolutionType>
168  int MSAC<SolutionType>::SolveMaster(SolutionType& solution,
169  std::vector<bool>& inliers)
170  {
171  SolutionType best_sol, act_sol;
172  std::vector<unsigned> which_samples;
173  std::vector<bool> tmp(_iDataSize, false);
174  std::vector<std::vector<bool> > inliervec(_iSolutionCount, tmp);
175  double act_score, best_score=numeric_limits<double>::max();
176  int sample_index, best_index=-1, act_num_inlier, best_num_inlier=0;
177 
178  which_samples.resize(_iSampleSize);
179  inliers.resize(_iSolutionCount);
180 
181  for (sample_index = 0; sample_index < _iSolutionCount; sample_index++){
182  //cout << "." << flush;
183  //for (sample_index = 0; sample_index < 1; sample_index++){
184  if (GenerateSamples(sample_index, which_samples)){
185  if (!GetSampleSolution(which_samples, act_sol)){
186  BIASERR("GetSampleSolution failed");
187  BIASASSERT(false);
188  }
189  if (!EvaluateSolution(act_sol, inliervec[sample_index],
190  act_num_inlier, act_score)){
191  BIASERR("Evaluate Solution failed");
192  BIASASSERT(false);
193  }
194  BIASCDOUT(D_MSAC_SOLVEM, setw(3)<<sample_index<<"th solution: "
195  <<act_sol<<" with score "<<act_score<<" and "<<act_num_inlier
196  <<" inliers\n");
197 
198  if (_MSACRefineSolution && true){
199  which_samples.clear();
200  for (int i=0; i<_iDataSize; i++){
201  if (inliervec[sample_index][i]){
202  which_samples.push_back(i);
203  }
204  }
205 
206  if (!RefineSolution(which_samples, act_sol,
207  inliervec[sample_index])){
208  BIASERR("RefineSolution returned false");
209  BIASASSERT(false);
210  }
211  if (!EvaluateSolution(act_sol, inliervec[sample_index],
212  act_num_inlier, act_score)){
213  BIASERR("Evaluate Solution failed");
214  BIASASSERT(false);
215  }
216  BIASCDOUT(D_MSAC_SOLVEM, setw(3)<<sample_index
217  <<"th refined solution: "
218  <<act_sol<<" with score "<<act_score<<" and "
219  <<act_num_inlier<<" inliers\n");
220  }
221 
222 
223 #ifdef BIAS_DEBUG
224  if (sample_index!=0){
225  BIASCDOUT(D_MSAC_SOLVEM, "(best: "<<best_sol<<"/"<<best_score<<"/"
226  <<best_num_inlier<<std::endl);
227  }
228 #endif
229  if (best_score>act_score){
230  best_score=act_score;
231  best_index=sample_index;
232  best_num_inlier=act_num_inlier;
233  best_sol=act_sol;
234  }
235  if (best_score<_dTerminateScore){
236  BIASCDOUT(D_MSAC_SOLVEM, "finished sampling, got a good score "
237  <<best_score<<std::endl);
238  //cout << "rechaded score of "<<best_score<<", aborting\n";
239  break;
240  }
241  } else { // if (GenerateSamples(sample_index, which_samples)){
242  BIASERR("GenerateSamples failed");
243  BIASASSERT(false);
244  }
245  }
246  // now search best solution and refine it if not already done in loop
247  if (!_MSACRefineSolution){
248  solution=best_sol;
249  BIASCDOUT(D_MSAC_SOLVEM, "now refining solution "<<solution<<std::endl);
250  which_samples.clear();
251  for (int i=0; i<_iDataSize; i++){
252  if (inliervec[best_index][i]){
253  which_samples.push_back(i);
254  }
255  }
256 
257  if (!RefineSolution(which_samples, solution, inliers)){
258  BIASERR("RefineSolution returned false");
259  BIASASSERT(false);
260  }
261  } else {
262  inliers=inliervec[best_index];
263  solution=best_sol;
264  }
265  BIASCDOUT(D_MSAC_SOLVEM, "finished: score "<<best_score<<" with "
266  <<best_num_inlier<<" inlier, solution is "<<solution<<std::endl);
267  return 0;
268  }
269 
270  template <class SolutionType>
272  GetSampleSolution(std::vector<unsigned int> &which_samples,
273  SolutionType &solutions)
274  {
275  BIASERR("this function should be implemented in derived class");
276  return -1;
277  }
278 
279 
280 
281  template <class SolutionType>
283  EvaluateSolution(const SolutionType& solution, std::vector<bool>& inlier,
284  int& num_inliers, double& evaluate_score)
285  {
286  BIASERR("this function should be implemented in derived class");
287  return false;
288  }
289 
290 
291 
292 
293  template <class SolutionType>
295  RefineSolution(std::vector<unsigned int>& which_samples,
296  SolutionType& solution, std::vector<bool>& new_inliers)
297  {
298  BIASERR("this function should be implemented in derived class");
299  return false;
300  }
301 
302 
303 
304  template <class SolutionType>
306  GenerateSamples(int sample_index, std::vector<unsigned int>& which_samples)
307  {
308  return _GenerateSamplesRandom(sample_index, which_samples);
309  }
310 
311 
312 
313 
314  template <class SolutionType>
316  _GenerateSamplesRandom(int sample_index,
317  std::vector<unsigned int>& which_samples)
318  {
319  bool res=true;
320 #ifdef BIAS_DEBUG
321  if (_iSampleSize==0){
322  BIASERR("call Init or appropriate constructor befor using MSAC");
323  BIASASSERT(false);
324  res=false;
325  }
326  if (_iSampleSize>=_iDataSize){
327  BIASERR("_iDataSize should be set in derived class befor using MSAC"
328  <<" _iSampleSize="<<_iSampleSize<<" _iDataSize : "
329  <<_iDataSize);
330  BIASASSERT(false);
331  res=false;
332  }
333 #endif
334  // initialzing random with 0 and 1 does not seem to work well
335  BIAS::Random ran(sample_index+rand());
336  int count=0;
337  unsigned int index;
338  which_samples.clear();
339 
340  do {
341  index = ran.GetUniformDistributedInt(0, _iDataSize-1);
342  if (find(which_samples.begin(), which_samples.end(), index)==
343  which_samples.end()){
344  which_samples.push_back(index);
345  count++;
346  }
347  } while (count<_iSampleSize);
348 
349 #ifdef BIAS_DEBUG
350  if ((GetDebugLevel() & D_MSAC_SAMPLES)!=0){
351  BIASCDOUT(D_MSAC_SAMPLES, "---------- sample "<<sample_index
352  <<" ---------------------------------"<<"\nnow using data: ");
353  std::ostream_iterator<int> oi(GetDebugStream(), " ");
354  std::copy(which_samples.begin(), which_samples.end(), oi);
355  GetDebugStream() << std::endl;
356  }
357 #endif
358 
359  return res;
360  }
361 
362 
363 
364 
365  template <class SolutionType>
366  double MSAC<SolutionType>::
367  _CalculateTerminateScore(double sigma, double expected_inlier_fraction)
368  {
369  double res=0.0;
370  res += _iDataSize * expected_inlier_fraction * sigma;
371  res += _iDataSize * (1.0-expected_inlier_fraction) *
372  _MSACSigmaFac * sigma;
373  return res;
374  }
375 
376 
377 
378 
379  template <class SolutionType>
381  _CalculateSampleCount(double expected_inlier_fraction)
382  {
383  if (expected_inlier_fraction == 1.0)
384  // the analytic expression below cant cope with this so do it explicitly.
385  return 1;
386 
387  // from Torr's thesis.
388  int res = int(log (1.0 - (_MSACConfidenceThresh)) /
389  log (1.0 - pow (expected_inlier_fraction,
390  (double) _iSampleSize)));
391  return res;
392  }
393 
394 } // namespace
395 
396 
397 #include <Base/Common/BIASpragmaEnd.hh>
398 
399 #endif // __MSAC_hh__
400 
virtual bool EvaluateSolution(const SolutionType &solution, std::vector< bool > &inlier, int &num_inliers, double &evaluate_score)
Definition: MSAC.hh:283
int Init(int data_size)
Definition: MSAC.hh:133
MSAC()
Definition: MSAC.hh:113
virtual bool GenerateSamples(int sample_index, std::vector< unsigned int > &which_samples)
Definition: MSAC.hh:306
virtual ~MSAC()
Definition: MSAC.hh:128
int _CalculateSampleCount(double expected_inlier_fraction)
Definition: MSAC.hh:381
int _iSolutionCount
Definition: MSAC.hh:90
double _MSACSigmaFac
Definition: MSAC.hh:86
int GetUniformDistributedInt(const int min, const int max)
get uniform distributed random variable including min/max
Definition: Random.cpp:139
int SolveMaster(SolutionType &solution, std::vector< bool > &inliers)
Definition: MSAC.hh:168
bool _GenerateSamplesRandom(int sample_index, std::vector< unsigned int > &which_samples)
Definition: MSAC.hh:316
int _iDataSize
Definition: MSAC.hh:89
double _MSACConfidenceThresh
Definition: MSAC.hh:85
virtual int GetSampleSolution(std::vector< unsigned int > &which_samples, SolutionType &solutions)
Definition: MSAC.hh:272
bool _MSACRefineSolution
Definition: MSAC.hh:84
double _CalculateTerminateScore(double sigma, double expected_inlier_fraction)
Definition: MSAC.hh:367
virtual bool RefineSolution(std::vector< unsigned int > &which_samples, SolutionType &solution, std::vector< bool > &new_inliers)
Definition: MSAC.hh:295
this class does something, but WHAT? Is it the M-Estimator SAmple Consensus ??
Definition: MSAC.hh:51
int _iSampleSize
Definition: MSAC.hh:91
double _dExpectedInlierFraction
Definition: MSAC.hh:88
double _dExpectedSigma
Definition: MSAC.hh:87
class for producing random numbers from different distributions
Definition: Random.hh:51
double _dTerminateScore
Definition: MSAC.hh:92