点云的平滑与法线计算

需要平滑的情况:

1、用RGB-D激光扫描仪等设备扫描物体,尤其是比较小的物体时,往往会有测量误差。这些误差所造成的不规则数据如果直接拿来曲面重建的话,会使得重建的曲面不光滑或者有漏洞,而且这种不规则数据很难用前面我们提到过的统计分析等滤波方法消除;

2、后处理过程中,对同一个物体从不同方向进行了多次扫描,然后把扫描结果进行配准,最后得到一个完整的模型,但是你配准的结果不一定准,比如,同一面墙壁由于配准误差变成了“两面墙”,并不能完全重叠。

通过重采样实现点云平滑

      点云重采样是通过“移动最小二乘”(MLS, Moving Least Squares )法来实现的,对应的类名叫做pcl::MovingLeastSquares

移动最小二乘法与传统的最小二乘法相比,有两个比较大的改进:

( 1)拟合函数的建立不同。这种方法建立拟合函数不是采用传统的多项式或其它函数,而是由一个系数向量 a(x)和基函数 p(x)构成, 这里 a(x)不是常数,而是坐标 x 的函数。 
( 2)引入紧支( Compact Support)概念,认为点 x 处的值 y 只受 x 附近子域内节点影响,这个子域称作点 x 的影响区域, 影响区域外的节点对 x的取值没有影响。在影响区域上定义一个权函数w(x), 如果权函数在整个区域取为常数, 就得到传统的最小二乘法。

1、拟合函数的建立:
在拟合区域的一个局域子域 U 上,拟合函数表示:

式中,a( x) = [a1 ( x) ,a2 ( x) …am ( x) ]T为为待求系数,它是坐标 x 的函数,p( x) = [p1 ( x) ,p2 ( x) …pm ( x) ]T 称为基
函数,它是一个阶完备的多项式,是基函数的项式[7],常用的二次基为 [1,u,v,u^{2}v^{2},uv]T.所以式( 1) 中的拟合函
数通常表示为 

   

 使上式的函数最小化,w( x - xi ) 是节点 xi 的权函数。

2 、权函数的确定

     权函数是移动最小二乘法的核心。在移动最小二乘法中,权函数 w( x - xi ) 应该具有紧支性,即权函数在 x 的一个子域内不等于 0,在这个子域外全是 0,这个子域称为权函数的支持域( 即 x 的影响域) ,其半径记为 s。常用的权函数为立方样条权函数:

                           

hi 为第 i 节点的权函数支持域的大小,β 为引入的影响系数。

// 对点云重采样  
pcl::search::KdTree<PointT>::Ptr treeSampling (new pcl::search::KdTree<PointT>); // 创建用于最近邻搜索的KD-Tree
pcl::PointCloud<PointT> mls_points;   //输出MLS
pcl::MovingLeastSquares<PointT, PointT> mls;  // 定义最小二乘实现的对象mls
mls.setComputeNormals (false);  //设置在最小二乘计算中是否需要存储计算的法线
mls.setInputCloud (cloud_filtered);        //设置待处理点云
mls.setPolynomialOrder(2);             // 拟合2阶多项式拟合,一般取2-5
mls.setPolynomialFit (false);  // 设置为false可以 加速 smooth
mls.setSearchMethod (treeSampling);    // 设置KD-Tree作为搜索方法
mls.setSearchRadius (0.05); // 单位m.设置用于拟合的K近邻半径,越大平滑力度越大
mls.process (mls_points);        //输出

估计点云的表面法线

点云的法线计算一般有两种方法:
1、使用曲面重建方法,从点云数据中得到采样点对应的曲面,然后再用曲面模型计算其表面的法线
2、直接使用近似值直接从点云数据集推断出曲面法线,这里主要用第2种方法来近似估计点云中每个点的表面法线。具体来说,就是把估计某个点的表面法线问题简化为:从该点最近邻计算的协方差矩阵的特征向量和特征值的分析,

从该点的周围点邻域(也称为k邻域)估计一点处的表面法线 ,所以这个K邻域的选取也很关键。

// 法线估计
pcl::NormalEstimation<PointT, pcl::Normal> normalEstimation;                    //创建法线估计的对象
normalEstimation.setInputCloud(cloud_smoothed);                                    //输入点云
pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>);          // 创建用于最近邻搜索的KD-Tree
normalEstimation.setSearchMethod(tree);
pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);     // 定义输出的点云法线
// K近邻确定方法,使用k个最近点,或者确定一个以r为半径的圆内的点集来确定都可以,两者选1即可
normalEstimation.setKSearch(10);                    // 使用当前点周围最近的10个点
//normalEstimation.setRadiusSearch(0.03);            //对于每一个点都用半径为3cm的近邻搜索方式
normalEstimation.compute(*normals);                 //计算法线

点云法向量计算步骤:

猜你喜欢

转载自blog.csdn.net/qq_30815237/article/details/86301545