19 #ifndef SPARSE_MAPPING_RANSAC_H_ 
   20 #define SPARSE_MAPPING_RANSAC_H_ 
   22 #include <glog/logging.h> 
   36                              std::mt19937 * generator, std::vector<int> * values);
 
   39 template <
class FittingFuncT, 
class ErrorFuncT>
 
   41   const FittingFuncT& m_fitting_func;
 
   42   const ErrorFuncT  & m_error_func;
 
   44   double        m_inlier_threshold;
 
   45   int           m_min_num_output_inliers;
 
   46   bool          m_reduce_min_num_output_inliers_if_no_fit;
 
   47   bool          m_increase_threshold_if_no_fit;
 
   48   std::mt19937  m_generator;
 
   52   template <
class ContainerT1, 
class ContainerT2>
 
   53   void inliers(
typename FittingFuncT::result_type 
const& H,
 
   54                std::vector<ContainerT1>  
const& p1,
 
   55                std::vector<ContainerT2>  
const& p2,
 
   56                std::vector<ContainerT1>       & inliers1,
 
   57                std::vector<ContainerT2>       & inliers2)
 const {
 
   61     for (
size_t i = 0; i < p1.size(); i++) {
 
   62       if (m_error_func(H, p1[i], p2[i]) < m_inlier_threshold) {
 
   63         inliers1.push_back(p1[i]);
 
   64         inliers2.push_back(p2[i]);
 
   70   template <
class ContainerT1, 
class ContainerT2>
 
   71   std::vector<size_t> 
inlier_indices(
typename FittingFuncT::result_type 
const& H,
 
   72                                      std::vector<ContainerT1>  
const& p1,
 
   73                                      std::vector<ContainerT2>  
const& p2)
 const {
 
   74     std::vector<size_t> result;
 
   75     for (
size_t i = 0; i < p1.size(); i++)
 
   76       if (m_error_func(H, p1[i], p2[i]) < m_inlier_threshold)
 
   79     LOG(INFO) << 
"RANSAC inliers / total = " << result.size() << 
" / " << p1.size() << 
".\n";
 
   85     m_min_num_output_inliers = 
static_cast<int>(m_min_num_output_inliers/1.5);
 
   90                         ErrorFuncT   
const& error_func,
 
   92                         double inlier_threshold,
 
   93                         int    min_num_output_inliers,
 
   94                         bool   reduce_min_num_output_inliers_if_no_fit,
 
   95                         bool   increase_threshold_if_no_fit):
 
   96     m_fitting_func(fitting_func), m_error_func(error_func),
 
   97     m_num_iterations(num_iterations),
 
   98     m_inlier_threshold(inlier_threshold),
 
   99     m_min_num_output_inliers(min_num_output_inliers),
 
  100     m_reduce_min_num_output_inliers_if_no_fit(reduce_min_num_output_inliers_if_no_fit),
 
  101     m_increase_threshold_if_no_fit(increase_threshold_if_no_fit),
 
  102     m_generator(
std::mt19937(
std::time(0))) {}
 
  105   template <
class ContainerT1, 
class ContainerT2>
 
  106   typename FittingFuncT::result_type 
operator()(std::vector<ContainerT1> 
const& p1,
 
  107                                                 std::vector<ContainerT2> 
const& p2) {
 
  112     typename FittingFuncT::result_type H;
 
  113     bool success = 
false;
 
  115     int orig_num_inliers = m_min_num_output_inliers;
 
  120     for (
int attempt_thresh = 0; attempt_thresh < 10; attempt_thresh++) {
 
  121       for (
int attempt_inlier = 0; attempt_inlier < 10; attempt_inlier++) {
 
  126         } 
catch (
const std::exception& e) {
 
  127           LOG(INFO) << e.what() << 
"\n";
 
  128           if (!m_reduce_min_num_output_inliers_if_no_fit)
 
  132           if (m_min_num_output_inliers < 3)
 
  134           LOG(INFO) << 
"Attempting RANSAC with " << m_min_num_output_inliers
 
  135                     << 
" output inliers.\n";
 
  141       if (!m_increase_threshold_if_no_fit)
 
  144       m_min_num_output_inliers = orig_num_inliers;  
 
  145       m_inlier_threshold *= 1.5;
 
  146       LOG(INFO) << 
"Increasing the inlier threshold to: " << m_inlier_threshold << 
".\n";
 
  150       LOG(FATAL) << 
"RANSAC was unable to find a fit that matched the supplied data.";
 
  156   template <
class ContainerT1, 
class ContainerT2>
 
  157   typename FittingFuncT::result_type 
attempt_ransac(std::vector<ContainerT1> 
const& p1,
 
  158                                                     std::vector<ContainerT2> 
const& p2) {
 
  160       LOG(FATAL) << 
"RANSAC error. Insufficient data.\n";
 
  161     if (p1.size() != p2.size())
 
  162       LOG(FATAL) << 
"RANSAC error. Data vectors are not the same size.\n";
 
  164     int min_elems_for_fit = m_fitting_func.min_elements_needed_for_fit();
 
  166     if (
static_cast<int>(p1.size()) < min_elems_for_fit)
 
  167       LOG(FATAL) << 
"RANSAC error. Not enough potential matches for this fitting functor.\n";
 
  170     if (m_min_num_output_inliers < min_elems_for_fit)
 
  171       throw std::runtime_error(
"RANSAC error. Number of requested inliers is less than " 
  172                                "min number of elements needed for fit.\n");
 
  174     typename FittingFuncT::result_type best_H;
 
  176     std::vector<ContainerT1> try1;
 
  177     std::vector<ContainerT2> try2;
 
  178     std::vector<int> random_indices(min_elems_for_fit);
 
  181     double min_err = std::numeric_limits<double>::max();
 
  182     for (
int iteration = 0; iteration < m_num_iterations; iteration++) {
 
  189       try1.resize(min_elems_for_fit);
 
  190       try2.resize(min_elems_for_fit);
 
  191       for (
int i = 0; i < min_elems_for_fit; i++) {
 
  192         try1[i] = p1[random_indices[i]];
 
  193         try2[i] = p2[random_indices[i]];
 
  197       typename FittingFuncT::result_type H = m_fitting_func(try1, try2);
 
  200       inliers(H, p1, p2, try1, try2);
 
  203       if (
static_cast<int>(try1.size()) < m_min_num_output_inliers)
 
  207       H = m_fitting_func(try1, try2);
 
  210       double err_val = 0.0;
 
  211       for (
size_t i = 0; i < try1.size(); i++)
 
  212         err_val += m_error_func(H, try1[i], try2[i]);
 
  213       err_val /= try1.size();
 
  216       if (err_val < min_err) {
 
  219         num_inliers = try1.size();
 
  223     if (num_inliers < m_min_num_output_inliers) {
 
  225       std::ostringstream os;
 
  226       os << 
"RANSAC was unable to find a fit with " << m_min_num_output_inliers << 
" inliers.";
 
  227       throw std::runtime_error(os.str());
 
  234   template <
class ContainerT1, 
class ContainerT2, 
class FittingFuncT, 
class ErrorFuncT>
 
  235   typename FittingFuncT::result_type 
ransac(std::vector<ContainerT1> 
const& p1,
 
  236                                             std::vector<ContainerT2> 
const& p2,
 
  237                                             FittingFuncT             
const& fitting_func,
 
  238                                             ErrorFuncT               
const& error_func,
 
  240                                             double  inlier_threshold,
 
  241                                             int     min_num_output_inliers,
 
  242                                             bool    reduce_min_num_output_inliers_if_no_fit,
 
  243                                             bool    increase_threshold_if_no_fit) {
 
  245       ransac_instance(fitting_func, error_func,
 
  246                       num_iterations, inlier_threshold,
 
  247                       min_num_output_inliers,
 
  248                       reduce_min_num_output_inliers_if_no_fit,
 
  249                       increase_threshold_if_no_fit);
 
  250     return ransac_instance(p1, p2);
 
  255 #endif  // SPARSE_MAPPING_RANSAC_H_