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>
36 static int NUM_REPS = mrpt::get_env<int>(
"NUM_REPS", 3);
38 mrpt::get_env<bool>(
"DO_SAVE_STAT_FILES",
false);
39 static bool DO_PRINT_ALL = mrpt::get_env<bool>(
"DO_PRINT_ALL",
false);
48 using namespace mrpt::poses::Lie;
52 mrpt::maps::CSimplePointsMap::Ptr pts =
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 <<
"|"
68 << matcherName <<
" test on: " << inFile <<
" with "
69 << pts->size() <<
" points\n";
71 double outliers_ratio = 0;
72 bool use_robust =
true;
75 "test_icp_Model=%s_Algo=%s_%s_%s_outliers=%06.03f_robust=%i",
76 inFile.c_str(), icpClassName.c_str(), solverName.c_str(),
77 matcherName.c_str(), outliers_ratio, use_robust ? 1 : 0);
79 const auto bbox = pts->boundingBox();
80 const auto bbox_size = bbox.max - bbox.min;
82 const double max_dim = mrpt::max3(bbox_size.x, bbox_size.y, bbox_size.z);
84 const double f = 0.15;
86 mrpt::system::CTicTac
timer;
89 mrpt::math::CMatrixDouble stats(
NUM_REPS, 2 + 2 + 1);
91 for (
int rep = 0; rep <
NUM_REPS; rep++)
94 auto&
rnd = mrpt::random::getRandomGenerator();
95 const double Dx =
rnd.drawUniform(-
f * bbox_size.x,
f * bbox_size.x);
96 const double Dy =
rnd.drawUniform(-
f * bbox_size.y,
f * bbox_size.y);
97 const double Dz =
rnd.drawUniform(-
f * bbox_size.z,
f * bbox_size.z);
98 const double yaw = mrpt::DEG2RAD(
rnd.drawUniform(-10.0, 10.0));
99 const double pitch = mrpt::DEG2RAD(
rnd.drawUniform(-10.0, 10.0));
100 const double roll = mrpt::DEG2RAD(
rnd.drawUniform(-10.0, 10.0));
102 const auto gt_pose = mrpt::poses::CPose3D(Dx, Dy, Dz, yaw, pitch, roll);
104 stats(rep, 0) = SO<3>::log(gt_pose.getRotationMatrix()).norm();
105 stats(rep, 1) = gt_pose.norm();
107 auto pts_reg = mrpt::maps::CSimplePointsMap::Create();
108 pts_reg->changeCoordinatesReference(*pts, -gt_pose);
112 pc_ref.
layers[
"raw"] = pts;
113 pc_mod.
layers[
"raw"] = pts_reg;
115 const auto init_guess = mrpt::math::TPose3D::Identity();
117 mp2p_icp::ICP::Ptr icp = std::dynamic_pointer_cast<mp2p_icp::ICP>(
118 mrpt::rtti::classFactory(icpClassName));
122 "Could not create object of type `%s`, is it registered?",
123 icpClassName.c_str());
126 if (!solverName.empty())
128 mp2p_icp::Solver::Ptr solver =
129 std::dynamic_pointer_cast<mp2p_icp::Solver>(
130 mrpt::rtti::classFactory(solverName));
134 "Could not create Solver of type `%s`, is it registered?",
137 icp->solvers().clear();
138 icp->solvers().push_back(solver);
142 if (!matcherName.empty())
144 mp2p_icp::Matcher::Ptr matcher =
145 std::dynamic_pointer_cast<mp2p_icp::Matcher>(
146 mrpt::rtti::classFactory(matcherName));
150 "Could not create Matcher of type `%s`, is it registered?",
151 matcherName.c_str());
153 icp->matchers().push_back(matcher);
157 if (!icp->matchers().empty())
159 if (
auto m = std::dynamic_pointer_cast<
161 icp->matchers().at(0));
164 mrpt::containers::yaml ps;
165 ps[
"threshold"] = 0.40 * max_dim;
166 ps[
"thresholdAngularDeg"] = 0;
171 std::dynamic_pointer_cast<mp2p_icp::Matcher_Point2Plane>(
172 icp->matchers().at(0));
175 mrpt::containers::yaml ps;
176 ps[
"distanceThreshold"] = 0.05 * max_dim;
177 ps[
"searchRadius"] = 0.20 * max_dim;
178 ps[
"planeEigenThreshold"] = 10.0;
179 ps[
"minimumPlanePoints"] = 5;
194 icp->align(pc_mod, pc_ref, init_guess, icp_params, icp_results);
196 const double dt =
timer.Tac();
198 const auto pos_error = gt_pose - icp_results.
optimal_tf.mean;
199 const auto err_log_n = SO<3>::log(pos_error.getRotationMatrix()).norm();
200 const auto err_xyz = pos_error.norm();
201 const auto err_se3 = SE<3>::log(pos_error).norm();
203 stats(rep, 2 + 0) = err_log_n;
204 stats(rep, 2 + 1) = err_xyz;
205 stats(rep, 2 + 2) = dt;
209 std::cout <<
"GT pose : " << gt_pose.asString() <<
"\n";
210 std::cout <<
"ICP pose : "
211 << icp_results.
optimal_tf.mean.asString() <<
"\n";
212 std::cout <<
"Error SE(3) : " << err_se3 <<
"\n";
213 std::cout <<
"ICP pose stddev: "
221 std::cout <<
"ICP quality : " << icp_results.
quality <<
"\n";
222 std::cout <<
"ICP iterations : " << icp_results.
nIterations <<
"\n";
224 ASSERT_LT_(err_se3, 0.1);
229 stats.saveToTextFile(
230 mrpt::system::fileNameStripInvalidChars(tstName) +
232 mrpt::math::MATRIX_FORMAT_ENG,
true,
233 "% Columns: norm GT_rot, norm_GT_XYZ, norm(SO3_error) "
234 "norm(XYZ_error) icp_time\n\n");
237 int main([[maybe_unused]]
int argc, [[maybe_unused]]
char** argv)
241 auto&
rnd = mrpt::random::getRandomGenerator();
244 const std::vector<const char*> lst_files{
245 {
"bunny_decim.xyz.gz",
"happy_buddha_decim.xyz.gz"}};
247 using lst_algos_t = std::vector<std::tuple<
248 const char*,
const char*,
const char*,
int >>;
250 lst_algos_t lst_algos = {
251 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_Horn",
"mp2p_icp::Matcher_Points_DistanceThreshold", 10},
252 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_Horn",
"mp2p_icp::Matcher_Points_InlierRatio", 10},
255 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_OLAE",
"mp2p_icp::Matcher_Points_DistanceThreshold", 10},
256 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_OLAE",
"mp2p_icp::Matcher_Points_InlierRatio", 10},
259 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_GaussNewton",
"mp2p_icp::Matcher_Points_DistanceThreshold", 10},
260 {
"mp2p_icp::ICP",
"mp2p_icp::Solver_GaussNewton",
"mp2p_icp::Matcher_Points_InlierRatio", 10},
266 #if 0 // Disabled for now: we now need to initialize from a YAML file:
268 lst_algos.push_back({
"mp2p_icp::ICP_LibPointmatcher",
"",
"", 1});
271 for (
const auto& algo : lst_algos)
272 for (
const auto& fil : lst_files)
274 fil, std::get<0>(algo), std::get<1>(algo),
275 std::get<2>(algo), std::get<3>(algo));
277 catch (std::exception& e)
279 std::cerr << mrpt::exception_to_str(e) <<
"\n";