#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace small_gicp; class NormalEstimationTest : public testing::Test { public: void SetUp() override { points = std::make_shared(read_ply("data/target.ply")); points = voxelgrid_sampling(*points, 0.25); estimate_normals_covariances(*points, num_neighbors); tree = std::make_shared>(points); points_pcl = pcl::make_shared>(); points_pcl->resize(points->size()); for (size_t i = 0; i < points->size(); i++) { points_pcl->at(i).getVector4fMap() = points->point(i).cast(); } pcl::NormalEstimationOMP normal_estimation; normal_estimation.setKSearch(num_neighbors); normal_estimation.setInputCloud(points_pcl); normal_estimation.compute(*points_pcl); } template bool check_normals(const PointCloud& points) { if (traits::size(points) != points_pcl->size()) { return false; } for (size_t i = 0; i < traits::size(points); i++) { const Eigen::Vector4d normal = traits::normal(points, i); EXPECT_NEAR(normal.w(), 0.0, 1e-6) << "Last element must be zero"; EXPECT_NEAR(normal.norm(), 1.0, 1e-6) << "Normal must be unit vector"; const double error = (normal - points_pcl->at(i).getNormalVector4fMap().cast()).norm(); EXPECT_NEAR(error, 0.0, 1e-3) << "Normal estimation error is too large"; } return true; } template bool check_covs(const PointCloud& points) { if (traits::size(points) != this->points->size()) { return false; } for (size_t i = 0; i < traits::size(points); i++) { const Eigen::Matrix4d cov = traits::cov(points, i); EXPECT_NEAR(cov.bottomRows(1).norm(), 0.0, 1e-6) << "Bottom row must be zero"; EXPECT_NEAR(cov.rightCols(1).norm(), 0.0, 1e-6) << "Right column must be zero"; for (int j = 0; j < 3; j++) { for (int k = j + 1; k < 3; k++) { EXPECT_NEAR(cov(j, k), cov(k, j), 1e-6) << "Covariance matrix must be symmetric"; } } const double error = (cov - this->points->cov(i)).norm(); EXPECT_NEAR(error, 0.0, 1e-3) << "Covariance estimation error is too large"; } return true; } protected: const int num_neighbors = 20; PointCloud::Ptr points; KdTree::Ptr tree; pcl::PointCloud::Ptr points_pcl; }; // Load check TEST_F(NormalEstimationTest, LoadCheck) { EXPECT_FALSE(points->empty()); EXPECT_FALSE(points_pcl->empty()); } // Empty test TEST_F(NormalEstimationTest, EmptyTest) { // Empty point cloud auto empty_points = std::make_shared(); auto empty_tree = std::make_shared>(empty_points); estimate_normals(*empty_points, *empty_tree, num_neighbors); EXPECT_TRUE(empty_points->empty()); estimate_covariances(*empty_points, *empty_tree, num_neighbors); EXPECT_TRUE(empty_points->empty()); estimate_normals_covariances(*empty_points, *empty_tree, num_neighbors); EXPECT_TRUE(empty_points->empty()); // Empty point cloud (PCL) auto empty_points_pcl = pcl::make_shared>(); auto empty_tree_pcl = std::make_shared>>(empty_points_pcl); estimate_normals(*empty_points_pcl, *empty_tree_pcl, num_neighbors); EXPECT_TRUE(empty_points_pcl->empty()); estimate_covariances(*empty_points_pcl, *empty_tree_pcl, num_neighbors); EXPECT_TRUE(empty_points_pcl->empty()); estimate_normals_covariances(*empty_points_pcl, *empty_tree_pcl, num_neighbors); EXPECT_TRUE(empty_points_pcl->empty()); } // Empty test (TBB) TEST_F(NormalEstimationTest, EmptyTestTBB) { // Empty point cloud auto empty_points = std::make_shared(); auto empty_tree = std::make_shared>(empty_points); estimate_normals_tbb(*empty_points, *empty_tree, num_neighbors); EXPECT_TRUE(empty_points->empty()); estimate_covariances_tbb(*empty_points, *empty_tree, num_neighbors); EXPECT_TRUE(empty_points->empty()); estimate_normals_covariances_tbb(*empty_points, *empty_tree, num_neighbors); EXPECT_TRUE(empty_points->empty()); // Empty point cloud (PCL) auto empty_points_pcl = pcl::make_shared>(); auto empty_tree_pcl = std::make_shared>>(empty_points_pcl); estimate_normals_tbb(*empty_points_pcl, *empty_tree_pcl, num_neighbors); EXPECT_TRUE(empty_points_pcl->empty()); estimate_covariances_tbb(*empty_points_pcl, *empty_tree_pcl, num_neighbors); EXPECT_TRUE(empty_points_pcl->empty()); estimate_normals_covariances_tbb(*empty_points_pcl, *empty_tree_pcl, num_neighbors); EXPECT_TRUE(empty_points_pcl->empty()); } // Empty test (OMP) TEST_F(NormalEstimationTest, EmptyTestOMP) { // Empty point cloud auto empty_points = std::make_shared(); auto empty_tree = std::make_shared>(empty_points); estimate_normals_omp(*empty_points, *empty_tree, num_neighbors, 2); EXPECT_TRUE(empty_points->empty()); estimate_covariances_omp(*empty_points, *empty_tree, num_neighbors, 2); EXPECT_TRUE(empty_points->empty()); estimate_normals_covariances_omp(*empty_points, *empty_tree, num_neighbors, 2); EXPECT_TRUE(empty_points->empty()); // Empty point cloud (PCL) auto empty_points_pcl = pcl::make_shared>(); auto empty_tree_pcl = std::make_shared>>(empty_points_pcl); estimate_normals_omp(*empty_points_pcl, *empty_tree_pcl, num_neighbors, 2); EXPECT_TRUE(empty_points_pcl->empty()); estimate_covariances_omp(*empty_points_pcl, *empty_tree_pcl, num_neighbors, 2); EXPECT_TRUE(empty_points_pcl->empty()); estimate_normals_covariances_omp(*empty_points_pcl, *empty_tree_pcl, num_neighbors, 2); EXPECT_TRUE(empty_points_pcl->empty()); } // Normal/covariance estimation test TEST_F(NormalEstimationTest, NormalEstimationTest) { auto estimated = std::make_shared(); *estimated = *points; estimate_normals(*estimated, *tree, num_neighbors); EXPECT_TRUE(check_normals(*estimated)); estimate_covariances(*estimated, *tree, num_neighbors); EXPECT_TRUE(check_covs(*estimated)); *estimated = *points; estimate_normals_covariances(*estimated, *tree, num_neighbors); EXPECT_TRUE(check_normals(*estimated)); EXPECT_TRUE(check_covs(*estimated)); } // Normal/covariance estimation test (TBB) TEST_F(NormalEstimationTest, NormalEstimationTestTBB) { auto estimated = std::make_shared(); *estimated = *points; estimate_normals_tbb(*estimated, *tree, num_neighbors); EXPECT_TRUE(check_normals(*estimated)); estimate_covariances_tbb(*estimated, *tree, num_neighbors); EXPECT_TRUE(check_covs(*estimated)); *estimated = *points; estimate_normals_covariances_tbb(*estimated, *tree, num_neighbors); EXPECT_TRUE(check_normals(*estimated)); EXPECT_TRUE(check_covs(*estimated)); } // Normal/covariance estimation test (OMP) TEST_F(NormalEstimationTest, NormalEstimationTestOMP) { auto estimated = std::make_shared(); *estimated = *points; estimate_normals_omp(*estimated, *tree, num_neighbors, 2); EXPECT_TRUE(check_normals(*estimated)); estimate_covariances_omp(*estimated, *tree, num_neighbors, 2); EXPECT_TRUE(check_covs(*estimated)); *estimated = *points; estimate_normals_covariances_omp(*estimated, *tree, num_neighbors, 2); EXPECT_TRUE(check_normals(*estimated)); EXPECT_TRUE(check_covs(*estimated)); } // Normal/covariance estimation test (PCL) TEST_F(NormalEstimationTest, NormalEstimationTestPCL) { const auto copy_points = [&](auto& points) { points.resize(points_pcl->size()); for (size_t i = 0; i < points_pcl->size(); i++) { points.at(i).getVector4fMap() = points_pcl->at(i).getVector4fMap(); } }; // Normal estimation auto point_normals = pcl::make_shared>(); copy_points(*point_normals); estimate_normals(*point_normals, num_neighbors); EXPECT_TRUE(check_normals(*point_normals)); estimate_normals_tbb(*point_normals, num_neighbors); EXPECT_TRUE(check_normals(*point_normals)); estimate_normals_omp(*point_normals, num_neighbors, 2); EXPECT_TRUE(check_normals(*point_normals)); // Covariance estimation auto point_covs = pcl::make_shared>(); copy_points(*point_covs); estimate_covariances(*point_covs, num_neighbors); EXPECT_TRUE(check_covs(*point_covs)); estimate_covariances_tbb(*point_covs, num_neighbors); EXPECT_TRUE(check_covs(*point_covs)); estimate_covariances_omp(*point_covs, num_neighbors, 2); EXPECT_TRUE(check_covs(*point_covs)); // Normal/covariance estimation auto point_normals_covs = pcl::make_shared>(); copy_points(*point_normals_covs); estimate_normals_covariances(*point_normals_covs, num_neighbors); EXPECT_TRUE(check_normals(*point_normals_covs)); EXPECT_TRUE(check_covs(*point_normals_covs)); estimate_normals_covariances_tbb(*point_normals_covs, num_neighbors); EXPECT_TRUE(check_normals(*point_normals_covs)); EXPECT_TRUE(check_covs(*point_normals_covs)); estimate_normals_covariances_omp(*point_normals_covs, num_neighbors, 2); EXPECT_TRUE(check_normals(*point_normals_covs)); EXPECT_TRUE(check_covs(*point_normals_covs)); }