估计点云中的表面法线
翻译自:http://www.pointclouds.org/documentation/tutorials/normal_estimation.php#normal-estimation
线是几何表面的重要属性,并且在诸如计算机图形应用的许多领域中被大量使用,以应用产生阴影和其他视觉效果的正确光源。
给定几何表面,通常在表面上的某个点处推断法线的方向作为垂直于该点的表面的向量通常是繁琐的。 但是,由于我们获取了代表真实表面点云数据集上的一组点样本,因此有两种方法:
使用表面网格划分技术从获取的点云数据集中获取下伏曲面,然后从网格中计算曲面法线;
使用近似值直接从点云数据集推断出曲面法线。
本教程将针对后者,即给定点云数据集,直接计算云中每个点的曲面法线。
理论基础
虽然存在许多不同的常规估计方法,但我们将专注于本教程的方法是最简单的方法之一,其公式如下。 确定表面上的点的法线的问题可以近似转化成估计与表面相切的平面的法线的问题,这又成为最小二乘平面拟合估计问题。
因此,用于估计表面法线的解决方案被简化为对从查询点的最近邻居创建的协方差矩阵的特征向量和特征值(或PCA-主成分分析)的分析。 更具体地,对于每个点 ,我们如下组装协方差矩阵:
其中k是在 的邻域中考虑的点邻居的数量, 表示最近邻居的3D质心, 是协方差矩阵的第j个特征值,并且 是第j个本征向量。
要从PCL中的一组点估计协方差矩阵,您可以使用:
// 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);
估计法线:
#include <pcl/point_types.h> #include <pcl/features/normal_3d.h> { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); ... read, pass in or create a point cloud ... // Create the normal estimation class, and pass the input dataset to it pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setInputCloud (cloud); // Create an empty kdtree representation, and pass it to the normal estimation object. // Its content will be filled inside the object, based on the given input dataset (as no other search surface is given). pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ()); ne.setSearchMethod (tree); // Output datasets pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>); // Use all neighbors in a sphere of radius 3cm ne.setRadiusSearch (0.03); // Compute the features ne.compute (*cloud_normals); // cloud_normals->points.size () should have the same size as the input cloud->points.size ()* }
如果您的数据集是有组织的(例如,使用TOF相机,立体相机等获取 - 也就是说,它具有宽度和高度),为了获得更快的结果,可以使用积分图像来估计法线。
利用积分图像估计法线,代码如下:(用 VS2015 pro 运行时出现报错,显示为内存出错。。。)
#include <pcl/io/io.h> #include <pcl/io/pcd_io.h> #include <pcl/features/integral_image_normal.h> #include <pcl/visualization/cloud_viewer.h> int main () { // load point cloud pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile ("table_scene_mug_stereo_textured.pcd", *cloud); // estimate normals pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>); pcl::IntegralImageNormalEstimation<pcl::PointXYZ, pcl::Normal> ne; ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT); ne.setMaxDepthChangeFactor(0.02f); ne.setNormalSmoothingSize(10.0f); ne.setInputCloud(cloud); ne.compute(*normals); // visualize normals pcl::visualization::PCLVisualizer viewer("PCL Viewer"); viewer.setBackgroundColor (0.0, 0.0, 0.5); viewer.addPointCloudNormals<pcl::PointXYZ,pcl::Normal>(cloud, normals); while (!viewer.wasStopped ()) { viewer.spinOnce (); } return 0; }