鉴于Delaunay三角剖分在点云拟合方面有不错的应用,现对该算法的原理进行简单的汇总~
点集的三角剖分(Triangulation),对数值分析(如有限元分析)以及图形学来说,都是极为重要的预处理技术。尤其是Delaunay三角剖分,关于点集的很多种几何图都和Delaunay三角剖分相关,如Voronoi图,EMST树等。Delaunay三角剖分有最大化最小角“最接近于规则化的“的三角网和唯一性(任意四点不能共圆)两个特点。Delaunay三角剖分是变现三维形状的基础。可以通过这个物体的投影来建立二维视觉图,并用二维Delaunay三角剖分来分析识别该物体,或者将它与实物相比较。Delaunay剖分是连接计算机视觉与计算机图形学的桥梁。以下内容参考:http://www.cnblogs.com/RenLiQQ/archive/2008/02/06/1065399.html
3、平面图中所有的面都是三角面,且所有三角面的合集是散点集V的凸包。
//凸包的概念:用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点。
2、最大化最小角特性:在散点集可能形成的三角剖分中,Delaunay三角剖分所形成的三角形的最小角最大。从这个意义上讲,Delaunay三角网是“最接近于规则化的”三角网。具体的说是在两个相邻的三角形构成凸四边形的对角线,在相互交换后,两个内角的最小角不再增大。如下图所示:
Delaunay三角网格的性质可以推广到高维。一个三维点集的三角剖分是由四面体构成。下图显示了一个由两个四面体构成的简单三维Delaunay三角剖分。一个四面体的外接球来说明空接球准则。
input: 顶点列表(vertices) //vertices为外部生成的随机或乱序顶点列表
output:已确定的三角形列表(triangles)
初始化顶点列表
创建索引列表(indices = new Array(vertices.length)) //indices数组中的值为0,1,2,3,......,vertices.length-1
基于vertices中的顶点x坐标对indices进行sort //sort后的indices值顺序为顶点坐标x从小到大排序(也可对y坐标,本例中针对x坐标)
确定超级三角形
将超级三角形保存至未确定三角形列表(temp triangles)
将超级三角形push到triangles列表
遍历基于indices顺序的vertices中每一个点 //基于indices后,则顶点则是由x从小到大出现
初始化边缓存数组(edge buffer)
遍历temp triangles中的每一个三角形
计算该三角形的圆心和半径
如果该点在外接圆的右侧
则该三角形为Delaunay三角形,保存到triangles
并在temp里去除掉
跳过
如果该点在外接圆外(即也不是外接圆右侧)
则该三角形为不确定 //后面会在问题中讨论
跳过
如果该点在外接圆内
则该三角形不为Delaunay三角形
将三边保存至edge buffer
在temp中去除掉该三角形
对edge buffer进行去重
将edge buffer中的边与当前的点进行组合成若干三角形并保存至temp triangles中
将triangles与temp triangles进行合并
除去与超级三角形有关的三角形
end
以下摘自:http://www.cnblogs.com/zhiyishou/p/4430017.html
用图来解释伪代码过程,先用三点来做实例:
如图,随机的三个点
根据离散点的最大分布来求得随机一个超级三角形(超级三角形意味着该三角形包含了点集中所有的点),方法是根据相似三角形定理求得与矩形一半的小矩形的对角三角形,扩大一倍后则扩大后的直角三角形斜边经过点(Xmax,Ymin),但是为了将所有的点包含在超级三角形内,在右下角对该三角形的顶点进行了横和高的扩展,并要保证这个扩展三角形底大于高,才能实现包含。这样求得的超级三角形不会特别大使得计算复杂,而且过程也简单,并将超级三角形放入temp triangles中。
接下来就像是伪代码中描述的那样,对temp triangle中的的三角形遍历画外接圆,这时先对左边的第一个点进行判断,其在圆内,所以该三角形不为Delaunay三角形,将其三边保存至edge buffer中,temp triangle中删除该三角形。
将该点与edge buffer中的每一个边相连,组成三个三角形,加入到temp triangles中,
再将重复对temp triangles的遍历并画外接圆,这时使用的是第二个点来进行判断
再次对temp triangles进行遍历,这里该数组里则含有四个三角形,一个是上次检查跳过的含有第一个点的三角形和新根据第二个点生成的三个三角形
这时,temp buffer 中有六条边,triangles中有两个三角形,temp triangles中有1个三角形,对temp buffer中的六条边进行去重,得到五条边,将该点与这五条边组合成五个三角形并加入到temp triagnles 中,这时temp triangles中有6个三角形
由于三个点已经遍历结束,到了不会再对第三个点形成的三角形做外接圆,这时则将triangles与temp trianlges合并,合并后的数组表示包含已经确定的Delaunay三角形和剩下的三角形。这时除去合并后数组中的和超级三角形三个点有关的所有三角形,即进行数组坐标的限定,则得到了最后的结果:
实例1:(Matlab)
clear all;clc;close all;
%load seamount
[x,y,z]=peaks;
plot3(x,y,z);
%plot(x,y,'.','markersize',10)
xlabel('x'), ylabel('y')
grid on
tri = delaunay(x,y);
hold on, triplot(tri,x,y), hold off
figure
hidden on
trimesh(tri,x,y,z)
xlabel('x'),ylabel('y'),zlabel('Depth z');
左图为peaks函数的三维图形,有图为使用dalaunay三角剖分得到的三维模型,对比。
另外,在http://blog.csdn.net/newthinker_wei/article/details/45598769这篇博文里有使用opencv进行dalaunay三角剖分的讲述。
参考:
https://en.wikipedia.org/wiki/Delaunay_triangulation
http://www.cnblogs.com/RenLiQQ/archive/2008/02/06/1065399.html
http://www.linuxidc.com/Linux/2014-04/100131.htm
http://blog.csdn.net/newthinker_wei/article/details/45598769
http://cn.mathworks.com/help/matlab/math/delaunay-triangulation.html