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_