一、算法原理
迫松重建法是一种基于隐式函数的三角网格重建算法,该方法通过对点云数据进行最优化的插值处理之后来获取近似的曲面。
迫松曲面重建的过程:
1、定义八叉树。使用八叉树结构存储点集,根据采样点集的位置定义八叉树,然后细分八叉树使每个采样点都落在深度为D的叶节点;
2、设置函数空间:对八叉树的每个节点设置空间函数F,所有节点函数F的线性和可以表示向量场V,基函数F采用了盒滤波的n维卷积;
3、创建向量场:均匀采样的情况下,假设划分的块是常量,通过向量场V逼近指示函数的梯度。采用三次条样插值(三线插值);
4、求解泊松方程:方程的解采用拉普拉斯矩阵迭代求出;
5、提取等值面:为得到重构表面,需要选择阈值获得等值面;先估计采样点的位置,然后用其平均值进行等值面提取,然后用移动立方体算法得到等值面。
二、重要参数详解
// 参数设置
p.setDepth(7); // 这个参数很重要,是重建算法中的八叉树的最大深度,这里的7 只是一个上限,在实际的重建过程中是自适应的
p.setMinDepth(2);
p.setScale(1.25); //设置尺度参数scale ,这个参数是进行重建的立方体体素对应的直径直径和采样时立方体直径的比值
p.setSolverDivide(3); // 设置在求解拉普拉斯等式时高斯-代尔塔-拉普拉斯的深度
p.setIsoDivide(8); // 设置等值面提取时候的深度,这个参数可以避免在重建的时候有可能出现的内存溢出的问题,当设置9 以上的时候内存使用会减少很多,
// 但是一般设置7 或者是8
p.setSamplesPerNode(10); // 设置每个八叉树上最少采样点数目,原因是八叉树的建立和点云的密度是自适应调节的,所以需要设置最小的数量,当采样点的噪声比较少的时候
// 该值可以设置的比较小【1,5】,当采样点噪声较大的时候【15,20】,这样有利于最终得到的平滑且无噪声的曲面重建
p.setConfidence(false); // 设置信度标志,true : 使用法线向量长度作为置信度信息 FALSE 表示在重建之前对法线进行归一化处理
p.setManifold(false); // 设置流行标志,如果设置为true ,那么在多边形进行细化三角是添加重心, false :不添加
p.setOutputPolygons(false); // 设置是否输出为多边形,true 多边形,false 三角化后的曲面模型
三、显示
代码:
#if 1 // 曲面重建 - 迫松重建
using namespace std;
int main()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); //待滤波点云
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>); //滤波后点云
///读入点云数据
cout << "->正在读入点云..." << endl;
pcl::PCDReader reader;
reader.read("elephant.pcd", *cloud);
cout << "\t\t<读入点云信息>\n" << *cloud << endl;
// 第一 计算 点云的法向量
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
kdtree->setInputCloud(cloud);
n.setInputCloud(cloud);
n.setSearchMethod(kdtree);
n.setKSearch(10);
n.compute(*normals); //
// 第二 将 原始点云和法向量
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields(*cloud,*normals,*cloud_with_normals);
// 第三、开始迫松重建
pcl::search::KdTree<pcl::PointNormal>::Ptr kdtree_poisson(new pcl::search::KdTree<pcl::PointNormal>);
kdtree_poisson->setInputCloud(cloud_with_normals);
pcl::Poisson<pcl::PointNormal> p;
p.setSearchMethod(kdtree_poisson);
p.setInputCloud(cloud_with_normals);
// 参数设置
p.setDepth(7); // 这个参数很重要,是重建算法中的八叉树的最大深度,这里的7 只是一个上限,在实际的重建过程中是自适应的
p.setMinDepth(2);
p.setScale(1.25); //设置尺度参数scale ,这个参数是进行重建的立方体体素对应的直径直径和采样时立方体直径的比值
p.setSolverDivide(3); // 设置在求解拉普拉斯等式时高斯-代尔塔-拉普拉斯的深度
p.setIsoDivide(8); // 设置等值面提取时候的深度,这个参数可以避免在重建的时候有可能出现的内存溢出的问题,当设置9 以上的时候内存使用会减少很多,
// 但是一般设置7 或者是8
p.setSamplesPerNode(10); // 设置每个八叉树上最少采样点数目,原因是八叉树的建立和点云的密度是自适应调节的,所以需要设置最小的数量,当采样点的噪声比较少的时候
// 该值可以设置的比较小【1,5】,当采样点噪声较大的时候【15,20】,这样有利于最终得到的平滑且无噪声的曲面重建
p.setConfidence(false); // 设置信度标志,true : 使用法线向量长度作为置信度信息 FALSE 表示在重建之前对法线进行归一化处理
p.setManifold(false); // 设置流行标志,如果设置为true ,那么在多边形进行细化三角是添加重心, false :不添加
p.setOutputPolygons(false); // 设置是否输出为多边形,true 多边形,false 三角化后的曲面模型
//============ 显示-=======
pcl::PolygonMesh mesh;
p.performReconstruction(mesh);
// pcl::io::savePLYFile("object_mesh.ply", mesh);
//------------------------------可视化重建结果----------------------------------
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D viewer"));
viewer->setBackgroundColor(0, 0, 0);
viewer->setWindowName("3D_Rect");
viewer->addPolygonMesh(mesh, "my");
viewer->initCameraParameters();
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}
#endif