33 const TMatchingPair& c, std::vector<bool>& alreadySelectedThis,
34 std::vector<bool>& alreadySelectedOther
35 #ifdef AVOID_MULTIPLE_CORRESPONDENCES
37 const std::vector<std::vector<int>>& listDuplicatedLandmarksThis
44 #ifndef AVOID_MULTIPLE_CORRESPONDENCES 45 alreadySelectedThis[c.
this_idx] =
true;
48 for (std::vector<int>::iterator it1 =
49 listDuplicatedLandmarksThis[c.
this_idx].begin();
50 it1 != listDuplicatedLandmarksThis[c.
this_idx].end(); it1++)
51 alreadySelectedThis[*it1] =
true;
52 for (std::vector<int>::iterator it2 =
53 listDuplicatedLandmarksOther[c.
other_idx].begin();
54 it2 != listDuplicatedLandmarksOther[c.
other_idx].end(); it2++)
55 alreadySelectedOther[*it2] =
true;
90 const size_t nCorrs = in_correspondences.size();
93 const double MAX_RMSE_TO_END =
100 if (nCorrs <
params.ransac_minSetSize)
103 results.transformation.clear();
109 timlog.enter(
"ransac.find_max*");
112 unsigned int maxThis = 0, maxOther = 0;
113 for (
const auto& in_correspondence : in_correspondences)
115 maxThis = max(maxThis, in_correspondence.this_idx);
116 maxOther = max(maxOther, in_correspondence.other_idx);
119 timlog.leave(
"ransac.find_max*");
123 timlog.enter(
"ransac.count_unique_corrs");
127 std::vector<bool> hasCorrThis(maxThis + 1,
false);
128 std::vector<bool> hasCorrOther(maxOther + 1,
false);
129 unsigned int howManyDifCorrs = 0;
130 for (
const auto& in_correspondence : in_correspondences)
132 if (!hasCorrThis[in_correspondence.this_idx] &&
133 !hasCorrOther[in_correspondence.other_idx])
135 hasCorrThis[in_correspondence.this_idx] =
true;
136 hasCorrOther[in_correspondence.other_idx] =
true;
141 timlog.leave(
"ransac.count_unique_corrs");
145 results.transformation.clear();
149 if (howManyDifCorrs <
params.ransac_minSetSize)
152 results.transformation.clear();
157 #ifdef AVOID_MULTIPLE_CORRESPONDENCES 164 std::vector<std::vector<int>> listDuplicatedLandmarksThis(maxThis + 1);
166 for (k = 0; k < nCorrs - 1; k++)
168 std::vector<int> duplis;
169 for (
unsigned j = k; j < nCorrs - 1; j++)
171 if (in_correspondences[k].this_x == in_correspondences[j].this_x &&
172 in_correspondences[k].this_y == in_correspondences[j].this_y &&
173 in_correspondences[k].this_z == in_correspondences[j].this_z)
174 duplis.push_back(in_correspondences[j].this_idx);
176 listDuplicatedLandmarksThis[in_correspondences[k].this_idx] = duplis;
179 std::vector<std::vector<int>> listDuplicatedLandmarksOther(maxOther + 1);
180 for (k = 0; k < nCorrs - 1; k++)
182 std::vector<int> duplis;
183 for (
unsigned j = k; j < nCorrs - 1; j++)
185 if (in_correspondences[k].other_x ==
186 in_correspondences[j].other_x &&
187 in_correspondences[k].other_y ==
188 in_correspondences[j].other_y &&
189 in_correspondences[k].other_z == in_correspondences[j].other_z)
190 duplis.push_back(in_correspondences[j].other_idx);
192 listDuplicatedLandmarksOther[in_correspondences[k].other_idx] = duplis;
196 std::deque<TMatchingPairList> alreadyAddedSubSets;
201 const double ransac_consistency_test_chi2_quantile = 0.99;
202 const double chi2_thres_dim1 =
208 size_t largest_consensus_yet = 0;
209 double largestSubSet_RMSE = std::numeric_limits<double>::max();
212 const bool use_dynamic_iter_number =
results.ransac_iters == 0;
213 if (use_dynamic_iter_number)
216 params.probability_find_good_model > 0 &&
217 params.probability_find_good_model < 1);
223 std::vector<bool> alreadySelectedThis, alreadySelectedOther;
225 if (!
params.ransac_algorithmForLandmarks)
227 alreadySelectedThis.assign(maxThis + 1,
false);
228 alreadySelectedOther.assign(maxOther + 1,
false);
234 std::vector<size_t> corrsIdxs(nCorrs), corrsIdxsPermutation;
235 for (
size_t i = 0; i < nCorrs; i++) corrsIdxs[i] = i;
238 for (iter_idx = 0; iter_idx <
results.ransac_iters;
242 CTimeLoggerEntry tle(timlog,
"ransac.iter");
246 timlog.enter(
"ransac.permute");
251 timlog.leave(
"ransac.permute");
257 if (
params.ransac_algorithmForLandmarks)
260 timlog.enter(
"ransac.reset_selection_marks");
262 alreadySelectedThis.assign(maxThis + 1,
false);
263 alreadySelectedOther.assign(maxOther + 1,
false);
265 timlog.leave(
"ransac.reset_selection_marks");
278 timlog.enter(
"ransac.inner_loops");
280 for (
unsigned int j = 0;
281 j < nCorrs && subSet.size() <
params.ransac_maxSetSize; j++)
283 const size_t idx = corrsIdxsPermutation[j];
288 if (alreadySelectedThis[corr_j.
this_idx] ||
293 if (
params.user_individual_compat_callback)
298 if (!
params.user_individual_compat_callback(pm))
302 if (subSet.size() < 2)
308 subSet.push_back(corr_j);
309 markAsPicked(corr_j, alreadySelectedThis, alreadySelectedOther);
311 if (subSet.size() == 2)
319 const double corrs_dist1 =
321 subSet[0].this_x, subSet[0].this_y,
322 subSet[1].this_x, subSet[1].this_y);
324 const double corrs_dist2 =
326 subSet[0].other_x, subSet[0].other_y,
327 subSet[1].other_x, subSet[1].other_y);
331 const double corrs_dist_chi2 =
336 bool is_acceptable = (corrs_dist_chi2 < chi2_thres_dim1);
349 (referenceEstimation.
cov(2, 2) <
357 subSet.erase(subSet.begin() + (subSet.size() - 1));
363 corr_j, alreadySelectedThis, alreadySelectedOther);
370 timlog.enter(
"ransac.test_consistency");
390 const bool passTest =
391 maha_dist <
params.ransac_mahalanobisDistanceThreshold;
396 subSet.push_back(corr_j);
398 corr_j, alreadySelectedThis, alreadySelectedOther);
403 timlog.leave(
"ransac.test_consistency");
409 timlog.leave(
"ransac.inner_loops");
412 const bool has_to_eval_RMSE =
413 (subSet.size() >=
params.ransac_minSetSize);
417 double this_subset_RMSE = 0;
418 if (has_to_eval_RMSE)
421 CTimeLoggerEntry tle(timlog,
"ransac.comp_rmse");
429 for (
size_t k = 0; k < subSet.size(); k++)
433 subSet[k].other_x, subSet[k].other_y, gx, gy);
436 mrpt::math::distanceSqrBetweenPoints<double>(
437 subSet[k].this_x, subSet[k].this_y, gx, gy);
439 this_subset_RMSE /= std::max(static_cast<size_t>(1), subSet.size());
443 this_subset_RMSE = std::numeric_limits<double>::max();
449 if (subSet.size() >=
params.ransac_minSetSize)
458 if (!
params.ransac_fuseByCorrsMatch)
462 for (
size_t i = 0; i <
results.transformation.size(); i++)
465 results.transformation.get(i).mean.distanceTo(
466 referenceEstimation.
mean);
468 results.transformation.get(i).mean.phi() -
469 referenceEstimation.
mean.
phi()));
470 if (diffXY <
params.ransac_fuseMaxDiffXY &&
471 diffPhi <
params.ransac_fuseMaxDiffPhi)
489 for (
size_t i = 0; i < alreadyAddedSubSets.size(); i++)
491 if (subSet == alreadyAddedSubSets[i])
499 if (indexFound != -1)
502 if (
params.ransac_algorithmForLandmarks)
503 results.transformation.get(indexFound).log_w = log(
504 1 + exp(
results.transformation.get(indexFound).log_w));
506 results.transformation.get(indexFound).log_w =
508 exp(
results.transformation.get(indexFound).log_w));
513 alreadyAddedSubSets.push_back(subSet);
516 if (
params.ransac_algorithmForLandmarks)
517 newSOGMode.
log_w = 0;
519 newSOGMode.
log_w = log(static_cast<double>(subSet.size()));
521 newSOGMode.
mean = referenceEstimation.
mean;
522 newSOGMode.
cov = referenceEstimation.
cov;
525 results.transformation.push_back(newSOGMode);
529 const size_t ninliers = subSet.size();
530 if (largest_consensus_yet < ninliers)
532 largest_consensus_yet = ninliers;
535 if (use_dynamic_iter_number)
540 const double fracinliers =
542 static_cast<double>(howManyDifCorrs);
544 1 - pow(fracinliers, static_cast<double>(
547 pNoOutliers = std::max(
548 std::numeric_limits<double>::epsilon(),
550 pNoOutliers = std::min(
551 1.0 - std::numeric_limits<double>::epsilon(),
555 log(1 -
params.probability_find_good_model) /
558 results.ransac_iters = std::max(
562 cout <<
"[tfest::RANSAC] Iter #" << iter_idx
563 <<
":est. # iters=" <<
results.ransac_iters
564 <<
" pNoOutliers=" << pNoOutliers
565 <<
" #inliers: " << ninliers << endl;
570 if (subSet.size() >=
params.ransac_minSetSize &&
571 this_subset_RMSE < largestSubSet_RMSE)
574 cout <<
"[tfest::RANSAC] Iter #" << iter_idx
575 <<
" Better subset: " << subSet.size()
576 <<
" inliers, RMSE=" << this_subset_RMSE << endl;
578 results.largestSubSet = subSet;
579 largestSubSet_RMSE = this_subset_RMSE;
583 if (subSet.size() >=
params.ransac_minSetSize &&
584 this_subset_RMSE < MAX_RMSE_TO_END)
590 timlog.leave(
"ransac.iter");
595 cout <<
"[tfest::RANSAC] Finished after " << iter_idx
599 results.transformation.normalizeWeights();
604 printf(
"nCorrs=%u\n", static_cast<unsigned int>(nCorrs));
605 printf(
"Saving '_debug_in_correspondences.txt'...");
606 in_correspondences.dumpToFile(
"_debug_in_correspondences.txt");
607 printf(
"Ok\n"); printf(
"Saving '_debug_results.transformation.txt'...");
608 results.transformation.saveToTextFile(
609 "_debug_results.transformation.txt");
A namespace of pseudo-random numbers generators of diferent distributions.
void permuteVector(const VEC &in_vector, VEC &out_result)
Returns a random permutation of a vector: all the elements of the input vector are in the output but ...
CPose2D mean
The mean value.
const float normalizationStd
The struct for each mode:
A gaussian distribution for 2D points.
void markAsPicked(const TMatchingPair &c, std::vector< bool > &alreadySelectedThis, std::vector< bool > &alreadySelectedOther)
bool se2_l2(const mrpt::tfest::TMatchingPairList &in_correspondences, mrpt::math::TPose2D &out_transformation, mrpt::math::CMatrixDouble33 *out_estimateCovariance=nullptr)
Least-squares (L2 norm) solution to finding the optimal SE(2) (x,y,yaw) between two reference frames...
Parameters for se2_l2_robust().
mrpt::vision::TStereoCalibParams params
void composePoint(const mrpt::math::TPoint2D &l, CPoint2DPDFGaussian &g) const
Returns the PDF of the 2D point with "q"=this pose and "l" a point without uncertainty.
#define MRPT_END_WITH_CLEAN_UP(stuff)
void composePoint(double lx, double ly, double &gx, double &gy) const
An alternative, slightly more efficient way of doing with G and L being 2D points and P this 2D pose...
mrpt::math::CMatrixDouble33 cov
The 3x3 covariance matrix.
#define ASSERT_(f)
Defines an assertion mechanism.
This base provides a set of functions for maths stuff.
bool se2_l2_robust(const mrpt::tfest::TMatchingPairList &in_correspondences, const double in_normalizationStd, const TSE2RobustParams &in_ransac_params, TSE2RobustResult &out_results)
Robust least-squares (L2 norm) solution to finding the optimal SE(2) (x,y,yaw) between two reference ...
map< string, CVectorDouble > results
Declares a class that represents a Probability Density function (PDF) of a 2D pose ...
mrpt::system::CTimeLogger CTimeLogger
double phi() const
Get the phi angle of the 2D pose (in radians)
constexpr double DEG2RAD(const double x)
Degrees to radians.
mrpt::math::CMatrixDouble33 cov
double mahalanobisDistanceToPoint(const double x, const double y) const
Returns the Mahalanobis distance from this PDF to some point.
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
A structure for holding correspondences between two sets of points or points-like entities in 2D or 3...
return_t square(const num_t x)
Inline function for the square of a number.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
double chi2inv(double P, unsigned int dim=1)
The "quantile" of the Chi-Square distribution, for dimension "dim" and probability 0<P<1 (the inverse...
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
T distanceBetweenPoints(const T x1, const T y1, const T x2, const T y2)
Returns the distance between 2 points in 2D.
bool verbose
Show progress messages to std::cout console (default=true)
CRandomGenerator & getRandomGenerator()
A static instance of a CRandomGenerator class, for use in single-thread applications.
double log_w
The log-weight.
Functions for estimating the optimal transformation between two frames of references given measuremen...
For each individual-compatibility (IC) test, the indices of the candidate match between elements in b...
Output placeholder for se2_l2_robust()
int round(const T value)
Returns the closer integer (int) to x.