1、PCL点云三角化
1.1 Delaunay三角剖分
定义:假设点集中的一条边e(两个端点为a,b),e若满足下列条件,则称之为Delaunay边:存在一个圆经过a,b两点,圆内(圆上最多三点共圆)不含点集中任何其他的点。而Delaunay三角化就是指三角网格均是由Delaunay边组成,并满足最小角最大原则(在点集可能形成的三角剖分中,Delaunay三角剖分所形成的三角形的最小角最大)。
1.2 贪婪三角化
PCL中采用将三维点云投影到二维平面的方法来实现三角剖分, 具体采用贪婪三角化算法。
其过程为:
1:计算点云中点的法线,再将点云通过法线投影到二维坐标平面。
2:使用基于Delaunay三角剖分的空间区域增长算法完成平面点集的三角化。
3:根据投影点云的连接关系确定原始三维点云间的拓扑关系,最终得到曲面模型。
2、代码:
using PclSharp;
using PclSharp.Features;
using PclSharp.Helpers;
using PclSharp.IO;
using PclSharp.Search;
using PclSharp.Struct;
using PclSharp.Surface;
using System;
namespace PclSharpTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"C#--PclSharp算法库测试:");
//读取点云数据
var cloud = new PointCloudOfXYZ();
using (var reader = new PCDReader())
reader.Read(AppDomain.CurrentDomain.BaseDirectory + $"//pcd//bun0.pcd", cloud);
// 计算法向量
var normals = new PointCloudOfNormal();//法线点云
using (var ne = new NormalEstimationOfPointXYZAndNormal())//法线估计对象
using (var tree = new KdTreeOfXYZ()) //创建用于最近邻搜索的KD-Tree
{
//法线估计
ne.SetSearchMethod(tree);
ne.SetInputCloud(cloud);
ne.KSearch = 10;// 使用当前点周围最近的10个点
ne.Compute(normals);//计算法线
}
//将点云与法线进行字段拼接
PointCloudOfPointNormal cloud_with_normals = new PointCloudOfPointNormal(); //法向量点云对象
//将点云和法线拼接一起
PclHelper.concatenateFields(cloud, normals, cloud_with_normals);
//创建搜索树
KdTree<PointNormal> tree2 = new KdTreeOfXYZNormal();
tree2.SetInputCloud(cloud_with_normals);
// 初始化贪婪三角形的对象
GreedyProjectionTriangulationOfPointNormal gp3 = new GreedyProjectionTriangulationOfPointNormal();
//创建多变形网格,用于存储结果
PolygonMesh triangles = new PolygonMesh();
gp3.SearchRadius = 0.025f; //设置连接点之间的最大距离用于确定k近邻的球半径
gp3.Mu = 2.5f; //设置最近邻距离的乘子,以得到每个点的最终搜索半径
gp3.MaximumNearestNeighbors = 100; //设置搜索的最近邻点的最大数量
gp3.MaximumSurfaceAngle = (Math.PI / 4); // 45 degrees(pi)最大平面角
gp3.MinimumAngle = (Math.PI / 18); // 10 degrees 每个三角的最小角度
gp3.MaximumAngle = (2 * Math.PI / 3); // 120 degrees 每个三角的最大角度
gp3.NormalConsistency = false; //如果法向量一致,设置为true
//设置搜索方法和输入点云
gp3.SetInputCloud(cloud_with_normals);
gp3.SetSearchMethod(tree2);
//执行重构,结果保存在triangles中
gp3.Reconstruct(triangles);
using (var visualizer = new PclSharp.Vis.Visualizer("a window"))
{
//创建两个观察视点
int v1 = 1;
int v2 = 2;
visualizer.CreateViewPort(0.0, 0.0, 0.5, 1.0, v1);
visualizer.CreateViewPort(0.5, 0.0, 1.0, 1.0, v2);
visualizer.SetBackgroundColor_ViewPort(0f, 0f, 0f, v1);
visualizer.SetBackgroundColor_ViewPort(0.05f, 0f, 0f, v2);
visualizer.AddPointCloud(cloud, "v1", v1);
visualizer.AddPolygonMesh(triangles, "v2",v2);
visualizer.SetPointCloudColor(0.5, 1, 1, "v1");//原始点云附色
while (!visualizer.WasStopped)
visualizer.SpinOnce(100);
}
Console.ReadKey();
}
}
}
3、编译结果: