Jafar
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
ransac.hpp
00001 /**************************************************************************
00002  This file is kind of copy paste from the MRPT project http://www.mrpt.org.
00003  From MRPT: the C++ port "is highly inspired on Peter Kovesi's MATLAB 
00004  scripts (http://www.csse.uwa.edu.au/~pk)"
00005 ***************************************************************************/
00006 #ifndef  JMATH_RANSAC_HPP
00007 #define  JMATH_RANSAC_HPP
00008 #include "jmath/uniform_random.hpp"
00009 
00010 namespace jafar {
00011   namespace jmath {
00012     template <typename NUMTYPE = double>
00016     class RANSAC {
00017     public:
00018 
00020       typedef void (*RANSAC_fit_functor)(const ublas::matrix<NUMTYPE>  &data,
00021                                         const std::vector<size_t> &indices,
00022                                         ublas::vector< ublas::matrix<NUMTYPE> > &fit_models);
00023 
00025       typedef void (*RANSAC_distance_functor)(const ublas::matrix<NUMTYPE>  &data,
00026                                              const ublas::vector< ublas::matrix<NUMTYPE> > & test_models,
00027                                              NUMTYPE   distance_threshold,
00028                                              unsigned int & best_model_index,
00029                                              std::vector<size_t>& inlier_indices );
00030 
00032       typedef bool (*RANSAC_degenerate_functor)(const ublas::matrix<NUMTYPE>  &data,
00033                                                const std::vector<size_t> &indices );
00034 
00044       static bool execute(const ublas::matrix<NUMTYPE>    &data,
00045                           RANSAC_fit_functor          fit_func,
00046                           RANSAC_distance_functor   dist_func,
00047                           RANSAC_degenerate_functor   degen_func,
00048                           const NUMTYPE               distance_threshold,
00049                           const unsigned int        min_size_samples_to_fit,
00050                           std::vector<size_t>       &out_best_inliers,
00051                           ublas::matrix<NUMTYPE>    &out_best_model,
00052                           const NUMTYPE              prob_good_sample = 0.999,
00053                           const size_t              max_iter = 200000) 
00054       {
00055         JFR_ASSERT(min_size_samples_to_fit>=1, 
00056                    "minimum size of samples to fit must be greater than 0")
00057           const size_t D = data.size1();  //  dimensionality
00058         const size_t nb_pts = data.size2();
00059         
00060         JFR_ASSERT(D>=1, "data diemension must be greater than 0");
00061         JFR_ASSERT(nb_pts>1, "number of data points must be at least 2");
00062         // Maximum number of attempts to select a non-degenerate data set.
00063         const size_t maxDataTrials = 100; 
00064         // Sentinel value allowing detection of solution failure.
00065         out_best_model.resize(0,0);  
00066 
00067         size_t trialcount = 0;  //
00068         size_t bestscore =  0;
00069         size_t N = 1;     // Dummy initialisation for number of trials.
00070         
00071         std::vector<size_t>   ind( min_size_samples_to_fit );
00072         
00073         while (N > trialcount) {
00074           // Select at random s datapoints to form a trial model, M.
00075           // In selecting these points we have to check that they are not in
00076           // a degenerate configuration.
00077           bool degenerate=true;
00078           size_t count = 1;
00079           ublas::vector< ublas::matrix<NUMTYPE> >  MODELS;
00080 
00081           while (degenerate) {
00082             // Generate s random indicies in the range 1..npts
00083             ind.resize( min_size_samples_to_fit );
00084             
00085             random::uniform_fill((unsigned int)0, (unsigned int)nb_pts-1, ind);
00086 
00087             // Test that these points are not a degenerate configuration.
00088             degenerate = degen_func(data, ind);
00089 
00090             if (!degenerate) {
00091               // Fit model to this random selection of data points.
00092               // Note that M may represent a set of models that fit the data
00093               fit_func(data,ind,MODELS);
00094 
00095               // Depending on your problem it might be that the only way you
00096               // can determine whether a data set is degenerate or not is to
00097               // try to fit a model and see if it succeeds.  If it fails we
00098               // reset degenerate to true.
00099               degenerate = MODELS.empty();
00100             }
00101 
00102             // Safeguard against being stuck in this loop forever
00103             if (++count > maxDataTrials) {
00104               JFR_DEBUG("unable to select a nondegenerate data set")
00105             }
00106           }
00107           JFR_DEBUG("found a non degenerate data set")
00108           // Once we are out here we should have some kind of model...
00109           // Evaluate distances between points and model returning the indices
00110           // of elements in x that are inliers.  Additionally, if M is a cell
00111           // array of possible models 'distfn' will return the model that has
00112           // the most inliers.  After this call M will be a non-cell objec
00113           // representing only one model.
00114           unsigned int best_model_index = -1;
00115           std::vector<size_t>   inliers;
00116           if (!degenerate) {
00117             dist_func(data,MODELS, distance_threshold, best_model_index, inliers);
00118             // JFR_ASSERT(((best_model_index < MODELS.size()) && (best_model_index > -1)), 
00119             //            "best model index must be in [0.."<<MODELS.size()<<"[");
00120           }
00121           JFR_DEBUG("best model index "<<best_model_index)
00122           // Find the number of inliers to this model.
00123           const size_t ninliers = inliers.size();
00124           JFR_DEBUG("nb inliers "<<ninliers)
00125           if (ninliers > bestscore ) {
00126             bestscore = ninliers;  // Record data for this model
00127             out_best_model.resize(MODELS[best_model_index].size1(), MODELS[best_model_index].size2());
00128             out_best_model    = MODELS[best_model_index];
00129             out_best_inliers  = inliers;
00130 
00131             // Update estimate of N, the number of trials to ensure we pick,
00132             // with probability p, a data set with no outliers.
00133             NUMTYPE fracinliers =  ninliers/static_cast<NUMTYPE>(nb_pts);
00134             NUMTYPE pNoOutliers = 1 -  pow(fracinliers,static_cast<NUMTYPE>(min_size_samples_to_fit));
00135           
00136             pNoOutliers = std::max( std::numeric_limits<NUMTYPE>::epsilon(), pNoOutliers);  // Avoid division by -Inf
00137             pNoOutliers = std::min(1.0 - std::numeric_limits<NUMTYPE>::epsilon() , pNoOutliers); // Avoid division by 0.
00138             // Number of
00139             N = log(1-prob_good_sample)/log(pNoOutliers);
00140             JFR_DEBUG("iter #"<<(unsigned)trialcount<<" Estimated number of iters: "<<(unsigned)N<<" pNoOutliers = "<<pNoOutliers<<" #inliers: "<<(unsigned)ninliers)
00141           }
00142 
00143           ++trialcount;
00144 
00145           JFR_DEBUG("trial "<<(unsigned int)trialcount<<" out of "<<(unsigned int)ceil(static_cast<double>(N)))
00146 
00147           // Safeguard against being stuck in this loop forever
00148           if (trialcount > max_iter) {
00149             JFR_DEBUG("Warning: maximum number of trials ("<<max_iter<<") reached")
00150             break;
00151           }
00152         }
00153 
00154         if (out_best_model.size1()>0) {  // We got a solution
00155           JFR_DEBUG("Finished in "<<(unsigned)trialcount<<" iterations")
00156           return true;
00157         }
00158         else {
00159           JFR_DEBUG("Warning: Finished without any proper solution.")
00160           return false;
00161         }
00162       }
00163     }; // end class
00165     typedef RANSAC<double> ransac;   
00166 
00167   } // end of namespace jmath
00168 } // end of namespace jafar
00169 
00170 #endif
 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