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";