test-mp2p_optimal_tf_algos.cpp
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  * A Modular Optimization framework for Localization and mApping (MOLA)
3  * Copyright (C) 2018-2021 Jose Luis Blanco, University of Almeria
4  * See LICENSE for license information.
5  * ------------------------------------------------------------------------- */
6 
17 #include <mrpt/core/exceptions.h>
18 #include <mrpt/core/get_env.h>
19 #include <mrpt/poses/CPose3D.h>
20 #include <mrpt/poses/CPose3DQuat.h>
21 #include <mrpt/poses/Lie/SO.h>
22 #include <mrpt/random.h>
23 #include <mrpt/system/CTimeLogger.h>
24 #include <mrpt/system/filesystem.h> // fileNameStripInvalidChars()
25 
26 #include <cstdlib>
27 #include <iostream>
28 #include <sstream>
29 
30 // Used to validate OLAE. However, it may make the Gauss-Newton solver, or the
31 // robust kernel with outliers to fail.
32 static bool TEST_LARGE_ROTATIONS = nullptr != ::getenv("TEST_LARGE_ROTATIONS");
33 static bool DO_SAVE_STAT_FILES = nullptr != ::getenv("DO_SAVE_STAT_FILES");
34 static bool DO_PRINT_ALL = nullptr != ::getenv("DO_PRINT_ALL");
35 static bool SKIP_OUTLIERS = nullptr != ::getenv("SKIP_OUTLIERS");
36 static const size_t num_reps = mrpt::get_env<int>("NUM_REPS", 25);
37 
38 using TPoints = std::vector<mrpt::math::TPoint3D>;
39 using TPlanes = std::vector<mp2p_icp::plane_patch_t>;
40 
41 TPoints generate_points(const size_t nPts)
42 {
43  auto& rnd = mrpt::random::getRandomGenerator();
44 
45  TPoints pA;
46  pA.resize(nPts);
47 
48  for (size_t i = 0; i < nPts; i++)
49  {
50  pA[i].x = rnd.drawUniform(0.0, 50.0);
51  pA[i].y = rnd.drawUniform(0.0, 50.0);
52  pA[i].z = rnd.drawUniform(0.0, 50.0);
53  }
54  return pA;
55 }
56 
57 TPlanes generate_planes(const size_t nPlanes)
58 {
59  auto& rnd = mrpt::random::getRandomGenerator();
60 
61  TPlanes plA;
62  plA.resize(nPlanes);
63 
64  for (size_t i = 0; i < nPlanes; i++)
65  {
66  plA[i].centroid.x = rnd.drawUniform(0.0, 50.0);
67  plA[i].centroid.y = rnd.drawUniform(0.0, 50.0);
68  plA[i].centroid.z = rnd.drawUniform(0.0, 50.0);
69 
70  auto n = mrpt::math::TVector3D(
71  rnd.drawUniform(-1.0, 1.0), rnd.drawUniform(-1.0, 1.0),
72  rnd.drawUniform(-1.0, 1.0));
73  n *= 1.0 / n.norm();
74 
75  plA[i].plane = mrpt::math::TPlane(plA[i].centroid, n);
76  }
77  return plA;
78 }
79 
80 // transform features
81 std::tuple<mrpt::poses::CPose3D, std::vector<std::size_t>>
83  const TPoints& pA, TPoints& pB,
84  mrpt::tfest::TMatchingPairList& pointsPairs, const TPlanes& plA,
85  TPlanes& plB, std::vector<mp2p_icp::matched_plane_t>& planePairs,
86  mp2p_icp::MatchedPointPlaneList& pt2plPairs, const double xyz_noise_std,
87  const double n_err_std /* normals noise*/, const double outliers_ratio)
88 {
89  const double outliers_bbox = 50.0;
90  std::vector<std::size_t> gt_outlier_indices;
91 
92  auto& rnd = mrpt::random::getRandomGenerator();
93 
94  double Dx, Dy, Dz, yaw, pitch, roll;
96  {
97  Dx = rnd.drawUniform(10.0, 20.0);
98  Dy = rnd.drawUniform(-30.0, -20.0);
99  Dz = rnd.drawUniform(5.0, 9.0);
100 
101  yaw = mrpt::DEG2RAD(rnd.drawUniform(-180.0, 180.0));
102  pitch = mrpt::DEG2RAD(rnd.drawUniform(-89.0, 89.0));
103  roll = mrpt::DEG2RAD(rnd.drawUniform(-89.0, 89.0));
104  }
105  else
106  {
107  Dx = rnd.drawUniform(-1.0, 1.0);
108  Dy = rnd.drawUniform(-1.0, 1.0);
109  Dz = rnd.drawUniform(-1.0, 1.0);
110 
111  yaw = mrpt::DEG2RAD(rnd.drawUniform(-5.0, 5.0));
112  pitch = mrpt::DEG2RAD(rnd.drawUniform(-5.0, 5.0));
113  roll = mrpt::DEG2RAD(rnd.drawUniform(-5.0, 5.0));
114  }
115 
116  const auto pose = mrpt::poses::CPose3D(Dx, Dy, Dz, yaw, pitch, roll);
117  // just the rotation, to transform vectors (vs. R^3 points):
118  const auto pose_rot_only = mrpt::poses::CPose3D(0, 0, 0, yaw, pitch, roll);
119 
120  // Points:
121  pB.resize(pA.size());
122  for (std::size_t i = 0; i < pA.size(); ++i)
123  {
124  // outlier?
125  const bool is_outlier = (rnd.drawUniform(0.0, 1.0) < outliers_ratio);
126  if (is_outlier) gt_outlier_indices.push_back(i);
127 
128  if (!is_outlier)
129  {
130  // Transform + noise:
131  pose.inverseComposePoint(pA[i], pB[i]);
132 
133  pB[i].x += rnd.drawGaussian1D(0, xyz_noise_std);
134  pB[i].y += rnd.drawGaussian1D(0, xyz_noise_std);
135  pB[i].z += rnd.drawGaussian1D(0, xyz_noise_std);
136  }
137  else
138  {
139  pB[i].x = rnd.drawUniform(.0, outliers_bbox);
140  pB[i].y = rnd.drawUniform(.0, outliers_bbox);
141  pB[i].z = rnd.drawUniform(.0, outliers_bbox);
142  }
143 
144  // Add pairing:
145  mrpt::tfest::TMatchingPair pair;
146  pair.localIdx = pair.globalIdx = i;
147 
148  pair.global = pA[i];
149  pair.local = pB[i];
150 
151  pointsPairs.push_back(pair);
152  }
153 
154  // Planes: transform + noise
155  plB.resize(plA.size());
156  pt2plPairs.clear();
157  pt2plPairs.reserve(plA.size());
158 
159  for (std::size_t i = 0; i < plA.size(); ++i)
160  {
161  const bool is_outlier = (rnd.drawUniform(0.0, 1.0) < outliers_ratio);
162  if (is_outlier) gt_outlier_indices.push_back(pA.size() + i);
163 
164  if (!is_outlier)
165  {
166  // Centroid: transform + noise
167  plB[i].centroid = pose.inverseComposePoint(plA[i].centroid);
168  }
169  else
170  {
171  // Outlier
172  for (int k = 0; k < 3; k++)
173  plB[i].centroid[k] =
174  rnd.drawUniform(-outliers_bbox, outliers_bbox);
175  }
176 
177  const auto sigma_c = xyz_noise_std;
178  const auto sigma_n = n_err_std;
179 
180  plB[i].centroid.x += rnd.drawGaussian1D(0, sigma_c);
181  plB[i].centroid.y += rnd.drawGaussian1D(0, sigma_c);
182  plB[i].centroid.z += rnd.drawGaussian1D(0, sigma_c);
183 
184  if (!is_outlier)
185  {
186  // Plane: rotate + noise
187  plB[i].plane = plA[i].plane;
188 
189  {
190  const mrpt::math::TVector3D ug = plA[i].plane.getNormalVector();
191  mrpt::math::TVector3D ul;
192  pose_rot_only.inverseComposePoint(ug, ul);
193 
194  auto& coefs = plB[i].plane.coefs;
195 
196  // Generate a random SO(3) rotation: angle \sim Gaussian(0,s_n)
197  if (std::abs(sigma_n) > 1e-9)
198  {
199  // unit vector at an arbitrary direction:
200  auto v = mrpt::math::TVector3D(
201  rnd.drawUniform(-1.0, 1.0), rnd.drawUniform(-1.0, 1.0),
202  rnd.drawUniform(-1.0, 1.0));
203  v *= (1.0 / v.norm());
204 
205  const double rnd_ang = rnd.drawGaussian1D(0, sigma_n);
206  v *= rnd_ang;
207 
208  mrpt::math::CVectorFixed<double, 3> vv;
209  for (int k = 0; k < 3; k++) vv[k] = v[k];
210 
211  const auto R33 = mrpt::poses::Lie::SO<3>::exp(vv);
212  const auto p = mrpt::poses::CPose3D(
213  R33, mrpt::math::CVectorFixed<double, 3>::Zero());
214 
215  // Noisy plane normal:
216  ul = p.rotateVector(ul);
217  }
218 
219  // Ax+By+Cz+D=0
220  coefs[0] = ul.x;
221  coefs[1] = ul.y;
222  coefs[2] = ul.z;
223  coefs[3] = 0; // temporary.
224  plB[i].plane.unitarize();
225 
226  coefs[3] =
227  -(coefs[0] * plB[i].centroid.x +
228  coefs[1] * plB[i].centroid.y +
229  coefs[2] * plB[i].centroid.z);
230  }
231  }
232  else
233  {
234  // Outlier:
235  for (int k = 0; k < 4; k++)
236  plB[i].plane.coefs[k] = rnd.drawUniform(-1.0, 1.0);
237  plB[i].plane.unitarize();
238  }
239 
240  // Add plane-plane pairing:
242  pair.p_global = plA[i];
243  pair.p_local = plB[i];
244  planePairs.push_back(pair);
245 
246  // Add point-plane pairing:
248  pt2pl.pl_global = plA[i];
249  pt2pl.pt_local = mrpt::math::TPoint3Df(
250  plB[i].centroid.x, plB[i].centroid.y, plB[i].centroid.z);
251 
252  pt2plPairs.push_back(pt2pl);
253  }
254 
255  return {pose, gt_outlier_indices};
256 }
257 
259  const size_t numPts, const size_t numLines, const size_t numPlanes,
260  const double xyz_noise_std = .0, const double n_err_std = .0,
261  bool use_robust = false, const double outliers_ratio = .0)
262 {
263  using namespace mrpt::poses::Lie;
264 
265  MRPT_START
266 
267  const std::string tstName = mrpt::format(
268  "test_icp_algos_nPt=%06u_nLin=%06u_nPl=%06u_xyzStd=%.04f_nStd=%."
269  "04f_outliers=%06.03f_robust=%i",
270  static_cast<unsigned int>(numPts), static_cast<unsigned int>(numLines),
271  static_cast<unsigned int>(numPlanes), xyz_noise_std, n_err_std,
272  outliers_ratio, use_robust ? 1 : 0);
273 
274  std::cout << "\n== [TEST] " << tstName << " =================\n";
275 
276  mrpt::system::CTimeLogger profiler;
277  profiler.setMinLoggingLevel(mrpt::system::LVL_ERROR); // to make it quiet
278 
279  // Repeat the test many times, with different random values:
280  mp2p_icp::OptimalTF_Result res_olae, res_horn, res_gn;
281  mrpt::poses::CPose3D gt_pose;
282 
283  const auto max_allowed_error =
284  std::min(1.0, 0.1 + 10 * xyz_noise_std + 50 * n_err_std);
285  // 0.01;
286 
287  // Collect stats: columns are (see write TXT to file code at the bottom)
288  mrpt::math::CMatrixDouble stats(num_reps, 1 + 3 + 3 + 3);
289 
290  double rmse_olea = 0, rmse_horn = 0, rmse_gn = 0;
291  double rmse_xyz_olea = 0, rmse_xyz_horn = 0, rmse_xyz_gn = 0;
292 
293  for (size_t rep = 0; rep < num_reps; rep++)
294  {
295  // The input points & planes
296  const TPoints pA = generate_points(numPts);
297  const TPlanes plA = generate_planes(numPlanes);
298 
299  TPoints pB;
300  TPlanes plB;
301 
302  mrpt::tfest::TMatchingPairList pointPairs;
303  mp2p_icp::MatchedPlaneList planePairs;
305 
306  const auto [this_gt_pose, this_outliers] = transform_points_planes(
307  pA, pB, pointPairs, plA, plB, planePairs, pt2plPairs, xyz_noise_std,
308  n_err_std, outliers_ratio);
309 
310  (void)this_outliers; // unused var
311 
312  stats(rep, 0) = SO<3>::log(gt_pose.getRotationMatrix()).norm();
313 
314 #if 0
315  // Also add the plane-centroid-to-plane-centroid as point-to-point
316  // constraints:
317  for (const auto& p : pt2plPairs)
318  pointPairs.emplace_back(
319  0, 0, /*indices not used here*/ p.pl_this.centroid.x,
320  p.pl_this.centroid.y, p.pl_this.centroid.z, p.pt_other.x,
321  p.pt_other.y, p.pt_other.z);
322 #endif
323 
324  // to show the result of the last iteration at end
325  gt_pose = this_gt_pose;
326 
328 
330  in.paired_pt2pt = pointPairs;
331  in.paired_pl2pl = planePairs;
332 
333  wp.use_scale_outlier_detector = use_robust;
334  if (auto sTh = ::getenv("SCALE_OUTLIER_THRESHOLD"); sTh != nullptr)
335  wp.scale_outlier_threshold = ::atof(sTh);
336 
337  // Only for tests with outliers, and if we are using small rotations,
338  // use the robust kernel, using the identity SE(3) transform as
339  // gross initial guess for the pose:
340  if (!TEST_LARGE_ROTATIONS && outliers_ratio > 0)
341  {
342  wp.use_robust_kernel = true;
343  wp.currentEstimateForRobust = mrpt::poses::CPose3D::Identity();
344  }
345 
346  // ======== TEST: olae_match ========
347  {
348  profiler.enter("olea_match");
349 
350  bool ok = mp2p_icp::optimal_tf_olae(in, wp, res_olae);
351  ASSERT_(ok);
352 
353  // const double dt_last =
354  const auto dt_olea = profiler.leave("olea_match");
355 
356  // Collect stats:
357 
358  // Measure errors in SE(3) if we have many points, in SO(3)
359  // otherwise:
360  const auto pos_error = gt_pose - res_olae.optimalPose;
361  const auto err_log_n =
362  SO<3>::log(pos_error.getRotationMatrix()).norm();
363  const auto err_xyz = pos_error.norm();
364 
365  if (DO_PRINT_ALL ||
366  (outliers_ratio < 1e-5 && err_log_n > max_allowed_error))
367  {
368  std::cout << " -Ground_truth : " << gt_pose.asString() << "\n"
369  << " -OLAE_output : "
370  << res_olae.optimalPose.asString() << "\n -GT_rot:\n"
371  << gt_pose.getRotationMatrix() << "\n -OLAE_rot:\n"
372  << res_olae.optimalPose.getRotationMatrix() << "\n";
373  ASSERT_LT_(err_log_n, max_allowed_error);
374  }
375 
376  stats(rep, 1 + 3 * 0 + 0) = err_log_n;
377  stats(rep, 1 + 3 * 1 + 0) = err_xyz;
378  stats(rep, 1 + 3 * 2 + 0) = dt_olea;
379  rmse_olea += mrpt::square(err_log_n);
380  rmse_xyz_olea += mrpt::square(err_xyz);
381  }
382 
383  // ======== TEST: Classic Horn ========
384  {
385  profiler.enter("se3_l2");
386 
387  bool ok = mp2p_icp::optimal_tf_horn(in, wp, res_horn);
388  ASSERT_(ok);
389 
390  const auto dt_horn = profiler.leave("se3_l2");
391 
392  const auto pos_error = gt_pose - res_horn.optimalPose;
393  const auto err_log_n =
394  SO<3>::log(pos_error.getRotationMatrix()).norm();
395  const auto err_xyz = pos_error.norm();
396 
397  // Don't make the tests fail if we have outliers, since it IS
398  // expected that, sometimes, we don't get to the optimum
399  if (DO_PRINT_ALL ||
400  (outliers_ratio < 1e-5 && err_log_n > max_allowed_error))
401  {
402  std::cout << " -Ground_truth : " << gt_pose.asString() << "\n"
403  << " -Horn_output : "
404  << res_horn.optimalPose.asString() << "\n -GT_rot:\n"
405  << gt_pose.getRotationMatrix() << "\n";
406  ASSERT_LT_(err_log_n, max_allowed_error);
407  }
408 
409  stats(rep, 1 + 3 * 0 + 1) = err_log_n;
410  stats(rep, 1 + 3 * 1 + 1) = err_xyz;
411  stats(rep, 1 + 3 * 2 + 1) = dt_horn;
412 
413  rmse_horn += mrpt::square(err_log_n);
414  rmse_xyz_horn += mrpt::square(err_xyz);
415  }
416 
417  // ======== TEST: GaussNewton method ========
418  {
419  profiler.enter("optimal_tf_gauss_newton");
420 
422  gnParams.verbose = false;
423  // Linearization point: Identity
424  gnParams.linearizationPoint = mrpt::poses::CPose3D();
425 
426  // NOTE: this is an "unfair" comparison, since we only run ONE
427  // iteration of the GN while the other methods are one-shot
428  // solutions. But GN is good enough even so for small rotations to
429  // solve it in just one iteration.
430  bool ok = mp2p_icp::optimal_tf_gauss_newton(in, res_gn, gnParams);
431  ASSERT_(ok);
432 
433  const auto dt_gn = profiler.leave("optimal_tf_gauss_newton");
434 
435  const auto pos_error = gt_pose - res_gn.optimalPose;
436  const auto err_log_n =
437  SO<3>::log(pos_error.getRotationMatrix()).norm();
438  const auto err_xyz = pos_error.norm();
439 
440  // Don't make the tests fail if we have outliers, since it IS
441  // expected that, sometimes, we don't get to the optimum
442  // Also, disable gauss-newton checks for large rotations, as it
443  // fails, and that's expected since it's a local algorithm.
444  if (0)
445  /*
446  !TEST_LARGE_ROTATIONS &&
447  //(DO_PRINT_ALL ||
448  (outliers_ratio < 1e-5 && err_log_n > max_allowed_error)))
449  */
450  {
451  std::cout << " -Ground truth : " << gt_pose.asString()
452  << "\n"
453  << " -GaussNewton output : "
454  << res_gn.optimalPose.asString() << "\n -GT_rot:\n"
455  << gt_pose.getRotationMatrix() << "\n";
456  ASSERT_LT_(err_log_n, max_allowed_error);
457  }
458 
459  stats(rep, 1 + 3 * 0 + 2) = err_log_n;
460  stats(rep, 1 + 3 * 1 + 2) = err_xyz;
461  stats(rep, 1 + 3 * 2 + 2) = dt_gn;
462 
463  rmse_gn += mrpt::square(err_log_n);
464  rmse_xyz_gn += mrpt::square(err_xyz);
465  }
466  } // for each repetition
467 
468  // RMSE:
469  rmse_olea = std::sqrt(rmse_olea / num_reps);
470  rmse_xyz_olea = std::sqrt(rmse_xyz_olea / num_reps);
471  rmse_horn = std::sqrt(rmse_horn / num_reps);
472  rmse_xyz_horn = std::sqrt(rmse_xyz_horn / num_reps);
473  rmse_gn = std::sqrt(rmse_gn / num_reps);
474  rmse_xyz_gn = std::sqrt(rmse_xyz_gn / num_reps);
475 
476  const double dt_olea = profiler.getMeanTime("olea_match");
477  const double dt_horn = profiler.getMeanTime("se3_l2");
478  const double dt_gn = profiler.getMeanTime("optimal_tf_gauss_newton");
479 
480  std::cout << " -Ground_truth: " << gt_pose.asString() << "\n"
481  << " -OLAE output : " << res_olae.optimalPose.asString() << " ("
482  << res_olae.outliers.size() << " outliers detected)\n"
483  << " -Horn output : " << res_horn.optimalPose.asString() << "\n"
484  << " -GN output : " << res_gn.optimalPose.asString()
485  << "\n"
486  // clang-format off
487  << " -OLAE : " << mrpt::format("SO3 rmse=%e XYZ rmse=%e time=%7.03f us\n",rmse_olea, rmse_xyz_olea, dt_olea * 1e6)
488  << " -Horn : " << mrpt::format("SO3 rmse=%e XYZ rmse=%e time=%7.03f us\n",rmse_horn, rmse_xyz_horn, dt_horn * 1e6)
489  << " -Gauss-Newton: " << mrpt::format("SO3 rmse=%e XYZ rmse=%e time=%7.03f us\n",rmse_gn, rmse_xyz_gn, dt_gn * 1e6);
490  // clang-format on
491 
492  if (DO_SAVE_STAT_FILES)
493  stats.saveToTextFile(
494  mrpt::system::fileNameStripInvalidChars(tstName) +
495  std::string(".txt"),
496  mrpt::math::MATRIX_FORMAT_ENG, true,
497  "% Columns: execution time x 3, norm(SO3_error) x3, "
498  "norm(XYZ_error) x3 (OLAE, Horn, GaussNewton)\n\n");
499 
500  return true; // all ok.
501  MRPT_END
502 }
503 
504 int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv)
505 {
506  try
507  {
508  auto& rnd = mrpt::random::getRandomGenerator();
509  rnd.randomize(1234); // for reproducible tests
510 
511  const double nXYZ = 0.001; // [meters] std. noise of XYZ points
512  const double nN = mrpt::DEG2RAD(0.5); // normals noise
513 
514  // arguments: nPts, nLines, nPlanes
515  // Points only. Noiseless:
516  ASSERT_(test_icp_algos(3 /*pt*/, 0 /*li*/, 0 /*pl*/));
517  ASSERT_(test_icp_algos(4 /*pt*/, 0 /*li*/, 0 /*pl*/));
518  ASSERT_(test_icp_algos(10 /*pt*/, 0 /*li*/, 0 /*pl*/));
519  ASSERT_(test_icp_algos(100 /*pt*/, 0 /*li*/, 0 /*pl*/));
520  ASSERT_(test_icp_algos(1000 /*pt*/, 0 /*li*/, 0 /*pl*/));
521 
522  // Points only. Noisy:
523  ASSERT_(test_icp_algos(100 /*pt*/, 0 /*li*/, 0 /*pl*/, nXYZ));
524  ASSERT_(test_icp_algos(1000 /*pt*/, 0 /*li*/, 0 /*pl*/, nXYZ));
525 
526  // Planes + 1 pt. Noiseless:
527  ASSERT_(test_icp_algos(2 /*pt*/, 0 /*li*/, 1 /*pl*/));
528  ASSERT_(test_icp_algos(2 /*pt*/, 0 /*li*/, 10 /*pl*/));
529  ASSERT_(test_icp_algos(2 /*pt*/, 0 /*li*/, 100 /*pl*/));
530 
531  // Points and planes, noisy.
532  ASSERT_(test_icp_algos(2 /*pt*/, 0 /*li*/, 1 /*pl*/, nXYZ, nN));
533  ASSERT_(test_icp_algos(10 /*pt*/, 0 /*li*/, 10 /*pl*/, nXYZ, nN));
534  ASSERT_(test_icp_algos(100 /*pt*/, 0 /*li*/, 100 /*pl*/, nXYZ, nN));
535 
536  if (!SKIP_OUTLIERS)
537  {
538  // Points only. Noisy w. outliers:
539  for (int robust = 0; robust <= 1; robust++)
540  for (double Or = .025; Or < 0.76; Or += 0.025)
541  ASSERT_(test_icp_algos(
542  200 /*pt*/, 0, 0, nXYZ, .0, robust != 0, Or));
543  }
544  }
545  catch (std::exception& e)
546  {
547  std::cerr << mrpt::exception_to_str(e) << "\n";
548  return 1;
549  }
550 }
mrpt::math::TPoint3Df pt_local
Definition: Pairings.h:55
static bool SKIP_OUTLIERS
std::vector< matched_plane_t > MatchedPlaneList
Definition: Pairings.h:40
std::vector< mp2p_icp::plane_patch_t > TPlanes
plane_patch_t p_global
Definition: Pairings.h:30
::std::string string
Definition: gtest.h:1979
TPoints generate_points(const size_t nPts)
static bool DO_PRINT_ALL
OLAE algorithm to find the SE(3) optimal transformation.
bool optimal_tf_horn(const mp2p_icp::Pairings &in, const WeightParameters &wp, OptimalTF_Result &result)
static const size_t num_reps
static bool TEST_LARGE_ROTATIONS
std::optional< mrpt::poses::CPose3D > linearizationPoint
Simple non-linear optimizer to find the SE(3) optimal transformation.
std::vector< point_plane_pair_t > MatchedPointPlaneList
Definition: Pairings.h:66
std::optional< mrpt::poses::CPose3D > currentEstimateForRobust
ROSCPP_DECL bool ok()
std::tuple< mrpt::poses::CPose3D, std::vector< std::size_t > > transform_points_planes(const TPoints &pA, TPoints &pB, mrpt::tfest::TMatchingPairList &pointsPairs, const TPlanes &plA, TPlanes &plB, std::vector< mp2p_icp::matched_plane_t > &planePairs, mp2p_icp::MatchedPointPlaneList &pt2plPairs, const double xyz_noise_std, const double n_err_std, const double outliers_ratio)
static bool DO_SAVE_STAT_FILES
plane_patch_t pl_global
Definition: Pairings.h:54
std::vector< mrpt::math::TPoint3D > TPoints
plane_patch_t p_local
Definition: Pairings.h:30
TPlanes generate_planes(const size_t nPlanes)
int main([[maybe_unused]] int argc, [[maybe_unused]] char **argv)
mrpt::poses::CPose3D optimalPose
std::size_t size() const
Definition: Pairings.h:197
bool test_icp_algos(const size_t numPts, const size_t numLines, const size_t numPlanes, const double xyz_noise_std=.0, const double n_err_std=.0, bool use_robust=false, const double outliers_ratio=.0)
bool optimal_tf_olae(const Pairings &in, const WeightParameters &wp, OptimalTF_Result &result)
Classic Horn&#39;s solution for optimal SE(3) transformation.
MatchedPlaneList paired_pl2pl
Definition: Pairings.h:105
mrpt::tfest::TMatchingPairList paired_pt2pt
Definition: Pairings.h:101
bool optimal_tf_gauss_newton(const Pairings &in, OptimalTF_Result &result, const OptimalTF_GN_Parameters &gnParams=OptimalTF_GN_Parameters())


mrpt_local_obstacles
Author(s): Jose-Luis Blanco-Claraco
autogenerated on Thu Jun 1 2023 03:06:43