PCL专栏目录及须知
Marching cubes(MC移动立方体3D重建)在HOPPE移动立方体重建一文中讲述了具体原理,本文原理解释,只涉及其RBF移动立方体方法的改进部分。
MC移动立方体重建(HOPPE)
1.RBF的改进
(1)设置离面约束点距离d
(2)根据现有点云数据,求解线性方程组,得到函数f(x)的参数
(3)使用MC方法确定三角面,其中Cube顶点数据值由f(x)定义。
具体流程为:
使用径向基函数(Radial Basis Function,RBF)生成函数空间,其中在表面处的函数值为0。
要成为RBF函数φ(x),需要满足条件:对于某一个固定点c,满足,
即对于围绕着某固定点c的等距的x,函数值相同。PCL使用的是这一径向基函数。
我们希望找到一个函数f,对于表面上点x,有f(x)=0。使用RBF函数的线性组合来表示函数f:
另外为避免在不相关的地方产生f(x)=0,将沿表面点的曲面法向量生成了一对离面约束点,一个在表面外,一个在表面内,他们距表面的距离为d,从而可以得到另外2组方程f(x)=d和f(x)=-d。其中距离d不能设置的过大,要保证离面约束点到生成他的点的距离是最近的。如下图所示,4个手指处生成的离面约束点不能交叠。
左图:手部模型;右图手指处表面和2组离面约束点形成表面的示意图
最后上述方程可以组合形成一个线性方程组,求解后即可得到f(x)。然后使用MC方法就可以得到三角化的表面。
2.完整代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/marching_cubes_rbf.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
int main()
{
/****************RBF移动立方体重建********************/
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>); // 源点云
pcl::io::loadPCDFile("D:/code/csdn/data/bunny2.pcd", *cloud);
// 计算法线
pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> n;
pcl::search::KdTree<pcl::PointXYZRGB>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZRGB>);
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(20); // k邻域搜索范围
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
n.compute(*normals);
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloudNormals(new pcl::PointCloud<pcl::PointXYZRGBNormal>); // 连接点云及法向量
pcl::concatenateFields(*cloud, *normals, *cloudNormals);
// RBF移动立方体重建
pcl::MarchingCubes<pcl::PointXYZRGBNormal>::Ptr segmentation(new pcl::MarchingCubesRBF<pcl::PointXYZRGBNormal>);
pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree2(new pcl::search::KdTree<pcl::PointXYZRGBNormal>);
tree2->setInputCloud(cloudNormals);
segmentation->setInputCloud(cloudNormals);
segmentation->setIsoLevel(0.0f); // 提取表面的iso级别
segmentation->setGridResolution(50, 50, 50); // 行进立方体网格分辨率
segmentation->setPercentageExtendGrid(0.0f); // 定义在点云的边框和网格限制之间的网格内应该保留多少自由空间
pcl::PolygonMesh triangles; // 存储最终三角化的网格模型
segmentation->reconstruct(triangles);
pcl::io::savePLYFile("D:/code/csdn/data/bunny4.ply", triangles);
/****************展示********************/
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("GridProjection"));
viewer->addPointCloud(cloud, "cloud");
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer0(new pcl::visualization::PCLVisualizer("GridProjection0"));
viewer0->setBackgroundColor(255, 255, 255);
viewer0->addPolygonMesh(triangles, "triangles");
viewer0->setRepresentationToWireframeForAllActors(); // 网格模型以线框图模式显示
while (!viewer->wasStopped() || !viewer0->wasStopped())
{
viewer->spinOnce(100);
viewer0->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return (0);
}
3.结果展示
原始点云
重建展示