21 #include <mrpt/core/exceptions.h>
22 #include <mrpt/core/get_env.h>
23 #include <mrpt/maps/CSimplePointsMap.h>
24 #include <mrpt/poses/CPose3D.h>
25 #include <mrpt/poses/CPose3DQuat.h>
26 #include <mrpt/poses/Lie/SE.h>
27 #include <mrpt/poses/Lie/SO.h>
28 #include <mrpt/random.h>
29 #include <mrpt/system/CTimeLogger.h>
30 #include <mrpt/system/filesystem.h>
31 #include <mrpt/version.h>
33 #include <Eigen/Dense>
39 int NUM_REPS = mrpt::get_env<int>(
"NUM_REPS", 3);
41 bool DO_PRINT_ALL = mrpt::get_env<bool>(
"DO_PRINT_ALL",
false);
47 const std::string& matcherName,
int pointDecimation)
49 using namespace mrpt::poses::Lie;
51 const auto fileFullPath = datasetDir + inFile;
55 if (pointDecimation > 1)
57 auto decimPts = mrpt::maps::CSimplePointsMap::Create();
58 for (
size_t i = 0; i < pts->size(); i += pointDecimation)
61 pts->getPoint(i,
x, y, z);
62 decimPts->insertPoint(
x, y, z);
67 std::cout <<
"Running " << icpClassName <<
"|" << solverName <<
"|" << matcherName
68 <<
" test on: " << inFile <<
" with " << pts->size() <<
" points\n";
70 double outliers_ratio = 0;
71 bool use_robust =
true;
74 "test_icp_Model=%s_Algo=%s_%s_%s_outliers=%06.03f_robust=%i", inFile.c_str(),
75 icpClassName.c_str(), solverName.c_str(), matcherName.c_str(), outliers_ratio,
78 const auto bbox = pts->boundingBox();
79 const auto bbox_size = bbox.max - bbox.min;
81 const double max_dim = mrpt::max3(bbox_size.x, bbox_size.y, bbox_size.z);
83 const double f = 0.15;
85 mrpt::system::CTicTac
timer;
88 mrpt::math::CMatrixDouble stats(NUM_REPS, 2 + 2 + 1);
90 for (
int rep = 0; rep < NUM_REPS; rep++)
93 auto&
rnd = mrpt::random::getRandomGenerator();
94 const double Dx =
rnd.drawUniform(-
f * bbox_size.x,
f * bbox_size.x);
95 const double Dy =
rnd.drawUniform(-
f * bbox_size.y,
f * bbox_size.y);
96 const double Dz =
rnd.drawUniform(-
f * bbox_size.z,
f * bbox_size.z);
97 const double yaw = mrpt::DEG2RAD(
rnd.drawUniform(-10.0, 10.0));
98 const double pitch = mrpt::DEG2RAD(
rnd.drawUniform(-10.0, 10.0));
99 const double roll = mrpt::DEG2RAD(
rnd.drawUniform(-10.0, 10.0));
101 const auto gt_pose = mrpt::poses::CPose3D(Dx, Dy, Dz, yaw, pitch, roll);
103 stats(rep, 0) = SO<3>::log(gt_pose.getRotationMatrix()).norm();
104 stats(rep, 1) = gt_pose.norm();
106 auto pts_reg = mrpt::maps::CSimplePointsMap::Create();
107 pts_reg->changeCoordinatesReference(*pts, -gt_pose);
111 pc_ref.
layers[
"raw"] = pts;
112 pc_mod.
layers[
"raw"] = pts_reg;
114 const auto init_guess = mrpt::math::TPose3D::Identity();
116 mp2p_icp::ICP::Ptr icp =
117 std::dynamic_pointer_cast<mp2p_icp::ICP>(mrpt::rtti::classFactory(icpClassName));
121 "Could not create object of type `%s`, is it registered?", icpClassName.c_str());
124 if (!solverName.empty())
126 mp2p_icp::Solver::Ptr solver =
127 std::dynamic_pointer_cast<mp2p_icp::Solver>(mrpt::rtti::classFactory(solverName));
131 "Could not create Solver of type `%s`, is it registered?", solverName.c_str());
133 icp->solvers().clear();
134 icp->solvers().push_back(solver);
138 if (!matcherName.empty())
140 mp2p_icp::Matcher::Ptr matcher =
141 std::dynamic_pointer_cast<mp2p_icp::Matcher>(mrpt::rtti::classFactory(matcherName));
145 "Could not create Matcher of type `%s`, is it registered?",
146 matcherName.c_str());
148 icp->matchers().push_back(matcher);
152 if (!icp->matchers().empty())
154 if (
auto m = std::dynamic_pointer_cast<mp2p_icp::Matcher_Points_DistanceThreshold>(
155 icp->matchers().at(0));
158 mrpt::containers::yaml ps;
159 ps[
"threshold"] = 0.40 * max_dim;
160 ps[
"thresholdAngularDeg"] = 0;
165 std::dynamic_pointer_cast<mp2p_icp::Matcher_Point2Plane>(icp->matchers().at(0));
168 mrpt::containers::yaml ps;
169 ps[
"distanceThreshold"] = 0.05 * max_dim;
170 ps[
"searchRadius"] = 0.20 * max_dim;
171 ps[
"planeEigenThreshold"] = 10.0;
172 ps[
"minimumPlanePoints"] = 5;
187 icp->align(pc_mod, pc_ref, init_guess, icp_params, icp_results);
189 const double dt =
timer.Tac();
191 const auto pos_error = gt_pose - icp_results.
optimal_tf.mean;
192 const auto err_log_n = SO<3>::log(pos_error.getRotationMatrix()).norm();
193 const auto err_xyz = pos_error.norm();
194 const auto err_se3 = SE<3>::log(pos_error).norm();
196 stats(rep, 2 + 0) = err_log_n;
197 stats(rep, 2 + 1) = err_xyz;
198 stats(rep, 2 + 2) = dt;
202 std::cout <<
"GT pose : " << gt_pose.asString() <<
"\n";
203 std::cout <<
"ICP pose : " << icp_results.
optimal_tf.mean.asString() <<
"\n";
204 std::cout <<
"Error SE(3) : " << err_se3 <<
"\n";
205 std::cout <<
"ICP pose stddev: "
213 std::cout <<
"ICP quality : " << icp_results.
quality <<
"\n";
214 std::cout <<
"ICP iterations : " << icp_results.
nIterations <<
"\n";
216 ASSERT_LT_(err_se3, 0.1);
221 stats.saveToTextFile(
222 mrpt::system::fileNameStripInvalidChars(tstName) +
std::string(
".txt"),
223 mrpt::math::MATRIX_FORMAT_ENG,
true,
224 "% Columns: norm GT_rot, norm_GT_XYZ, norm(SO3_error) "
225 "norm(XYZ_error) icp_time\n\n");
230 int main([[maybe_unused]]
int argc, [[maybe_unused]]
char** argv)
234 auto&
rnd = mrpt::random::getRandomGenerator();
237 const std::vector<const char*> lst_files{
238 {
"bunny_decim.xyz.gz",
"happy_buddha_decim.xyz.gz"}};
241 std::vector<std::tuple<
const char*,
const char*,
const char*,
int >>;
243 lst_algos_t lst_algos = {
244 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_Horn",
"mp2p_icp::Matcher_Points_DistanceThreshold", 10},
245 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_Horn",
"mp2p_icp::Matcher_Points_InlierRatio", 10},
248 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_OLAE",
"mp2p_icp::Matcher_Points_DistanceThreshold", 10},
249 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_OLAE",
"mp2p_icp::Matcher_Points_InlierRatio", 10},
252 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_GaussNewton",
"mp2p_icp::Matcher_Points_DistanceThreshold", 10},
253 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_GaussNewton",
"mp2p_icp::Matcher_Points_InlierRatio", 10},
259 #if 0 // Disabled for now: we now need to initialize from a YAML file:
261 lst_algos.push_back({
"mp2p_icp::ICP_LibPointmatcher",
"",
"", 1});
264 for (
const auto& algo : lst_algos)
265 for (
const auto& fil : lst_files)
267 fil, std::get<0>(algo), std::get<1>(algo), std::get<2>(algo),
270 catch (std::exception& e)
272 std::cerr << mrpt::exception_to_str(e) <<
"\n";