29 #include <bias_config.h>
30 #include <Base/Common/BIASpragmaStart.hh>
32 #include <Base/Debug/Debug.hh>
33 #include <Base/Math/Random.hh>
34 #include <Base/Geometry/HomgPoint2D.hh>
35 #include <Base/Math/Matrix.hh>
43 #define RANSAC_SAMPLE_PROGRESS_EVERY 100
45 #define RANSAC_DEFAULT_PROBOFGOODSOLUTION 0.98
46 #define RANSAC_DEFAULT_SOSMALLSOLUTIONCHANGE 0.02
79 template <
class SolutionType>
99 RANSAC(
unsigned int sample_size,
unsigned int max_solutions_per_sample = 1,
100 bool refine_solution =
false,
bool greedy =
false);
104 inline void Init(
unsigned int sample_size,
unsigned int max_solutions_per_sample = 1,
105 bool refine_solution =
false,
bool greedy =
false);
145 inline virtual int SolveMaster(
double inlying_data_fraction,
146 SolutionType &solution,
147 std::vector<bool> &inliers);
155 std::vector<SolutionType> &solutions);
225 bool existing_solution_flag,
226 std::vector<bool>& inlier,
int& accept_count,
227 double& evaluate_score,
bool& ok_to_terminate_flag);
240 SolutionType& solution,
241 std::vector<bool>& new_inliers);
251 std::vector<unsigned int>& which_samples);
254 std::vector<unsigned int>& sample_table);
257 std::vector<unsigned int>& sampletable);
305 double desired_prob_good,
306 unsigned int sample_size);
316 template <
class SolutionType>
inline
319 _dProbabilityOfGoodSolution = RANSAC_DEFAULT_PROBOFGOODSOLUTION;
320 _dSoSmallSolutionChange = RANSAC_DEFAULT_SOSMALLSOLUTIONCHANGE;
321 _uiSampleSize=_uiMaxSolutionsPerSample=_uiDataSize=_uiMaxSamples=0;
322 _uiExplicitSampleNo = 0;
323 _bRefineSolution =
false;
324 _iBestSampleAcceptCount = _iBestInlierAcceptCount = -1;
325 _dBestSampleEvaluateScore = _dBestInlierEvaluateScore = -1.0;
326 _got_solution_flag =
false;
328 NewDebugLevel(
"D_RANSAC_INLIERS");
329 NewDebugLevel(
"D_RANSAC_SAMPLES");
330 NewDebugLevel(
"D_RANSAC_SOLVE_MASTER");
331 NewDebugLevel(
"D_RANSAC_SAMPLE_QUALITY");
332 NewDebugLevel(
"D_RANSAC_SAMPLE_PROGRESS");
333 NewDebugLevel(
"D_RANSAC_SOLUTION");
337 template <
class SolutionType>
inline
339 unsigned int max_solutions_per_sample,
340 bool refine_solution,
bool greedy)
342 _dProbabilityOfGoodSolution = RANSAC_DEFAULT_PROBOFGOODSOLUTION;
343 _dSoSmallSolutionChange = RANSAC_DEFAULT_SOSMALLSOLUTIONCHANGE;
344 Init(sample_size, max_solutions_per_sample, refine_solution);
346 _iBestSampleAcceptCount = _iBestInlierAcceptCount = -1;
347 _dBestSampleEvaluateScore = _dBestInlierEvaluateScore = -1.0;
348 _got_solution_flag =
false;
350 NewDebugLevel(
"D_RANSAC_INLIERS");
351 NewDebugLevel(
"D_RANSAC_SAMPLES");
352 NewDebugLevel(
"D_RANSAC_SOLVE_MASTER");
353 NewDebugLevel(
"D_RANSAC_SAMPLE_QUALITY");
354 NewDebugLevel(
"D_RANSAC_SAMPLE_PROGRESS");
355 NewDebugLevel(
"D_RANSAC_SOLUTION");
359 template <
class SolutionType>
inline
361 unsigned int max_solutions_per_sample,
362 bool refine_solution,
bool greedy)
364 _uiSampleSize=sample_size;
365 _uiMaxSolutionsPerSample=max_solutions_per_sample;
366 _bRefineSolution=refine_solution;
368 _uiExplicitSampleNo = 0;
372 template <
class SolutionType>
inline
377 template <
class SolutionType>
inline
379 SolutionType& solution,
380 std::vector<bool>& inliers)
382 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC::SolveMaster() --------------------"
383 "--------------------------------------\n");
387 BIASERR(
"_uiDataSize should be set in derived class first "
391 if (inlying_data_fraction>1.0 || inlying_data_fraction<0.0){
392 BIASERR(
"invalid inlying_data_fraction: "<<inlying_data_fraction);
396 if (_uiDataSize < _uiSampleSize) {
397 BIASERR(
"SolveMaster: _uiDataSize < _uiSampleSize !");
401 std::vector<bool> inlier_set(_uiDataSize,
false);
403 std::vector<SolutionType> multisoln_table(_uiMaxSolutionsPerSample);
407 if (_uiExplicitSampleNo>0) {
409 sample_count = _uiExplicitSampleNo;
410 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: Using "<< sample_count
411 <<
" samples (explicitly specified).");
414 sample_count = ComputeSampleCount(inlying_data_fraction,
415 _dProbabilityOfGoodSolution,
418 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: Need at most "<< sample_count
419 <<
" samples for "<< inlying_data_fraction <<
" inlier fraction");
424 if (_uiMaxSamples != 0 && (
unsigned)sample_count > _uiMaxSamples) {
425 sample_count = _uiMaxSamples;
426 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: But will bail out after "
431 std::vector<unsigned int> which_samples;
437 int sample_accept_count;
440 double sample_evaluate_score;
443 bool ok_to_terminate_flag;
449 int inlier_accept_count;
452 double inlier_evaluate_score;
455 bool best_so_far_flag;
460 bool checkpoint_set_flag =
false;
463 int sample_checkpoint_count = 0;
464 int inlier_checkpoint_count = 0;
468 bool termination_check_active_flag =
false;
469 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"\nchecking at most "<<sample_count
473 int best_sample_index = -1;
476 for (sample_index = 0; sample_index < sample_count; sample_index++){
478 if (sample_index % RANSAC_SAMPLE_PROGRESS_EVERY ==
479 RANSAC_SAMPLE_PROGRESS_EVERY-1) {
480 BCDOUT(D_RANSAC_SAMPLE_PROGRESS,
"RANSAC sample "
481 <<sample_index+1<<
" of "<<sample_count << std::endl);
485 if (GenerateSamples(sample_index, which_samples)){
490 nsolutions = GetSampleSolutions(which_samples, multisoln_table);
491 if (nsolutions == 0) {
492 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"o"<<std::flush);
494 for (
int solution_index=0; solution_index<nsolutions;solution_index++){
495 BCDOUT(D_RANSAC_SOLVE_MASTER,
"evaluating solution "
496 <<solution_index+1<<
"/"<<nsolutions<<std::endl);
497 SolutionType* active_solution_ptr = &multisoln_table[solution_index];
499 if (_got_solution_flag)
500 sample_accept_count = _iBestSampleAcceptCount;
502 ok_to_terminate_flag =
false;
503 sample_evaluate_score = DBL_MAX;
505 EvaluateSolution(*active_solution_ptr, _got_solution_flag,
506 inlier_set, sample_accept_count,
507 sample_evaluate_score, ok_to_terminate_flag);
509 BCDOUT(D_RANSAC_SOLVE_MASTER,
"sample: "<<sample_index<<
"/"
511 <<solution_index<<
")"
512 <<
" solution: "<<(*active_solution_ptr)
513 <<
" inliers: " <<sample_accept_count<<
"/"<<_uiDataSize
514 <<
" score: "<< sample_evaluate_score<<
" good_flag: "
515 <<std::boolalpha<<good_flag<<std::endl);
516 inlier_accept_count=-1;
517 inlier_evaluate_score = 1e20;
518 if (good_flag && _bRefineSolution) {
520 SolutionType samplesolution = *active_solution_ptr;
521 bool ok_to_terminate_with_linear = ok_to_terminate_flag;
523 which_samples.clear();
524 for (
unsigned int i=0; i<_uiDataSize; i++)
525 if (inlier_set[i]) which_samples.push_back(i);
526 BCDOUT(D_RANSAC_SOLVE_MASTER,
"refining solution "
527 <<*active_solution_ptr<<std::endl);
528 if (RefineSolution(which_samples, *active_solution_ptr,
530 if (_got_solution_flag)
531 inlier_accept_count = _iBestInlierAcceptCount;
532 BCDOUT(D_RANSAC_SOLVE_MASTER,
"evaluating refined solution: "
533 <<*active_solution_ptr<<std::endl);
536 EvaluateSolution (*active_solution_ptr, _got_solution_flag,
537 inlier_set, inlier_accept_count,
538 inlier_evaluate_score, ok_to_terminate_flag);
540 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: minimal/refined "
541 <<sample_accept_count<<
"/"
542 <<inlier_accept_count<<
" "
543 <<sample_evaluate_score<<
"/"
544 <<inlier_evaluate_score<<std::endl);
546 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: (note) "
547 <<
"EvaluateSolution returned false\n");
552 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: (note) RefineSolution"
553 <<
" returned false\n");
557 if (!good_flag || (inlier_accept_count < sample_accept_count)) {
558 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: (note) Linear solution"
559 <<
" overrides refined !!! \n");
561 inlier_accept_count = sample_accept_count;
562 inlier_evaluate_score = sample_evaluate_score;
563 *active_solution_ptr = samplesolution;
564 ok_to_terminate_flag = ok_to_terminate_with_linear;
567 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: (note) either good_flag"
568 <<
"=false or _bRefineSolution=false\n");
576 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"."<<std::flush);
577 best_so_far_flag =
false;
579 if (!_got_solution_flag) {
580 BCDOUT(D_RANSAC_SOLVE_MASTER,
"setting _got_solution_flag to "
582 _got_solution_flag =
true;
583 best_so_far_flag =
true;
585 if (!_bRefineSolution) {
586 if (sample_accept_count > _iBestSampleAcceptCount ||
587 (sample_accept_count == _iBestSampleAcceptCount &&
588 sample_evaluate_score < _dBestSampleEvaluateScore))
589 best_so_far_flag =
true;
591 if (inlier_accept_count > _iBestInlierAcceptCount ||
592 (inlier_accept_count == _iBestInlierAcceptCount &&
593 inlier_evaluate_score < _dBestInlierEvaluateScore))
594 best_so_far_flag =
true;
600 if (best_so_far_flag) {
601 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"b"<<std::flush);
602 _iBestSampleAcceptCount = sample_accept_count;
603 _dBestSampleEvaluateScore =
604 (sample_evaluate_score<inlier_evaluate_score) ?
605 sample_evaluate_score : inlier_evaluate_score;
606 _iBestInlierAcceptCount = inlier_accept_count;
607 _dBestInlierEvaluateScore = inlier_evaluate_score;
608 best_sample_index = sample_index;
611 inliers = inlier_set;
612 solution = *active_solution_ptr;
614 BCDOUT(D_RANSAC_SOLVE_MASTER,
"RANSAC: Sample "<<sample_index
615 <<
" is best so far. " <<
"Inliers/score "
616 << _iBestSampleAcceptCount <<
"/"
617 <<_dBestSampleEvaluateScore<<
": "
618 <<solution<<std::endl);
619 if (_bRefineSolution){
620 BCDOUT(D_RANSAC_SOLVE_MASTER,
" refined inliers/score "
621 <<_iBestInlierAcceptCount <<
"/"
622 <<_dBestInlierEvaluateScore<<std::endl);
626 if (ok_to_terminate_flag){
627 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"x"<<std::flush);
628 termination_check_active_flag =
true;
631 BCDOUT(D_RANSAC_SOLVE_MASTER,
632 "RANSAC: termination_check_active_flag = true");
636 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"*"<< std::endl << std::flush);
641 if (_got_solution_flag) {
643 if (_greedy && termination_check_active_flag) {
644 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"X"<<std::flush);
645 BCDOUT(D_RANSAC_SOLVE_MASTER,
" found solution, stopping sample "
649 if (!checkpoint_set_flag) {
650 checkpoint_set_flag =
true;
651 }
else if (_greedy) {
656 if (!_bRefineSolution) {
657 if (termination_check_active_flag &&
658 ((
double) (_iBestSampleAcceptCount - sample_checkpoint_count)
659 /(
double)sample_checkpoint_count <_dSoSmallSolutionChange)){
660 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"S"<<std::flush);
664 if (termination_check_active_flag &&
665 ((
double) (_iBestInlierAcceptCount - inlier_checkpoint_count)
666 /(
double)inlier_checkpoint_count <_dSoSmallSolutionChange)){
667 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"S"<<std::flush);
674 inlier_checkpoint_count = _iBestInlierAcceptCount;
675 sample_checkpoint_count = _iBestSampleAcceptCount;
678 BIASERR(
"GenerateSamples failed");
683 if (sample_index % RANSAC_SAMPLE_PROGRESS_EVERY ==
684 RANSAC_SAMPLE_PROGRESS_EVERY-1) {
685 if (_bRefineSolution){
686 BCDOUT(D_RANSAC_SAMPLE_PROGRESS,
"Refined inliers/score "
687 <<_iBestInlierAcceptCount <<
"/"
688 <<_dBestInlierEvaluateScore<<
"\n");
690 BCDOUT(D_RANSAC_SAMPLE_PROGRESS,
" Unrefined inliers/score "
691 << _iBestSampleAcceptCount <<
"/"
692 <<_dBestSampleEvaluateScore<<
" as solution : "
699 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"\n");
700 BCDOUT(D_RANSAC_SAMPLE_QUALITY,
"stopped after "<<sample_index
703 if (!_got_solution_flag) {
704 BCDOUT(D_RANSAC_SOLUTION,
"RANSAC: no solution found\n");
705 BIASWARN(
"RANSAC: no solution found, return -2");
707 best_sample_index = -2;
709 if (_greedy && sample_index==sample_count){
710 BCDOUT(D_RANSAC_SOLUTION,
711 "RANSAC: early termination not successful\n");
712 BCDOUT(D_RANSAC_SOLUTION,
713 "RANSAC: no sufficient solution found\n");
715 BCDOUT(D_RANSAC_SOLVE_MASTER,
"\nRANSAC: using sample "<<best_sample_index
716 <<
" with inliers/score "<< _iBestSampleAcceptCount <<
"/"
717 <<_dBestSampleEvaluateScore<<
" as solution : "
719 if (_bRefineSolution){
720 BCDOUT(D_RANSAC_SOLVE_MASTER,
" refined inliers/score "
721 <<_iBestInlierAcceptCount <<
"/"
722 <<_dBestInlierEvaluateScore<<
"\n");
725 _dLastBestSampleEvaluateScore = _dBestSampleEvaluateScore;
727 _iBestSampleAcceptCount = -1;
728 _dBestSampleEvaluateScore = -1;
729 _iBestInlierAcceptCount = -1;
730 _dBestInlierEvaluateScore = -1;
731 _got_solution_flag =
false;
732 return best_sample_index;
736 template <
class SolutionType>
inline
739 std::vector<SolutionType> &solutions)
741 BIASERR(
"this function should be implemented in derived class");
746 template <
class SolutionType>
inline
749 std::vector<bool>& out_inlier_flags,
int& accept_count_ptr,
750 double& evaluate_score_ptr,
bool& ok_to_terminate_flag_ptr)
752 BIASERR(
"this function should be implemented in derived class");
756 template <
class SolutionType>
inline
759 SolutionType& solution,
760 std::vector<bool>& new_inliers)
762 BIASERR(
"this function should be implemented in derived class");
766 template <
class SolutionType>
inline
770 return GenerateSamplesRandom(sample_index, which_samples);
773 template <
class SolutionType>
inline
776 std::vector<unsigned int>& which_samples)
779 BIASERR(
"unfinished code");
811 template <
class SolutionType>
inline
814 std::vector<unsigned int>& which_samples)
818 if (_uiSampleSize==0){
819 BIASERR(
"call Init or appropriate constructor before using RANSAC "
820 <<
"(_uiSampleSize==0");
824 if (_uiSampleSize>=_uiDataSize){
825 BIASERR(
"_uiDataSize should be set in derived class before using RANSAC "
826 <<
"\t_uiSampleSize: "<<_uiSampleSize<<
"\t_uiDataSize: "
833 Random ran(sample_index+rand());
834 unsigned int count=0;
836 which_samples.clear();
839 if (find(which_samples.begin(), which_samples.end(), index)==
840 which_samples.end()){
841 which_samples.push_back(index);
845 }
while (count<_uiSampleSize);
848 if (DebugLevelIsSet(
"D_RANSAC_SAMPLES")){
849 BCDOUT(D_RANSAC_SAMPLES,
"---------- sample "<<sample_index
850 <<
" ---------------------------------"<<
"\nnow using data: ");
851 std::ostream_iterator<int> oi(GetDebugStream(),
" ");
852 std::copy(which_samples.begin(), which_samples.end(), oi);
853 GetDebugStream() << std::endl;
861 template <
class SolutionType>
inline
864 unsigned int sample_size)
866 if (inlying_data_fraction == 1.0)
871 return int(log (1.0 - desired_prob_good) /
872 log (1.0 - pow (inlying_data_fraction, (
double) sample_size)));
878 #include <Base/Common/BIASpragmaEnd.hh>
880 #endif //__RANSAC_hh__
unsigned int _uiMaxSamples
absolute max number of samples
unsigned _uiSampleSize
number of samples available
double _dLastBestSampleEvaluateScore
bool GenerateSamplesEvenspace(int sample_index, std::vector< unsigned int > &sample_table)
bool GenerateSamplesRandom(int sample_index, std::vector< unsigned int > &sampletable)
double _dBestSampleEvaluateScore
unsigned _uiMaxSolutionsPerSample
max number of solutions that are to be computed for one sample set
virtual bool GenerateSamples(int sample_index, std::vector< unsigned int > &which_samples)
pick a set of samples
unsigned int _uiExplicitSampleNo
use this number of samples
bool _bRefineSolution
do we want to refine a good sample (one for which evaluate solution returned true)?
virtual int SolveMaster(double inlying_data_fraction, SolutionType &solution, std::vector< bool > &inliers)
Main computation function called by user.
double _dBestInlierEvaluateScore
int GetUniformDistributedInt(const int min, const int max)
get uniform distributed random variable including min/max
void Init(unsigned int sample_size, unsigned int max_solutions_per_sample=1, bool refine_solution=false, bool greedy=false)
bool _got_solution_flag
if we already have a solution for which EvaluateSolution returned true
double _dSoSmallSolutionChange
If all other conditions are right, and the fractional change in the solution statistics is less than ...
double GetFinalScore() const
int _iBestSampleAcceptCount
sampled best values
void SetMaxSamples(unsigned int max_samples)
Explicitly set max number of samples.
static int ComputeSampleCount(double inlying_data_fraction, double desired_prob_good, unsigned int sample_size)
Generic abstract base class for RANSAC (RANdom SAmple Consensus) estimators.
bool _greedy
if true, the first acceptable solution is returned
virtual int GetSampleSolutions(std::vector< unsigned int > &which_samples, std::vector< SolutionType > &solutions)
Compute solution(s) for the given set of samples.
int _iBestInlierAcceptCount
refined best values
virtual bool RefineSolution(std::vector< unsigned int > &which_samples, SolutionType &solution, std::vector< bool > &new_inliers)
refine previously computed solution based on its inliers
unsigned _uiDataSize
number of data elements needed to compute a solution
void SetSampleCount(unsigned int uiSamples)
Explicitly set number of samples.
double _dProbabilityOfGoodSolution
prob. for computing number of samples, set close to 1
virtual bool EvaluateSolution(const SolutionType &solution, bool existing_solution_flag, std::vector< bool > &inlier, int &accept_count, double &evaluate_score, bool &ok_to_terminate_flag)
evaluate the goodness of a solution
class for producing random numbers from different distributions