00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "pointmatcher/PointMatcher.h"
00037 #include "../contrib/gtest/gtest.h"
00038
00039 #include <string>
00040
00041 #include <fstream>
00042
00043 #include "boost/filesystem.hpp"
00044 #include "boost/filesystem/path.hpp"
00045 #include "boost/filesystem/operations.hpp"
00046
00047 using namespace std;
00048 using namespace PointMatcherSupport;
00049 using boost::assign::map_list_of;
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 typedef PointMatcher<float> PM;
00063 typedef PM::DataPoints DP;
00064
00065 std::string dataPath;
00066
00067 DP ref2D;
00068 DP data2D;
00069 DP ref3D;
00070 DP data3D;
00071 PM::TransformationParameters validT2d;
00072 PM::TransformationParameters validT3d;
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 TEST(icpTest, icpTest)
00097 {
00098 DP ref = DP::load(dataPath + "cloud.00000.vtk");
00099 DP data = DP::load(dataPath + "cloud.00001.vtk");
00100
00101 namespace fs = boost::filesystem;
00102 fs::path config_dir(dataPath + "icp_data");
00103 EXPECT_TRUE( fs::exists(config_dir) && fs::is_directory(config_dir) );
00104
00105 fs::directory_iterator end_iter;
00106 for( fs::directory_iterator d(config_dir); d != end_iter; ++d)
00107 {
00108 if (!fs::is_regular_file(d->status()) ) continue;
00109
00110
00111 PM::ICP icp;
00112 std::string config_file = d->path().string();
00113 if (fs::extension(config_file) != ".yaml") continue;
00114 std::ifstream ifs(config_file.c_str());
00115 EXPECT_NO_THROW(icp.loadFromYaml(ifs)) << "This error was caused by the test file:" << endl << " " << config_file;
00116
00117
00118 PM::TransformationParameters curT = icp(data, ref);
00119
00120
00121
00122 fs::path cur_file = d->path();
00123 cur_file.replace_extension(".cur_trans");
00124
00125 std::ofstream otfs(cur_file.c_str());
00126 otfs.precision(16);
00127 otfs << curT;
00128 otfs.close();
00129
00130
00131 fs::path ref_file = d->path();
00132 ref_file.replace_extension(".ref_trans");
00133 PM::TransformationParameters refT = 0*curT;
00134
00135 std::ifstream itfs(ref_file.c_str());
00136 for (int row = 0; row < refT.cols(); row++)
00137 {
00138 for (int col = 0; col < refT.cols(); col++)
00139 {
00140 itfs >>refT(row, col);
00141 }
00142 }
00143
00144
00145
00146
00147
00148
00149
00150 double rotTol = 0.1, transTol = 0.1;
00151
00152
00153
00154 PM::TransformationParameters refRot = refT.block(0, 0, 3, 3);
00155 PM::TransformationParameters refTrans = refT.block(0, 3, 3, 1);
00156 PM::TransformationParameters curRot = curT.block(0, 0, 3, 3);
00157 PM::TransformationParameters curTrans = curT.block(0, 3, 3, 1);
00158 PM::TransformationParameters rotErrMat = refRot*(curRot.transpose())
00159 - PM::TransformationParameters::Identity(3, 3);
00160 PM::TransformationParameters transErrMat = refTrans - curTrans;
00161 double rotErr = rotErrMat.array().abs().sum();
00162 double transErr = transErrMat.array().abs().sum();
00163
00164
00165
00166
00167 EXPECT_LT(rotErr, rotTol) << "This error was caused by the test file:" << endl << " " << config_file;
00168 EXPECT_LT(transErr, transTol) << "This error was caused by the test file:" << endl << " " << config_file;
00169 }
00170 }
00171
00172
00173
00174
00175
00176 TEST(PointCloudTest, CopyConstructor2D)
00177 {
00178 const DP ref2DCopy(ref2D);
00179 EXPECT_TRUE(ref2DCopy.features == ref2D.features);
00180 EXPECT_TRUE(ref2DCopy.featureLabels == ref2D.featureLabels);
00181 EXPECT_TRUE(ref2DCopy.descriptors == ref2D.descriptors);
00182 EXPECT_TRUE(ref2DCopy.descriptorLabels == ref2D.descriptorLabels);
00183 EXPECT_TRUE(ref2DCopy == ref2D);
00184 }
00185
00186 TEST(PointCloudTest, CopyConstructor3D)
00187 {
00188 const DP ref3DCopy(ref3D);
00189 EXPECT_TRUE(ref3DCopy.features == ref3D.features);
00190 EXPECT_TRUE(ref3DCopy.featureLabels == ref3D.featureLabels);
00191 EXPECT_TRUE(ref3DCopy.descriptors == ref3D.descriptors);
00192 EXPECT_TRUE(ref3DCopy.descriptorLabels == ref3D.descriptorLabels);
00193 EXPECT_TRUE(ref3DCopy == ref3D);
00194 }
00195
00196 TEST(PointCloudTest, FeatureConstructor2D)
00197 {
00198 const DP ref2DCopy(ref2D.features, ref2D.featureLabels);
00199 EXPECT_TRUE(ref2DCopy.features == ref2D.features);
00200 EXPECT_TRUE(ref2DCopy.featureLabels == ref2D.featureLabels);
00201 EXPECT_TRUE(ref2DCopy == ref2D);
00202 EXPECT_TRUE(ref2DCopy.descriptors.rows() == 0);
00203 EXPECT_TRUE(ref2DCopy.descriptors.cols() == 0);
00204 }
00205
00206 TEST(PointCloudTest, FeatureConstructor3D)
00207 {
00208 const DP ref3DCopy(ref3D.features, ref3D.featureLabels);
00209 EXPECT_TRUE(ref3DCopy.features == ref3D.features);
00210 EXPECT_TRUE(ref3DCopy.featureLabels == ref3D.featureLabels);
00211 EXPECT_TRUE(ref3DCopy == ref3D);
00212 EXPECT_TRUE(ref3DCopy.descriptors.rows() == 0);
00213 EXPECT_TRUE(ref3DCopy.descriptors.cols() == 0);
00214 }
00215
00216 TEST(PointCloudTest, ConcatenateFeatures2D)
00217 {
00218 const int leftPoints(ref2D.features.cols() / 2);
00219 const int rightPoints(ref2D.features.cols() - leftPoints);
00220 DP lefts(
00221 ref2D.features.leftCols(leftPoints),
00222 ref2D.featureLabels
00223 );
00224 DP rights(
00225 ref2D.features.rightCols(rightPoints),
00226 ref2D.featureLabels
00227 );
00228 lefts.concatenate(rights);
00229 EXPECT_TRUE(lefts == ref2D);
00230 }
00231
00232 TEST(PointCloudTest, ConcatenateFeatures3D)
00233 {
00234 const int leftPoints(ref3D.features.cols() / 2);
00235 const int rightPoints(ref3D.features.cols() - leftPoints);
00236 DP lefts(
00237 ref3D.features.leftCols(leftPoints),
00238 ref3D.featureLabels
00239 );
00240 DP rights(
00241 ref3D.features.rightCols(rightPoints),
00242 ref3D.featureLabels
00243 );
00244 lefts.concatenate(rights);
00245 EXPECT_TRUE(lefts == ref3D);
00246 }
00247
00248 TEST(PointCloudTest, ConcatenateDescSame)
00249 {
00250 typedef DP::Label Label;
00251 typedef DP::Labels Labels;
00252
00253 const int leftPoints(ref2D.features.cols() / 2);
00254 const int rightPoints(ref2D.features.cols() - leftPoints);
00255 DP lefts(
00256 ref2D.features.leftCols(leftPoints),
00257 ref2D.featureLabels,
00258 PM::Matrix::Random(5, leftPoints),
00259 Labels(Label("Desc5D", 5))
00260 );
00261 DP rights(
00262 ref2D.features.rightCols(rightPoints),
00263 ref2D.featureLabels,
00264 PM::Matrix::Random(5, rightPoints),
00265 Labels(Label("Desc5D", 5))
00266 );
00267 lefts.concatenate(rights);
00268 EXPECT_TRUE(lefts.descriptors.rows() == 5);
00269 EXPECT_TRUE(lefts.descriptors.cols() == lefts.features.cols());
00270 }
00271
00272 TEST(PointCloudTest, ConcatenateDescSame2)
00273 {
00274 typedef DP::Label Label;
00275 typedef DP::Labels Labels;
00276
00277 DP ref3DCopy(ref3D.features, ref3D.featureLabels);
00278 ref3DCopy.descriptorLabels.push_back(Label("Desc5D", 5));
00279 ref3DCopy.descriptors = PM::Matrix::Random(5, ref3DCopy.features.cols());
00280
00281 const int leftPoints(ref3DCopy.features.cols() / 2);
00282 const int rightPoints(ref3DCopy.features.cols() - leftPoints);
00283 DP lefts(
00284 ref3DCopy.features.leftCols(leftPoints),
00285 ref3DCopy.featureLabels,
00286 ref3DCopy.descriptors.leftCols(leftPoints),
00287 ref3DCopy.descriptorLabels
00288 );
00289 DP rights(
00290 ref3DCopy.features.rightCols(rightPoints),
00291 ref3DCopy.featureLabels,
00292 ref3DCopy.descriptors.rightCols(rightPoints),
00293 ref3DCopy.descriptorLabels
00294 );
00295 lefts.concatenate(rights);
00296 EXPECT_TRUE(lefts == ref3DCopy);
00297 }
00298
00299 TEST(PointCloudTest, ConcatenateDescDiffName)
00300 {
00301 typedef DP::Label Label;
00302 typedef DP::Labels Labels;
00303
00304 const int leftPoints(ref2D.features.cols() / 2);
00305 const int rightPoints(ref2D.features.cols() - leftPoints);
00306 DP lefts(
00307 ref2D.features.leftCols(leftPoints),
00308 ref2D.featureLabels,
00309 PM::Matrix::Random(5, leftPoints),
00310 Labels(Label("MyDesc5D", 5))
00311 );
00312 DP rights(
00313 ref2D.features.rightCols(rightPoints),
00314 ref2D.featureLabels,
00315 PM::Matrix::Random(5, rightPoints),
00316 Labels(Label("YourDesc5D", 5))
00317 );
00318 lefts.concatenate(rights);
00319 EXPECT_TRUE(lefts.descriptors.rows() == 0);
00320 EXPECT_TRUE(lefts.descriptors.cols() == 0);
00321 }
00322
00323 TEST(PointCloudTest, ConcatenateDescDiffSize)
00324 {
00325 typedef DP::Label Label;
00326 typedef DP::Labels Labels;
00327
00328 const int leftPoints(ref2D.features.cols() / 2);
00329 const int rightPoints(ref2D.features.cols() - leftPoints);
00330 DP lefts(
00331 ref2D.features.leftCols(leftPoints),
00332 ref2D.featureLabels,
00333 PM::Matrix::Random(3, leftPoints),
00334 Labels(Label("DescND", 3))
00335 );
00336 DP rights(
00337 ref2D.features.rightCols(rightPoints),
00338 ref2D.featureLabels,
00339 PM::Matrix::Random(5, rightPoints),
00340 Labels(Label("DescND", 5))
00341 );
00342 EXPECT_THROW(lefts.concatenate(rights), DP::InvalidField);
00343 }
00344
00345
00346
00347
00348
00349 TEST(IOTest, loadYaml)
00350 {
00351
00352
00353 std::ifstream ifs0((dataPath + "default-convert.yaml").c_str());
00354 EXPECT_NO_THROW(PM::DataPointsFilters filters(ifs0));
00355
00356
00357 PM::ICP icp;
00358
00359 std::ifstream ifs1((dataPath + "default.yaml").c_str());
00360 EXPECT_NO_THROW(icp.loadFromYaml(ifs1));
00361
00362 std::ifstream ifs2((dataPath + "unit_tests/badIcpConfig_InvalidParameter.yaml").c_str());
00363 EXPECT_THROW(icp.loadFromYaml(ifs2), PointMatcherSupport::Parametrizable::InvalidParameter);
00364
00365 std::ifstream ifs3((dataPath + "unit_tests/badIcpConfig_InvalidModuleType.yaml").c_str());
00366 EXPECT_THROW(icp.loadFromYaml(ifs3), PointMatcherSupport::InvalidModuleType);
00367 }
00368
00369 class IOLoadSaveTest : public testing::Test
00370 {
00371
00372 public:
00373 virtual void SetUp()
00374 {
00375 nbPts = 10;
00376 addRandomFeature("x", 1);
00377 addRandomFeature("y", 1);
00378 addRandomFeature("z", 1);
00379 ptCloud.addFeature("pad", PM::Matrix::Ones(1, nbPts));
00380
00381 addRandomDescriptor("normals",3);
00382 addRandomDescriptor("eigValues",3);
00383 addRandomDescriptor("eigVectors",9);
00384 addRandomDescriptor("color",4);
00385 }
00386
00387 void addRandomFeature(const string& featureName, const int rows)
00388 {
00389 ptCloud.addFeature(featureName,PM::Matrix::Random(rows, nbPts));
00390 }
00391
00392 void addRandomDescriptor(const string& descriptorName, const int rows)
00393 {
00394 ptCloud.addDescriptor(descriptorName, PM::Matrix::Random(rows, nbPts));
00395 }
00396
00397 virtual void loadSaveTest(const string& testFileName, const int nbPts = 10)
00398 {
00399 this->testFileName = testFileName;
00400 ptCloud.save(testFileName);
00401
00402 ptCloudFromFile = DP::load(testFileName);
00403
00404 EXPECT_TRUE(ptCloudFromFile.features.cols() == ptCloud.features.cols());
00405 EXPECT_TRUE(ptCloudFromFile.descriptorExists("normals",3));
00406 EXPECT_TRUE(ptCloudFromFile.getDescriptorViewByName("normals").isApprox(ptCloud.getDescriptorViewByName("normals")));
00407 EXPECT_TRUE(ptCloudFromFile.descriptorExists("eigValues",3));
00408 EXPECT_TRUE(ptCloudFromFile.getDescriptorViewByName("eigValues").isApprox(ptCloud.getDescriptorViewByName("eigValues")));
00409 EXPECT_TRUE(ptCloudFromFile.descriptorExists("eigVectors",9));
00410 EXPECT_TRUE(ptCloudFromFile.getDescriptorViewByName("eigVectors").isApprox(ptCloud.getDescriptorViewByName("eigVectors")));
00411 EXPECT_TRUE(ptCloudFromFile.descriptorExists("color",4));
00412 EXPECT_TRUE(ptCloudFromFile.getDescriptorViewByName("color").isApprox(ptCloud.getDescriptorViewByName("color")));
00413
00414 EXPECT_TRUE(ptCloudFromFile.features.isApprox(ptCloud.features));
00415
00416 }
00417
00418 virtual void TearDown()
00419 {
00420 EXPECT_TRUE(boost::filesystem::remove(boost::filesystem::path(testFileName)));
00421 }
00422
00423
00424 protected:
00425 int nbPts;
00426 DP::Labels featureLabels;
00427 DP ptCloud;
00428 DP ptCloudFromFile;
00429 string testFileName;
00430
00431 };
00432
00433 TEST_F(IOLoadSaveTest, VTK)
00434 {
00435 ptCloud.addDescriptor("genericScalar", PM::Matrix::Random(1, nbPts));
00436 ptCloud.addDescriptor("genericVector", PM::Matrix::Random(3, nbPts));
00437
00438 loadSaveTest("unit_test.vtk");
00439
00440 EXPECT_TRUE(ptCloudFromFile.descriptorExists("genericScalar",1));
00441 EXPECT_TRUE(ptCloudFromFile.descriptorExists("genericVector",3));
00442
00443 }
00444
00445 TEST_F(IOLoadSaveTest, PLY)
00446 {
00447 loadSaveTest("unit_test.ply");
00448 }
00449
00450 TEST_F(IOLoadSaveTest, PCD)
00451 {
00452 loadSaveTest("unit_test.pcd");
00453 }
00454
00455 TEST_F(IOLoadSaveTest, CSV)
00456 {
00457 loadSaveTest("unit_test.csv");
00458 }
00459
00460
00461
00462
00463
00464
00465
00466 class IcpHelper: public testing::Test
00467 {
00468 public:
00469
00470 PM::ICP icp;
00471
00472 PM::Parameters params;
00473
00474 virtual void dumpVTK()
00475 {
00476
00477 icp.inspector.reset(
00478 PM::get().InspectorRegistrar.create(
00479 "VTKFileInspector",
00480 boost::assign::map_list_of
00481 ("baseFileName","./unitTest")
00482 )
00483 );
00484 }
00485
00486 void validate2dTransformation()
00487 {
00488 const PM::TransformationParameters testT = icp(data2D, ref2D);
00489 const int dim = validT2d.cols();
00490
00491 const BOOST_AUTO(validTrans, validT2d.block(0, dim-1, dim-1, 1).norm());
00492 const BOOST_AUTO(testTrans, testT.block(0, dim-1, dim-1, 1).norm());
00493
00494 const BOOST_AUTO(validAngle, acos(validT2d(0,0)));
00495 const BOOST_AUTO(testAngle, acos(testT(0,0)));
00496
00497 EXPECT_NEAR(validTrans, testTrans, 0.05);
00498 EXPECT_NEAR(validAngle, testAngle, 0.05);
00499 }
00500
00501 void validate3dTransformation()
00502 {
00503
00504
00505 const PM::TransformationParameters testT = icp(data3D, ref3D);
00506 const int dim = validT2d.cols();
00507
00508 const BOOST_AUTO(validTrans, validT3d.block(0, dim-1, dim-1, 1).norm());
00509 const BOOST_AUTO(testTrans, testT.block(0, dim-1, dim-1, 1).norm());
00510
00511 const BOOST_AUTO(testRotation, Eigen::Quaternion<float>(Eigen::Matrix<float,3,3>(testT.topLeftCorner(3,3))));
00512 const BOOST_AUTO(validRotation, Eigen::Quaternion<float>(Eigen::Matrix<float,3,3>(validT3d.topLeftCorner(3,3))));
00513
00514 const BOOST_AUTO(angleDist, validRotation.angularDistance(testRotation));
00515
00516
00517
00518
00519 EXPECT_NEAR(validTrans, testTrans, 0.1);
00520 EXPECT_NEAR(angleDist, 0.0, 0.1);
00521
00522 }
00523 };
00524
00525
00526 class GenericTest: public IcpHelper
00527 {
00528
00529 public:
00530
00531
00532 virtual void SetUp()
00533 {
00534 icp.setDefault();
00535
00536
00537 }
00538
00539
00540 virtual void TearDown()
00541 {
00542 }
00543 };
00544
00545
00546
00547
00548
00549
00550 TEST_F(GenericTest, ICP_default)
00551 {
00552 validate2dTransformation();
00553 validate3dTransformation();
00554 }
00555
00556
00557
00558
00559
00560
00561 class DataFilterTest: public IcpHelper
00562 {
00563 public:
00564
00565 virtual void SetUp()
00566 {
00567 icp.setDefault();
00568
00569
00570
00571
00572 icp.readingDataPointsFilters.clear();
00573 }
00574
00575
00576 virtual void TearDown() {}
00577
00578 void addFilter(string name, PM::Parameters params)
00579 {
00580 PM::DataPointsFilter* testedDataPointFilter =
00581 PM::get().DataPointsFilterRegistrar.create(name, params);
00582
00583 icp.readingDataPointsFilters.push_back(testedDataPointFilter);
00584 }
00585
00586 void addFilter(string name)
00587 {
00588 PM::DataPointsFilter* testedDataPointFilter =
00589 PM::get().DataPointsFilterRegistrar.create(name);
00590
00591 icp.readingDataPointsFilters.push_back(testedDataPointFilter);
00592 }
00593 };
00594
00595
00596 TEST_F(DataFilterTest, RemoveNaNDataPointsFilter)
00597 {
00598
00599 DP ref2DCopy(ref2D);
00600 int goodCount(0);
00601 const float nan(std::numeric_limits<float>::quiet_NaN());
00602 for (int i(0); i < ref2DCopy.features.cols(); ++i)
00603 {
00604 if (rand() % 3 == 0)
00605 {
00606 ref2DCopy.features(rand() % ref2DCopy.features.rows(), i) = nan;
00607 }
00608 else
00609 ++goodCount;
00610 }
00611
00612
00613 addFilter("RemoveNaNDataPointsFilter");
00614 icp.readingDataPointsFilters.apply(ref2DCopy);
00615 EXPECT_TRUE(ref2DCopy.features.cols() == goodCount);
00616 }
00617
00618 TEST_F(DataFilterTest, MaxDistDataPointsFilter)
00619 {
00620
00621 params = map_list_of<string,string>
00622 ("dim","0")
00623 ("maxDist", toParam(6.0))
00624 ;
00625
00626
00627 params["dim"] = "0";
00628 icp.readingDataPointsFilters.clear();
00629 addFilter("MaxDistDataPointsFilter", params);
00630 validate2dTransformation();
00631 validate3dTransformation();
00632
00633
00634 params["dim"] = "1";
00635 icp.readingDataPointsFilters.clear();
00636 addFilter("MaxDistDataPointsFilter", params);
00637 validate2dTransformation();
00638 validate3dTransformation();
00639
00640
00641 params["dim"] = "2";
00642 icp.readingDataPointsFilters.clear();
00643 addFilter("MaxDistDataPointsFilter", params);
00644 EXPECT_ANY_THROW(validate2dTransformation());
00645 validate3dTransformation();
00646
00647
00648 params["dim"] = "-1";
00649 icp.readingDataPointsFilters.clear();
00650 addFilter("MaxDistDataPointsFilter", params);
00651 validate2dTransformation();
00652 validate3dTransformation();
00653
00654
00655 params["dim"] = "3";
00656
00657 EXPECT_ANY_THROW(addFilter("MaxDistDataPointsFilter", params));
00658
00659 }
00660
00661 TEST_F(DataFilterTest, MinDistDataPointsFilter)
00662 {
00663
00664 params = map_list_of<string,string>
00665 ("dim","0")
00666 ("minDist", toParam(0.05))
00667 ;
00668
00669
00670 params["dim"] = "0";
00671 icp.readingDataPointsFilters.clear();
00672 addFilter("MinDistDataPointsFilter", params);
00673 validate2dTransformation();
00674 validate3dTransformation();
00675
00676
00677 params["dim"] = "1";
00678 icp.readingDataPointsFilters.clear();
00679 addFilter("MinDistDataPointsFilter", params);
00680 validate2dTransformation();
00681 validate3dTransformation();
00682
00683
00684
00685 params["dim"] = "2";
00686 icp.readingDataPointsFilters.clear();
00687 addFilter("MinDistDataPointsFilter", params);
00688 EXPECT_ANY_THROW(validate2dTransformation());
00689 validate3dTransformation();
00690
00691
00692 params["dim"] = "-1";
00693 icp.readingDataPointsFilters.clear();
00694 addFilter("MinDistDataPointsFilter", params);
00695 validate2dTransformation();
00696 validate3dTransformation();
00697
00698 }
00699
00700 TEST_F(DataFilterTest, MaxQuantileOnAxisDataPointsFilter)
00701 {
00702
00703 string ratio = "0.95";
00704 params = map_list_of<string,string>
00705 ("dim","0")
00706 ("ratio", ratio)
00707 ;
00708
00709
00710 params["dim"] = "0";
00711 icp.readingDataPointsFilters.clear();
00712 addFilter("MaxQuantileOnAxisDataPointsFilter", params);
00713 validate2dTransformation();
00714 validate3dTransformation();
00715
00716
00717 params["dim"] = "1";
00718 icp.readingDataPointsFilters.clear();
00719 addFilter("MaxQuantileOnAxisDataPointsFilter", params);
00720 validate2dTransformation();
00721 validate3dTransformation();
00722
00723
00724 params["dim"] = "2";
00725 icp.readingDataPointsFilters.clear();
00726 addFilter("MaxQuantileOnAxisDataPointsFilter", params);
00727 EXPECT_ANY_THROW(validate2dTransformation());
00728 validate3dTransformation();
00729 }
00730
00731
00732
00733 TEST_F(DataFilterTest, SurfaceNormalDataPointsFilter)
00734 {
00735
00736 params = map_list_of
00737 ("knn", "5")
00738 ("epsilon", "0.1")
00739 ("keepNormals", "1")
00740 ("keepDensities", "1")
00741 ("keepEigenValues", "1")
00742 ("keepEigenVectors", "1" )
00743 ("keepMatchedIds" , "1" )
00744 ;
00745
00746
00747 addFilter("SurfaceNormalDataPointsFilter", params);
00748 validate2dTransformation();
00749 validate3dTransformation();
00750
00751
00752
00753
00754
00755 }
00756
00757 TEST_F(DataFilterTest, MaxDensityDataPointsFilter)
00758 {
00759
00760 vector<double> ratio = list_of (100) (1000) (5000);
00761
00762 for(unsigned i=0; i < ratio.size(); i++)
00763 {
00764 icp.readingDataPointsFilters.clear();
00765 params = map_list_of
00766 ("knn", "5")
00767 ("epsilon", "0.1")
00768 ("keepNormals", "0")
00769 ("keepDensities", "1")
00770 ("keepEigenValues", "0")
00771 ("keepEigenVectors", "0" )
00772 ("keepMatchedIds" , "0" )
00773 ;
00774
00775 addFilter("SurfaceNormalDataPointsFilter", params);
00776
00777 params = map_list_of ("maxDensity", toParam(ratio[i]));
00778 addFilter("MaxDensityDataPointsFilter", params);
00779
00780
00781
00782
00783
00784
00785
00786
00787 validate3dTransformation();
00788
00789 double nbInitPts = data3D.features.cols();
00790 double nbRemainingPts = icp.getPrefilteredReadingPtsCount();
00791 EXPECT_TRUE(nbRemainingPts < nbInitPts);
00792 }
00793 }
00794
00795 TEST_F(DataFilterTest, SamplingSurfaceNormalDataPointsFilter)
00796 {
00797
00798 params = map_list_of
00799 ("knn", "5")
00800 ("averageExistingDescriptors", "1")
00801 ("keepNormals", "1")
00802 ("keepDensities", "1")
00803 ("keepEigenValues", "1")
00804 ("keepEigenVectors", "1")
00805 ;
00806
00807 addFilter("SamplingSurfaceNormalDataPointsFilter", params);
00808 validate2dTransformation();
00809 validate3dTransformation();
00810
00811 }
00812
00813 TEST_F(DataFilterTest, OrientNormalsDataPointsFilter)
00814 {
00815
00816 PM::DataPointsFilter* extraDataPointFilter;
00817 extraDataPointFilter = PM::get().DataPointsFilterRegistrar.create(
00818 "SurfaceNormalDataPointsFilter");
00819 icp.readingDataPointsFilters.push_back(extraDataPointFilter);
00820 addFilter("ObservationDirectionDataPointsFilter");
00821 addFilter("OrientNormalsDataPointsFilter", map_list_of
00822 ("towardCenter", toParam(false))
00823 );
00824 validate2dTransformation();
00825 validate3dTransformation();
00826 }
00827
00828
00829 TEST_F(DataFilterTest, RandomSamplingDataPointsFilter)
00830 {
00831 vector<double> prob = list_of (0.80) (0.85) (0.90) (0.95);
00832 for(unsigned i=0; i<prob.size(); i++)
00833 {
00834
00835 params = map_list_of
00836 ("prob", toParam(prob[i]))
00837 ;
00838 icp.readingDataPointsFilters.clear();
00839 addFilter("RandomSamplingDataPointsFilter", params);
00840 validate2dTransformation();
00841 validate3dTransformation();
00842 }
00843 }
00844
00845 TEST_F(DataFilterTest, FixStepSamplingDataPointsFilter)
00846 {
00847 vector<unsigned> steps = list_of (1) (2) (3);
00848 for(unsigned i=0; i<steps.size(); i++)
00849 {
00850
00851 params = map_list_of
00852 ("startStep", toParam(steps[i]))
00853 ;
00854 icp.readingDataPointsFilters.clear();
00855 addFilter("FixStepSamplingDataPointsFilter", params);
00856 validate2dTransformation();
00857 validate3dTransformation();
00858 }
00859 }
00860
00861 TEST_F(DataFilterTest, VoxelGridDataPointsFilter)
00862 {
00863 vector<bool> useCentroid = list_of(false)(true);
00864 vector<bool> averageExistingDescriptors = list_of(false)(true);
00865 for (unsigned i = 0 ; i < useCentroid.size() ; i++)
00866 {
00867 for (unsigned j = 0; j < averageExistingDescriptors.size(); j++)
00868 {
00869 params = map_list_of<string,string>
00870 ("vSizeX","0.02")
00871 ("vSizeY","0.02")
00872 ("vSizeZ","0.02")
00873 ("useCentroid",toParam(true))
00874 ("averageExistingDescriptors",toParam(true))
00875 ;
00876 icp.readingDataPointsFilters.clear();
00877 addFilter("VoxelGridDataPointsFilter", params);
00878 validate2dTransformation();
00879 }
00880 }
00881
00882 for (unsigned i = 0 ; i < useCentroid.size() ; i++)
00883 {
00884 for (unsigned j = 0; j < averageExistingDescriptors.size(); j++)
00885 {
00886 params = map_list_of<string,string>
00887 ("vSizeX","1")
00888 ("vSizeY","1")
00889 ("vSizeZ","1")
00890 ("useCentroid",toParam(true))
00891 ("averageExistingDescriptors",toParam(true));
00892 icp.readingDataPointsFilters.clear();
00893 addFilter("VoxelGridDataPointsFilter", params);
00894 validate3dTransformation();
00895 }
00896 }
00897 }
00898
00899
00900
00901
00902
00903
00904 class MatcherTest: public IcpHelper
00905 {
00906
00907 public:
00908
00909 PM::Matcher* testedMatcher;
00910
00911
00912 virtual void SetUp()
00913 {
00914 icp.setDefault();
00915
00916
00917 }
00918
00919
00920 virtual void TearDown(){}
00921
00922 void addFilter(string name, PM::Parameters params)
00923 {
00924 testedMatcher =
00925 PM::get().MatcherRegistrar.create(name, params);
00926 icp.matcher.reset(testedMatcher);
00927 }
00928
00929 };
00930
00931 TEST_F(MatcherTest, KDTreeMatcher)
00932 {
00933 vector<unsigned> knn = list_of (1) (2) (3);
00934 vector<double> epsilon = list_of (0.0) (0.2);
00935 vector<double> maxDist = list_of (1.0) (0.5);
00936
00937 for(unsigned i=0; i < knn.size(); i++)
00938 {
00939 for(unsigned j=0; j < epsilon.size(); j++)
00940 {
00941 for(unsigned k=0; k < maxDist.size(); k++)
00942 {
00943 params = map_list_of
00944 ("knn", toParam(knn[i]))
00945 ("epsilon", toParam(epsilon[j]))
00946 ("searchType", "1")
00947 ("maxDist", toParam(maxDist[k]))
00948 ;
00949
00950 addFilter("KDTreeMatcher", params);
00951 validate2dTransformation();
00952 validate3dTransformation();
00953 }
00954 }
00955 }
00956 }
00957
00958
00959
00960
00961
00962
00963
00964 class OutlierFilterTest: public IcpHelper
00965 {
00966 public:
00967 PM::OutlierFilter* testedOutlierFilter;
00968
00969
00970 virtual void SetUp()
00971 {
00972 icp.setDefault();
00973
00974
00975
00976 icp.outlierFilters.clear();
00977 }
00978
00979
00980 virtual void TearDown(){}
00981
00982 void addFilter(string name, PM::Parameters params)
00983 {
00984 testedOutlierFilter =
00985 PM::get().OutlierFilterRegistrar.create(name, params);
00986 icp.outlierFilters.push_back(testedOutlierFilter);
00987 }
00988
00989 };
00990
00991
00992
00993 TEST_F(OutlierFilterTest, MaxDistOutlierFilter2D)
00994 {
00995 addFilter("MaxDistOutlierFilter", map_list_of
00996 ("maxDist", toParam(0.015))
00997 );
00998 validate2dTransformation();
00999 }
01000
01001 TEST_F(OutlierFilterTest, MaxDistOutlierFilter3D)
01002 {
01003 addFilter("MaxDistOutlierFilter", map_list_of
01004 ("maxDist", toParam(0.1))
01005 );
01006 validate3dTransformation();
01007 }
01008
01009
01010 TEST_F(OutlierFilterTest, MinDistOutlierFilter2D)
01011 {
01012
01013
01014 PM::OutlierFilter* extraOutlierFilter;
01015
01016 extraOutlierFilter =
01017 PM::get().OutlierFilterRegistrar.create(
01018 "MaxDistOutlierFilter", map_list_of
01019 ("maxDist", toParam(0.015))
01020 )
01021 ;
01022 icp.outlierFilters.push_back(extraOutlierFilter);
01023
01024 addFilter("MinDistOutlierFilter", map_list_of ("minDist", toParam(0.0002)) );
01025
01026 validate2dTransformation();
01027 }
01028
01029 TEST_F(OutlierFilterTest, MinDistOutlierFilter3D)
01030 {
01031
01032
01033 PM::OutlierFilter* extraOutlierFilter;
01034
01035 extraOutlierFilter =
01036 PM::get().OutlierFilterRegistrar.create(
01037 "MaxDistOutlierFilter", map_list_of
01038 ("maxDist", toParam(0.1))
01039 )
01040 ;
01041 icp.outlierFilters.push_back(extraOutlierFilter);
01042
01043 addFilter("MinDistOutlierFilter", map_list_of ("minDist", toParam(0.0002)) );
01044
01045 validate3dTransformation();
01046 }
01047
01048 TEST_F(OutlierFilterTest, MedianDistOutlierFilter)
01049 {
01050 addFilter("MedianDistOutlierFilter", map_list_of ("factor", toParam(3.5)));
01051 validate2dTransformation();
01052 validate3dTransformation();
01053 }
01054
01055
01056 TEST_F(OutlierFilterTest, TrimmedDistOutlierFilter)
01057 {
01058 addFilter("TrimmedDistOutlierFilter", map_list_of ("ratio", toParam(0.85)) );
01059 validate2dTransformation();
01060 validate3dTransformation();
01061 }
01062
01063
01064 TEST_F(OutlierFilterTest, VarTrimmedDistOutlierFilter)
01065 {
01066 addFilter("VarTrimmedDistOutlierFilter", map_list_of
01067 ("minRatio", toParam(0.60))
01068 ("maxRatio", toParam(0.80))
01069 ("lambda", toParam(0.9))
01070 );
01071 validate2dTransformation();
01072 validate3dTransformation();
01073 }
01074
01075
01076
01077
01078
01079
01080 class ErrorMinimizerTest: public IcpHelper
01081 {
01082 public:
01083 PM::ErrorMinimizer* errorMin;
01084
01085
01086 virtual void SetUp()
01087 {
01088 icp.setDefault();
01089
01090
01091 }
01092
01093
01094 virtual void TearDown(){}
01095
01096 void addFilter(string name)
01097 {
01098 errorMin = PM::get().ErrorMinimizerRegistrar.create(name);
01099 icp.errorMinimizer.reset(errorMin);
01100 }
01101 };
01102
01103
01104 TEST_F(ErrorMinimizerTest, PointToPointErrorMinimizer)
01105 {
01106 addFilter("PointToPointErrorMinimizer");
01107 validate2dTransformation();
01108 validate3dTransformation();
01109 }
01110
01111 TEST_F(ErrorMinimizerTest, PointToPlaneErrorMinimizer)
01112 {
01113 addFilter("PointToPlaneErrorMinimizer");
01114 validate2dTransformation();
01115 validate3dTransformation();
01116 }
01117
01118
01119
01120
01121
01122
01123 class TransformationCheckerTest: public IcpHelper
01124 {
01125 public:
01126 PM::TransformationChecker* transformCheck;
01127
01128
01129 virtual void SetUp()
01130 {
01131 icp.setDefault();
01132
01133
01134
01135 icp.transformationCheckers.clear();
01136 }
01137
01138
01139 virtual void TearDown(){}
01140
01141 void addFilter(string name, PM::Parameters params)
01142 {
01143 transformCheck =
01144 PM::get().TransformationCheckerRegistrar.create(name, params);
01145
01146 icp.transformationCheckers.push_back(transformCheck);
01147 }
01148 };
01149
01150
01151 TEST_F(TransformationCheckerTest, CounterTransformationChecker)
01152 {
01153 addFilter("CounterTransformationChecker", map_list_of ("maxIterationCount", toParam(20)) );
01154 validate2dTransformation();
01155 }
01156
01157 TEST_F(TransformationCheckerTest, DifferentialTransformationChecker)
01158 {
01159 addFilter("DifferentialTransformationChecker", map_list_of
01160 ("minDiffRotErr", toParam(0.001))
01161 ("minDiffTransErr", toParam(0.001))
01162 ("smoothLength", toParam(4))
01163 );
01164 validate2dTransformation();
01165 }
01166
01167 TEST_F(TransformationCheckerTest, BoundTransformationChecker)
01168 {
01169
01170
01171
01172 PM::TransformationChecker* extraTransformCheck;
01173
01174 extraTransformCheck = PM::get().TransformationCheckerRegistrar.create(
01175 "CounterTransformationChecker"
01176 );
01177 icp.transformationCheckers.push_back(extraTransformCheck);
01178
01179 addFilter("BoundTransformationChecker", map_list_of
01180 ("maxRotationNorm", toParam(1.0))
01181 ("maxTranslationNorm", toParam(1.0))
01182 );
01183 validate2dTransformation();
01184 }
01185
01186
01187
01188
01189 TEST(Transformation, RigidTransformation)
01190 {
01191 PM::Transformation* rigidTrans;
01192 rigidTrans = PM::get().REG(Transformation).create("RigidTransformation");
01193
01194
01195
01196 PM::Matrix T_3D = PM::Matrix::Identity(4,4);
01197 T_3D(0,0) = 2.3;
01198 T_3D(0,1) = 0.03;
01199
01200 EXPECT_FALSE(rigidTrans->checkParameters(T_3D));
01201
01202 EXPECT_THROW(rigidTrans->compute(data3D, T_3D), TransformationError);
01203
01204
01205 for(int i = 0; i < 10; i++)
01206 {
01207 T_3D = rigidTrans->correctParameters(T_3D);
01208 EXPECT_TRUE(rigidTrans->checkParameters(T_3D));
01209 }
01210
01211
01212
01213 PM::Matrix T_2D = PM::Matrix::Identity(3,3);
01214 T_2D(1,0) = 8.99;
01215 T_2D(0,1) = 4.03;
01216
01217 EXPECT_FALSE(rigidTrans->checkParameters(T_2D));
01218
01219 EXPECT_THROW(rigidTrans->compute(data2D, T_2D), TransformationError);
01220
01221
01222 for(int i = 0; i < 10; i++)
01223 {
01224 T_2D = rigidTrans->correctParameters(T_2D);
01225 EXPECT_TRUE(rigidTrans->checkParameters(T_2D));
01226 }
01227
01228 }
01229
01230
01231
01232
01233 TEST(Inspectors, PerformanceInspector)
01234 {
01235 PM::Inspector* performances =
01236 PM::get().REG(Inspector).create(
01237 "PerformanceInspector", map_list_of
01238 ("baseFileName", "/tmp/utest_performances")
01239 ("dumpPerfOnExit", "1")
01240 )
01241 ;
01242
01243 }
01244
01245 TEST(Inspectors, VTKFileInspector)
01246 {
01247 PM::Inspector* vtkFile =
01248 PM::get().REG(Inspector).create(
01249 "VTKFileInspector", map_list_of
01250 ("baseFileName", "/tmp/utest_vtk")
01251 ("dumpPerfOnExit", "1")
01252 )
01253 ;
01254
01255 }
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266 TEST(Loggers, FileLogger)
01267 {
01268 string infoFileName = "utest_info";
01269 string warningFileName = "utest_warn";
01270
01271 Logger* fileLog =
01272 PM::get().REG(Logger).create(
01273 "FileLogger", map_list_of
01274 ("infoFileName", infoFileName)
01275 ("warningFileName", warningFileName)
01276 ("displayLocation", "1")
01277 )
01278 ;
01279
01280
01281 delete fileLog;
01282
01283
01284 EXPECT_TRUE(boost::filesystem::remove(boost::filesystem::path(infoFileName)));
01285 EXPECT_TRUE(boost::filesystem::remove(boost::filesystem::path(warningFileName)));
01286 }
01287
01288
01289
01290
01291
01292 int main(int argc, char **argv)
01293 {
01294 dataPath = "";
01295 for(int i=1; i < argc; i++)
01296 {
01297 if (strcmp(argv[i], "--path") == 0 && i+1 < argc)
01298 dataPath = argv[i+1];
01299 }
01300
01301 if(dataPath == "")
01302 {
01303 cerr << "Missing the flag --path ./path/to/examples/data\n Please give the path to the test data folder which should be included with the source code. The folder is named 'examples/data'." << endl;
01304 return -1;
01305 }
01306
01307
01308 ref2D = DP::load(dataPath + "2D_oneBox.csv");
01309 data2D = DP::load(dataPath + "2D_twoBoxes.csv");
01310 ref3D = DP::load(dataPath + "car_cloud400.csv");
01311 data3D = DP::load(dataPath + "car_cloud401.csv");
01312
01313
01314 validT2d = PM::TransformationParameters(3,3);
01315 validT2d << 0.987498, 0.157629, 0.0859918,
01316 -0.157629, 0.987498, 0.203247,
01317 0, 0, 1;
01318
01319 validT3d = PM::TransformationParameters(4,4);
01320 validT3d << 0.982304, 0.166685, -0.0854066, 0.0446816,
01321 -0.150189, 0.973488, 0.172524, 0.191998,
01322 0.111899, -0.156644, 0.981296, -0.0356313,
01323 0, 0, 0, 1;
01324
01325 testing::GTEST_FLAG(print_time) = true;
01326 testing::InitGoogleTest(&argc, argv);
01327 return RUN_ALL_TESTS();
01328 }
01329
01330
01331