注意:本方法不会计算所有点云点的法向量,适用于较密集的点云,只计算除部分具有代表性的法向量,加快计算速度(但不可避免会影响结果准确性)!!!
1.原理
使用基于一阶泰勒近似的最小二乘估计对密集数据进行表面法线估计。
(1)遍历点云,生成点云窗口(即遍历点云中的每个点,分别获取其一定范围内的邻域点,作为一个窗口)
(2)对于每个点云点P,及其邻域点,使用一阶泰勒近似的最小二乘估计一个平面,方程式可近似写为:
(3)通过计算该平面的法向量,得到这一块点云的法向量。
(4)窗口不断平移,计算所有窗口的点云法向量。作为最终结果。
2.使用场景
该方法适用于点云较密集的场景(最好是有序点云,无序点云也可以计算,但效果不好)。
不会计算所有点云点的法向量,会按照窗口计算其中窗口拟合出平面的法向量。
计算速度较快。
对于密集点云来说:生成的法向量较少,且具有代表性。
3.注意事项
(1)因只计算部分点的法向量,因此最后结果中有许多nan值。
(2)本类的下方函数,在注释中是计算单个点的法向量。输入为x、y。
在其源码中:xy用来计算索引,计算方式为:const int index = y * width + x;
使用的时候要注意。
computePointNormal()
4.关键函数
(1)计算对象边界的深度变化阈值
setNormalSmoothingSize()
(2)是否使用深度平滑(true为使用,false为不使用)
setDepthDependentSmoothing()
(3)平滑法线的区域大小(窗口大小)
setMaxDepthChangeFactor()
5.代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/features/linear_least_squares_normal.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>
int main()
{
/****************最小二乘法表面法线估计********************/
// 原始点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("D:/code/csdn/data/bunny.pcd", *cloud_in); // 加载原始点云数据
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
// 最小二乘法表面法线估计
pcl::LinearLeastSquaresNormalEstimation<pcl::PointXYZ, pcl::Normal> feature;
feature.setDepthDependentSmoothing(true); // 是否使用深度平滑
feature.setNormalSmoothingSize(10.0f); // 计算对象边界的深度变化阈值
feature.setMaxDepthChangeFactor(0.02f); // 平滑法线的区域大小(窗口大小)
feature.setInputCloud(cloud_in);
feature.compute(*normals);
pcl::Normal normal;
feature.computePointNormal(0.5, 0, normal);
/****************展示********************/
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer(""));
viewer->setBackgroundColor(0, 0, 0);
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color(cloud_in, 0, 225, 0);
viewer->addPointCloud<pcl::PointXYZ>(cloud_in, color, "sample cloud"); // 添加点云
viewer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(cloud_in, normals, 20, 0.02, "normals"); // 添加点云法向量
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}
6.结果展示
注意不是所有点云点都生成了法向量