PCL学习笔记——点云曲面重建(一)

一. 基于多项式平滑点云及法线估计的曲面重建

本小节介绍基于移动最小二乘法(MLS)的法线估计、点云平滑和数据重采样。有时,测量较小的对象时会产生一些误差,这些误差所造成的不规则数据如果直接拿来曲面重建的话会使重建的曲面不光滑或者有漏洞。这些不规则很难用统计分析消除,所以为了建立完整的模型必须对表面进行平滑处理和漏洞修复。在不能进行额外扫描的情况下,我们可以通过对数据重采样来解决这一问题,重采样算法通过对周围数据点进行高阶多项式插值来重建表面缺少的部分。此外,由多个扫描点扫描结果配准后得到的数据直接拿来曲面重建的话会产生“双墙”等人造伪数据,即某块区域会出现重叠的两个曲面。重采样算法也可以对这个问题进行处理。

PCL学习笔记——点云曲面重建(一)
图1 法线估计结果
PCL学习笔记——点云曲面重建(一)
图2 曲率图

如图1左侧,是一个由两组点云数据配后得到的数据集的表面法线估计的结果,由于配准造成的误差,法线有噪声,即使在同一平面上的点集,其法线方向不严格一致;右侧则是同一数据集经过点云平滑后再进行法线估计所得到的结果,明显比左图准确一致的多。为了对重采样前后曲率特征进行量化衡量,我们绘制出了数据集中每点的曲率,得到图2,与上图可视化结果一致,平滑处理前的曲率特征方差很大,而平滑后的则方差较小。

下面是一个用最小二乘法对点云进行平滑处理的例子
代码:

#include <pcl/point_types.h>          //PCL中所有点类型定义的头文件
#include <pcl/io/pcd_io.h>            //打开关闭pcd文件的类定义的头文件
#include <pcl/kdtree/kdtree_flann.h>  //kd-tree搜索对象的类定义的头文件
#include <pcl/surface/mls.h>          //最小二乘法平滑处理类定义头文件
int
main(int argc, char** argv)
{// 将一个适当类型的输入文件加载到对象PointCloud中
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
	// 加载bun0.pcd文件,加载的文件在 PCL的测试数据中是存在的 
	pcl::io::loadPCDFile("rabbit.pcd", *cloud);
	// 创建一个KD树
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
	// 输出文件中有PointNormal类型,用来存储移动最小二乘法算出的法线
	pcl::PointCloud<pcl::PointNormal> mls_points;
	// 定义对象 (第二种定义类型是为了存储法线, 即使用不到也需要定义出来)
	pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls;
	mls.setComputeNormals(true);  //设置在最小二乘计算中需要进行法线估计
	//设置参数
	mls.setInputCloud(cloud);
	mls.setPolynomialFit(true);
	mls.setSearchMethod(tree);
	mls.setSearchRadius(0.03);
	// 曲面重建
	mls.process(mls_points);
	// 保存结果
	pcl::io::savePCDFile("rabbit-mls.pcd", mls_points);
}

原教材中提供的bun0.pcd文件有问题,运行程序后会出现
“[pcl::PCDReader::readHeader] No points to read”
换用其他pcd文件则可以。

具体代码分析:

pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
	// 加载bun0.pcd文件,加载的文件在 PCL的测试数据中是存在的 
pcl::io::loadPCDFile("rabbit.pcd", *cloud);

由于例子中用到的pcd文件只有XYZ坐标,我们把它加载到PointCloud对象中,XYZ坐标字段在本演示中是必需有的,其他字段可有可无,但如果存在也会在处理后的输出点云中被保留。

mls.setComputeNormals(true);  //设置在最小二乘计算中需要进行法线估计

进行法线估计,如果不需要法线估计,就跳过这一步。

pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls;// 定义最小二乘法实现的对象mls

MovingLeastSquares模板类的第一个模板参数为点类型PointXYZ是设置输入点云类型的,输入的数据中只有xyz坐标字段,它在输出的时候被平滑了,而第二个模板参数为点类型PointNormal,即输出为只包含法线的点云。

mls.setPolynomialFit (true);

可以通过不需要多项式拟合来加快平滑速度,设置为ture时则在整个算法运行时采用多项式拟合来提高精度,缺省值和其他用来控制平滑过程的参数请参照相关类的API。

 pcl::io::savePCDFile ("bun0-mls.pcd", mls_points);         //保存结果

如果法线和处理后的原始数据必须在相同PointCloud对象中,则需要将这两字段连接起来形成新的点云。