Jafar
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
ransac.hpp
00001 #ifndef RANSAC_TEMPLATE_HPP
00002 #define RANSAC_TEMPLATE_HPP
00003 
00004 #include <float.h>
00005 #include <vector>
00006 #include <cmath>
00007 
00008 #include "kernel/jafarException.hpp"
00009 
00011 #include "jmath/randomIntTmplt.hpp"
00012 
00013 #define PROBABILITY_GOOD_MODEL  0.90
00014 #define TOO_SMALL_MODEL_CHANGE  0.10
00015 
00016 namespace jafar {
00018   namespace model3d {
00059     template <class ModelType>
00060     class RANSAC
00061     {
00062     public:
00063       
00072       RANSAC();
00073       
00077       RANSAC(unsigned int sample_length);
00078       
00079       virtual ~RANSAC();
00080       
00081       
00088       void initialize(unsigned int sample_length);
00089       
00117       int Algorithm(double inlying_data_fraction,
00118         ModelType& model,
00119         std::vector<bool>& inliers,
00120         unsigned int&    nModelInlierNumber,
00121         double& dbModelScore);
00122       
00129       virtual void fitSampleModel(std::vector<unsigned int>&sample_data_indices,
00130          ModelType& model)=0;
00131       
00162       virtual 
00163       bool evaluateModel(const ModelType& model,
00164        std::vector<bool>& inlier, 
00165        unsigned int& unInlierNumber,
00166        double& evaluate_score);
00167       
00173       virtual 
00174       double distance(const ModelType& model, unsigned int unIndex)=0;
00175       //      {return 0.0;}
00176       
00186       virtual bool isDegenerate(std::vector<unsigned int>& sample_data_indices) 
00187       { return false; }
00188       
00195       virtual 
00196       bool generateSample(std::vector<unsigned int>& sample_data_indices);
00197       
00205       bool generateRandomSample(std::vector<unsigned int>& sampletable);
00206       
00207       
00208       // Setter and Getter functions
00209       
00216       inline void setMaxIterationNumber(unsigned int unMaxIterationNumber)
00217       { m_unMaxIterationNumber = unMaxIterationNumber; }
00218       
00233       void fixIterationNumber(unsigned int uiIterationNumber)
00234       { m_unFixedIterationNumber = uiIterationNumber; }
00235       
00237       void setInlierNumberThreshold(unsigned int unInlierNumberThreshold)
00238       {m_unInlierNumberThreshold = unInlierNumberThreshold;}
00239       
00241       unsigned int getInlierNumberThreshold()
00242       {return m_unInlierNumberThreshold;}
00243       
00247       void setInlierDistanceThreshold (double dbInlierDistanceThreshold)
00248       {  m_dbInlierDistanceThreshold =  dbInlierDistanceThreshold;}
00249       
00253       double getInlierDistanceThreshold ()
00254       {  return m_dbInlierDistanceThreshold;}
00255       
00257       void setModelErrorThreshold(double dbModelErrorThreshold)
00258       { m_dbModelErrorThreshold = dbModelErrorThreshold;}
00259       
00261       double getModelErrorThreshold()
00262       { return m_dbModelErrorThreshold;}
00263       
00264     protected:
00266       unsigned int m_unDataLength;
00267       
00271       unsigned int m_unSampleLength;
00272       
00273       jafar::jmath::RandomUIntVect*  m_pRandomUIntVect;
00274       
00280       unsigned int m_unMaxIterationNumber;
00281       
00289       unsigned int m_unFixedIterationNumber;
00290       
00298       double m_dbProbabilityOfGoodModel;
00299       
00307       double m_dbInlierDistanceThreshold;
00308       
00315       unsigned int m_unInlierNumberThreshold;
00316       
00320       double m_dbModelErrorThreshold;
00321       
00322       
00323     private:
00324       static int ComputeIterationNumber(double inlying_data_fraction, 
00325           double desired_prob_good, 
00326           unsigned int sample_length);
00327     };
00328     
00329     
00330     
00331     //------------------------------------------------------------
00332     //   template Implementation                                    
00333     //------------------------------------------------------------
00334 
00335     template <class ModelType>
00336     RANSAC<ModelType>::RANSAC()
00337     {
00338       m_dbProbabilityOfGoodModel = PROBABILITY_GOOD_MODEL;
00339       m_unSampleLength=m_unDataLength=m_unMaxIterationNumber=0;
00340       m_unFixedIterationNumber = 0;
00341       m_pRandomUIntVect = NULL;
00342       
00343       srand(time(NULL));
00344     }
00345     
00346     template <class ModelType>
00347     RANSAC<ModelType>::RANSAC(unsigned int sample_length)
00348     {
00349       m_dbProbabilityOfGoodModel = PROBABILITY_GOOD_MODEL;
00350       initialize(sample_length);
00351       m_unDataLength = 0;
00352       m_pRandomUIntVect = NULL;
00353       
00354       srand(time(NULL));
00355     }
00356     
00357     template <class ModelType>
00358     void RANSAC<ModelType>::initialize(unsigned int sample_length)
00359     {
00360       m_unSampleLength = sample_length;
00361       m_unMaxIterationNumber = 0;
00362       m_unFixedIterationNumber = 0;
00363       
00364       srand(time(NULL));
00365 
00366 
00367     }
00368     
00369     template <class ModelType>
00370     RANSAC<ModelType>::~RANSAC()
00371     {
00372       if (m_pRandomUIntVect != NULL) {
00373   delete m_pRandomUIntVect;
00374   m_pRandomUIntVect = NULL;
00375       }
00376     }
00377     
00378     template <class ModelType>
00379     int RANSAC<ModelType>::Algorithm(double inlying_data_fraction,
00380              ModelType& model,
00381              std::vector<bool>& inliers,
00382              unsigned int&    nModelInlierNumber,
00383              double& dbModelScore)
00384     {
00385       JFR_PRECOND(m_unDataLength!=0,
00386       "m_unDataLength should be set in derived class first.. use initialize");
00387 
00388       if (inlying_data_fraction>1.0 || inlying_data_fraction<0.0){
00389   JFR_RUN_TIME("invalid value : inlying_data_fraction must be between 0 and 1 ");
00390       }
00391       
00392       if (m_unDataLength < m_unSampleLength) {
00393   JFR_RUN_TIME("Algorithm: m_unDataLength < m_unSampleLength !");
00394       }
00395       
00396       // current Model
00397       ModelType curModel;
00398       // score for current model, set by evaluateModel
00399       double dbCurScore;
00400       // number of inliers for current model
00401       unsigned int nCurInlierNumber; 
00402 
00403       std::vector<bool> curInliers(m_unDataLength, false);
00404 
00405       // indexes of sample for current model
00406       std::vector<unsigned int> sample_data_indices;
00407 
00408       // current model is accepted by evaluateModel
00409       bool bGoodModel;
00410       // we have at least got a good model
00411       bool bGotModel;
00412       
00413       // indicates that the current is the best model so far
00414       bool theBestFlag;
00415       
00416       int iteration_number; // the number of loop
00417       int nIterationIndex;  // loop index
00418 
00419       // reset values
00420       nModelInlierNumber   = 0;
00421       dbModelScore = DBL_MAX;
00422       bGotModel = false;
00423       
00424       // check whether m_unFixedIterationNumber has been set
00425       // (to a positive value)
00426       if (m_unFixedIterationNumber>0) {
00427   // yes the user specified to make exactly 
00428   // m_unFixedIterationNumber iterations
00429   iteration_number = m_unFixedIterationNumber; 
00430       }
00431       else {
00432   // compute the number of iterations needed using Torr's thesis
00433   iteration_number = ComputeIterationNumber(inlying_data_fraction, 
00434               m_dbProbabilityOfGoodModel,
00435               m_unSampleLength);
00436       }
00437       
00438       // in all cases, Algorithm will stop at most after
00439       //  m_unMaxIterationNumber iterations
00440       if (m_unMaxIterationNumber != 0 && 
00441     (unsigned)iteration_number > m_unMaxIterationNumber) {
00442   iteration_number = m_unMaxIterationNumber;
00443       }
00444       
00445       // the main loop      
00446       for (nIterationIndex = 0; nIterationIndex < iteration_number; 
00447      nIterationIndex++) {
00448 
00449   // generate a sample  
00450   if (! generateSample(sample_data_indices)) {
00451     // generateSample failed, so continue and 
00452     // try a next iteration
00453     continue;
00454   }
00455     
00456   // now we have a sample
00457   if ( isDegenerate(sample_data_indices)){
00458     // we have a degerated sample, so continue and 
00459     // try a next iteration
00460     continue;
00461   }
00462     
00463   // now we have a non-degenerate sample
00464   fitSampleModel(sample_data_indices, curModel);
00465   if (bGotModel)
00466     nCurInlierNumber = nModelInlierNumber;
00467     
00468   dbCurScore = DBL_MAX;
00469   bGoodModel = evaluateModel(curModel, 
00470            curInliers,
00471            nCurInlierNumber,
00472            dbCurScore);
00473       
00474   // the criteria for deciding the best model is the following:
00475   // 1. if the unInlierNumber is higher than the previous best, 
00476   //    take it,
00477   // 2. if the unInlierNumber is equal to the previous best, and 
00478   //    the evaluate score is smaller than the previous best,
00479   //    take it.
00480   theBestFlag = false;
00481   if (bGoodModel) {
00482     if (!bGotModel) {
00483       bGotModel = true;
00484       theBestFlag = true;
00485     } 
00486     else {
00487       if (nCurInlierNumber > nModelInlierNumber ||
00488     (nCurInlierNumber == nModelInlierNumber &&
00489      dbCurScore < dbModelScore))
00490         theBestFlag = true;
00491     }
00492     
00493     if (theBestFlag) {
00494       // save inliers number, score, inliers and model
00495       nModelInlierNumber = nCurInlierNumber;
00496       dbModelScore = dbCurScore;      
00497       inliers = curInliers;
00498       model = curModel;     
00499     }
00500   } // if (bGoodModel)
00501       } // for (int nIterationIndex = 0 ...
00502       
00503       if (!bGotModel) {
00504   // "RANSAC: no model was found";
00505   // so it will return "failed" (-2)
00506   nIterationIndex = -2;
00507       }
00508       
00509       return nIterationIndex;
00510     }
00511     
00512     
00513     template <class ModelType>
00514     bool RANSAC<ModelType>::
00515     evaluateModel(const ModelType& model,
00516       std::vector<bool>& inlier,
00517       unsigned int& unInlierNumber,
00518       double& dbScore)
00519     {
00520       bool bGoodModel = false;
00521       inlier.clear();
00522       inlier.resize(m_unDataLength);
00523       
00524       unsigned int nCurInlierNumber = 0;
00525       dbScore = 0.0;
00526       double dbDistance;
00527       
00528       for (unsigned int i=0; i<m_unDataLength; i++){
00529   dbDistance = distance(model,i);
00530   inlier[i] = (dbDistance < m_dbInlierDistanceThreshold);
00531   if (inlier[i]) {
00532     nCurInlierNumber++;
00533     dbScore += dbDistance;
00534   }
00535       }
00536       if (nCurInlierNumber!=0) {
00537   dbScore /= nCurInlierNumber;
00538       } 
00539       else {
00540   dbScore=DBL_MAX;
00541   bGoodModel=false;
00542       }
00543       unInlierNumber = nCurInlierNumber;
00544       
00545       // we have a good model if the inlier number is greater than 
00546       // the inlier number threshold and the model score is smaller than the 
00547       // model error threshold
00548       bGoodModel = (unInlierNumber > m_unInlierNumberThreshold)
00549   && (dbScore < m_dbModelErrorThreshold);
00550 
00551       return bGoodModel;
00552     }
00553 
00554     
00555     template <class ModelType>
00556     bool RANSAC<ModelType>::
00557     generateSample(std::vector<unsigned int>& sample_data_indices)
00558     {
00559       return generateRandomSample(sample_data_indices);
00560     }
00561     
00562     template <class ModelType>
00563     bool RANSAC<ModelType>::
00564     generateRandomSample(std::vector<unsigned int>& sample_data_indices)
00565     {
00566       if (m_unSampleLength==0){
00567   //"call initialize or appropriate constructor befor using RANSAC"
00568   return false;
00569       }
00570       if (m_unSampleLength>=m_unDataLength){
00571   //"m_unDataLength should be set in derived class befor using RANSAC"
00572   return false;
00573       }
00574       JFR_PRECOND(m_pRandomUIntVect!=NULL,
00575       "NULL pointer:must use new to create it \
00576  when knowing the data size ");
00577       
00578       sample_data_indices = m_pRandomUIntVect->getDifferent();
00579       
00580       return true;
00581     }
00582     
00583     
00584     template <class ModelType>
00585     int RANSAC<ModelType>::
00586     ComputeIterationNumber(double inlying_data_fraction, 
00587          double desired_prob_good, 
00588          unsigned int sample_length)
00589     {
00590       // the analytic expression below cant cope with this so do it explicitly.
00591       // if all the data are inliers : we don't need to RANSAC
00592       // we can compute the model directly from the data
00593       if (inlying_data_fraction == 1.0)      
00594   return 1;
00595       
00596       // from Torr's thesis.
00597       return int(log (1.0 - desired_prob_good) /
00598      log (1.0 - pow (inlying_data_fraction, 
00599          (double) sample_length)));
00600     }
00601     
00602     
00603   } // namespace model3d
00604 } // namespace jafar
00605 
00606 #endif // RANSAC_TEMPLATE_HPP
00607 
00608 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on Wed Oct 15 2014 00:37:21 for Jafar by doxygen 1.7.6.1
LAAS-CNRS