Surface normals are important properties of a geometric surface, and are heavily used in many areas such as computer graphics applications, to apply the correct light sources that generate shadings and other visual effects.
Given a geometric surface, it’s usually trivial to infer the direction of the normal at a certain point on the surface as the vector perpendicular to the surface at that point. However, since the point cloud datasets that we acquire represent a set of point samples on the real surface, there are two possibilities:
There are many different normal estimation methods.
The problem of determining the normal to a point on the surface is approximated by the problem of estimating the normal of a plane tangent to the surface, which in turn becomes a least-square plane fitting estimation problem.
The solution for estimating the surface normal is therefore reduced to an analysis of the eigenvectors and eigenvalues (or PCA – Principal Component Analysis) of a covariance matrix created from the nearest neighbors of the query point. More specifically, for each point, we assemble the covariance matrix as follows:
k is the number of point neighbors considered in the neighborhood of Pi, P_bar represents the 3D centroid of the nearest neighbors, lambda is the j-th eigenvalue of the covariance matrix, V_bar is the j-th eigenvector.
To estimate a covariance matrix from a set of points in PCL, you can use:
// Placeholder for the 3x3 covariance matrix at each surface patch
Eigen::Matrix3f covariance_matrix;
// 16-bytes aligned placeholder for the XYZ centroid of a surface patch
Eigen::Vector4f xyz_centroid;
// Estimate the XYZ centroid
compute3DCentroid (cloud, xyz_centroid);
// Compute the 3x3 covariance matrix
computeCovarianceMatrix (cloud, xyz_centroid, covariance_matrix);
In general, because there is no mathematical way to solve for the sign of the normal , its orientation computed via Principal Component Analysis (PCA) as shown above is ambiguous, and not consistently oriented over an entire point cloud dataset.
The solution to this problem is trivial if the viewpoint is in fact known. To orient all normals consistently towards the viewpoint, they need to satisfy the equation:
flipNormalTowardsViewpoint (const PointT &point, float vp_x, float vp_y, float vp_z, Eigen::Vector4f &normal);
If the dataset has multiple acquisition viewpoints, then the above normal re-orientation method does not hold, and more complex algorithms need to be implemented. Please e [RusuDissertation] for more information.
The specifics of the nearest-neighbor estimation problem raise the question of the right scale factor: given a sampled point cloud dataset, what are the correct k (given via pcl::Feature::setKSearch) or r (given via pcl::Feature::setRadiusSearch) values that should be used in determining the set of nearest neighbors of a point?
the figure above presents the effects of selecting a smaller scale (i.e., small r or k) versus a larger scale (i.e., large r or k).