introduce
The normal of a plane is a unit vector perpendicular to it. The normal of the surface at a point is defined as a vector perpendicular to the plane tangent to the surface at that point. You can also calculate surface normals for cloud points.
There is no detailed introduction to the mathematical principle of the estimation method here, just know that it uses the nearest neighbor (the point closest to the normal we calculate) to find out the tangent plane and normal vector. You can customize the method by using the search radius (the sphere with that radius as its center; all adjacent points within it) and the viewpoint (by default, the output normal will be directionless). Assume that all vectors must point to the camera - because otherwise they will belong to a surface that is not visible from the sensor - they can all be reoriented accordingly.
Normals are also important because they can provide us with information about the curvature of the surface at some point, which can benefit us. Many of PCL's algorithms will require us to provide normals to the input cloud
Code details
#include <pcl/io/pcd_io.h> #include <pcl/features/normal_3d.h> #include <pcl/features/normal_3d_omp.h> #include <boost/thread/thread.hpp> #include <pcl/visualization/pcl_visualizer.h> #include <time.h> #include <pcl/filters/voxel_grid.h> int main(int argc, char** argv) { // Object for storing the point cloud. pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // Object for storing the normals. pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>); clock_t start, end; // Read a PCD file from disk. if (pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *cloud) != 0) { return -1; } pcl::VoxelGrid<pcl::PointXYZ> grid; const float leaf = 0.005f; grid.setLeafSize (leaf, leaf, leaf); grid.setInputCloud (cloud); grid.filter (*cloud); std::cout<<cloud->points.size()<<std::endl; start = clock(); pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normalEstimation; normalEstimation.setInputCloud(cloud); normalEstimation.setRadiusSearch(0.01); normalEstimation.compute(*normals); end = clock(); std::cout<<normals->points.size()<<std::endl; std::cout<<"estimate the normals:"<<(end - start)/CLOCKS_PER_SEC<<"s"<<std::endl; start = clock(); pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> normalEstimation1; normalEstimation1.setRadiusSearch(0.01); normalEstimation1.setNumberOfThreads(12); normalEstimation1.setInputCloud(cloud); normalEstimation1.compute(*normals); end = clock(); std::cout<<normals->points.size()<<std::endl; std::cout<<"estimate the normalsOPM:"<<(end - start)/CLOCKS_PER_SEC<<"s"<<std::endl; // Visualize them. boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Normals")); viewer->addPointCloud<pcl::PointXYZ>(cloud, "cloud"); // Display one normal out of 20, as a line of length 3cm. viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud, normals, 20, 0.03, "normals"); while (!viewer->wasStopped()) { viewer->spinOnce(100); boost::this_thread::sleep(boost::posix_time::microseconds(100000)); } }
Downsampling the original point cloud can speed up the establishment of normals. In addition, OMP is used to speed up the establishment of normals.
Processing results
Normals are also stored in PointCloud objects, instantiated as Normal. If you have been extracting some indexes from the cloud and then providing them to the algorithm, make sure that the normals are treated the same. I did not use the "setViewPoint()" function. You can use "setKSearch()" instead of "setRadiusSearch()", which uses the integer K. This takes into account the k nearest neighbor of the point to calculate the Normal. Note that this can produce some strange results for points that are not in dense areas because some "neighbors" are too far away from them.
Code link
https://github.com/DoubleYuanL/PCL_Tutorial2-2.1_Normal_estimation.git