贪婪三角化
pcl::PolygonMesh PclTool::projectionTriangulation(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
// 正态估计
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n; // 法线估计对象
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>); // 存储估计的法线
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>); // 定义kd树指针
tree->setInputCloud(cloud); // 用cloud构建tree对象
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(20);
n.compute(*normals); // 估计法线存储到其中
// 法线不应包含点法线+曲面曲率
// //连接XYZ字段和法线字段*
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields(*cloud, *normals, *cloud_with_normals); // 连接字段
//* cloud_with_normals = cloud + normals
// 定义搜索树对象
pcl::search::KdTree<pcl::PointNormal>::Ptr tree2(new pcl::search::KdTree<pcl::PointNormal>);
tree2->setInputCloud(cloud_with_normals); // 点云构建搜索树
// 初始化对象
pcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3; // 定义三角化对象
pcl::PolygonMesh triangles; // 存储最终三角化的网络模型
// 设置连接点之间的最大距离(最大边长)
gp3.setSearchRadius(0.025); // 设置连接点之间的最大距离,(即是三角形最大边长)
// 设置各参数值
gp3.setMu(2.5); // 设置被样本点搜索其近邻点的最远距离为2.5,为了使用点云密度的变化
gp3.setMaximumNearestNeighbors(100); // 设置样本点可搜索的邻域个数
gp3.setMaximumSurfaceAngle(M_PI / 4); // 设置某点法线方向偏离样本点法线的最大角度45
gp3.setMinimumAngle(M_PI / 18); // 设置三角化后得到的三角形内角的最小的角度为10
gp3.setMaximumAngle(2 * M_PI / 3); // 设置三角化后得到的三角形内角的最大角度为120
gp3.setNormalConsistency(false); // 设置该参数保证法线朝向一致
// Get result
gp3.setInputCloud(cloud_with_normals); // 设置输入点云为有向点云
gp3.setSearchMethod(tree2); // 设置搜索方式
gp3.reconstruct(triangles); // 重建提取三角化
// 附加顶点信息
std::vector<int> parts = gp3.getPartIDs();
std::vector<int> states = gp3.getPointStates();
return triangles;
}
//可视化
bool PclTool::viewerPcl(pcl::PolygonMesh& triangles)
{
// 初始化PCL可视化对象
pcl::visualization::PCLVisualizer viewer("3D Viewer");
// 设置背景颜色
viewer.setBackgroundColor(0, 0, 0);
// 添加三角化后的网格模型
viewer.addPolygonMesh(triangles, "triangles");
// 设置相机位置和方向
viewer.setCameraPosition(0, 0, 0, 0, 0, 1, 0, -1, 0);
// 启动可视化
while (!viewer.wasStopped())
{
viewer.spinOnce(100);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "End show " << std::endl;
return true;
}