二维delaunay(Voronoi图)算法与实现(C++、OpenCv、)

一、定义:

在这里插入图片描述

三角剖分:
假设V是二维实数域上的有限点集,边e是由点集中的点作为端点构成的封闭线段, E为e的集合。那么该点集V的一个三角剖分T=(V,E)是一个平面图G,该平面图满足条件(简言之就是满足所有三角形的最小角的和是最大的):

  • 1.除了端点,平面图中的边不包含点集中的任何点。
  • 2.没有相交边。
  • 3.平面图中所有的面都是三角面,且所有三角面的合集是散点集V的凸包
  • tips:在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。(用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。)

Voronoi图是Delaunay三角剖分的对偶图,生成它的方法有很多 ,比较有名的有分治算法,扫描线算法,增量法等。但利用Delaunay三角剖分生成Voronoi图的算法是最快的。

  • Voronoi图的应用非常广泛。在计算几何中,重心Voronoi图(CVT)方法被用来优化网格,可以使种子点变得更加均匀。在网络通讯中,利用加权Voronoi图设计中继站的位置可以提高利用率,降低成本。

二、特点:

Delaunay三角剖分有最大化最小角,“最接近于规则化的“的三角网和唯一性(任意四点不能共圆)两个特点:

  • 1、空圆特性:Delaunay三角网是唯一的(任意四点不能共圆),在Delaunay三角形网中任一三角形的外接圆范围内不会有其它点存在。如下图所示:
    在这里插入图片描述

  • 2、最大化最小角特性:在散点集可能形成的三角剖分中,Delaunay三角剖分所形成的三角形的最小角最大。从这个意义上讲,Delaunay三角网是“最接近于规则化的“的三角网。具体的说是指在两个相邻的三角形构成凸四边形的对角线,在相互交换后,六个内角的最小角不再增大。如下图所示:

在这里插入图片描述

Voronoi图特点

  • 1、每个多边形内仅含有一个中心点;
  • 2、每个多边形区域内的点到相应中心点的距离最近;
  • 3、位于多边形边上的点到其两边的中心的距离相等。

三、计算方法:

1.Lawson算法:

基本原理

  • 1.首先建立一个大的三角形或多边形,把所有数据点包围起来
  • 2.向其中插入一点,该点与包含它的三角形三个顶点相连,形成三个新的三角形
  • 3.然后逐个对它们进行空外接圆检测,同时用Lawson设计的局部优化过程LOP进行优化(即通过交换对角线的方法来保证所形成的三角网为Delaunay三角网)

优点:

  • 上述基于散点的构网算法理论严密、唯一性好,网格满足空圆特性,较为理想。
  • 由其逐点插入的构网过程可知,遇到非Delaunay边时,通过删除调整,可以构造形成新的Delaunay边。
  • 在完成构网后,增加新点时,无需对所有的点进行重新构网,只需对新点的影响三角形范围进行局部联网,且局部联网的方法简单易行。
  • 同样,点的删除、移动也可快速动态地进行。
    缺点:
  • 但在实际应用当中,这种构网算法当点集较大时构网速度也较慢,如果点集范围是非凸区域或者存在内环,则会产生非法三角形

2.Bowyer-Watson算法:

Watson算法的基本步骤是:

  • 1、构造一个超级三角形,包含所有散点,放入三角形链表。

  • 2、将点集中的散点依次插入,在三角形链表中找出外接圆包含插入点的三角形(称为该点的影响三角形),删除影响三角形的公共边,将插入点同影响三角形的全部顶点连接起来,完成一个点在Delaunay三角形链表中的插入。

  • 3、根据优化准则对局部新形成的三角形优化。将形成的三角形放入Delaunay三角形链表。

  • 4、循环执行上述第2步,直到所有散点插入完毕。

    这一算法的关键的第2步图示如下:
    在这里插入图片描述

四、实现:

采用opencv2,其他版本大致相同,代码解释可参考

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

using namespace cv;
using namespace std;

static void draw_subdiv_point( Mat& img, Point2f fp, Scalar color )
{
    circle( img, fp, 3, color, CV_FILLED, 8, 0 );
}

static void draw_subdiv( Mat& img, Subdiv2D& subdiv, Scalar delaunay_color )
{
#if 1
    vector<Vec6f> triangleList;
    subdiv.getTriangleList(triangleList);
    vector<Point> pt(3);

    for( size_t i = 0; i < triangleList.size(); i++ )
    {
        Vec6f t = triangleList[i];
        pt[0] = Point(cvRound(t[0]), cvRound(t[1]));
        pt[1] = Point(cvRound(t[2]), cvRound(t[3]));
        pt[2] = Point(cvRound(t[4]), cvRound(t[5]));
        line(img, pt[0], pt[1], delaunay_color, 1, CV_AA, 0);
        line(img, pt[1], pt[2], delaunay_color, 1, CV_AA, 0);
        line(img, pt[2], pt[0], delaunay_color, 1, CV_AA, 0);
    }
#else
    vector<Vec4f> edgeList;
    subdiv.getEdgeList(edgeList);
    for( size_t i = 0; i < edgeList.size(); i++ )
    {
        Vec4f e = edgeList[i];
        Point pt0 = Point(cvRound(e[0]), cvRound(e[1]));
        Point pt1 = Point(cvRound(e[2]), cvRound(e[3]));
        line(img, pt0, pt1, delaunay_color, 1, CV_AA, 0);
    }
#endif
}

static void locate_point( Mat& img, Subdiv2D& subdiv, Point2f fp, Scalar active_color )
{
    int e0=0, vertex=0;

    subdiv.locate(fp, e0, vertex);

    if( e0 > 0 )
    {
        int e = e0;
        do
        {
            Point2f org, dst;
            if( subdiv.edgeOrg(e, &org) > 0 && subdiv.edgeDst(e, &dst) > 0 )
                line( img, org, dst, active_color, 3, CV_AA, 0 );

            e = subdiv.getEdge(e, Subdiv2D::NEXT_AROUND_LEFT);
        }
        while( e != e0 );
    }

    draw_subdiv_point( img, fp, active_color );
}


static void paint_voronoi( Mat& img, Subdiv2D& subdiv )
{
    vector<vector<Point2f> > facets;
    vector<Point2f> centers;
    subdiv.getVoronoiFacetList(vector<int>(), facets, centers);

    vector<Point> ifacet;
    vector<vector<Point> > ifacets(1);

    for( size_t i = 0; i < facets.size(); i++ )
    {
        ifacet.resize(facets[i].size());
        for( size_t j = 0; j < facets[i].size(); j++ )
            ifacet[j] = facets[i][j];

        Scalar color;
        color[0] = rand() & 255;
        color[1] = rand() & 255;
        color[2] = rand() & 255;
        fillConvexPoly(img, ifacet, color, 8, 0);

        ifacets[0] = ifacet;
        polylines(img, ifacets, true, Scalar(), 1, CV_AA, 0);
        circle(img, centers[i], 3, Scalar(), -1, CV_AA, 0);
    }
}


int main( int, char** )
{

    Scalar active_facet_color(0, 0, 255),
		delaunay_color(255,255,255);
    Rect rect(0, 0, 600, 600);

    Subdiv2D subdiv(rect);
    Mat img(rect.size(), CV_8UC3);

    img = Scalar::all(0);
    string win = "Delaunay Demo";
    imshow(win, img);

    for( int i = 0; i < 200; i++ )
    {
        Point2f fp( (float)(rand()%(rect.width-10)+5),
                    (float)(rand()%(rect.height-10)+5));

        locate_point( img, subdiv, fp, active_facet_color );
        imshow( win, img );

        if( waitKey( 100 ) >= 0 )
            break;

        subdiv.insert(fp);

        img = Scalar::all(0);
        draw_subdiv( img, subdiv, delaunay_color );
        imshow( win, img );

        if( waitKey( 100 ) >= 0 )
            break;
    }

    img = Scalar::all(0);
    paint_voronoi( img, subdiv );
    imshow( win, img );

    waitKey(0);

    return 0;
}

二维delaunay运行效果:
在这里插入图片描述

Voronoi图:
在这里插入图片描述

Reference:

https://baike.baidu.com/item/Delaunay%E4%B8%89%E8%A7%92%E5%89%96%E5%88%86%E7%AE%97%E6%B3%95/3779918?fr=aladdin
https://baike.baidu.com/item/%E5%87%B8%E5%8C%85
https://blog.csdn.net/czl389/article/details/62264960?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-3.channel_param

### 回答1: Delaunay四面体和Voronoi是计算几何学中经常使用的两种形,它们之间存在着密切的关联。 Delaunay四面体是由一组点构成的三维空间中的四面体。具体来说,对于给定的一组点,Delaunay四面体是使得这些点形成四面体的方式中,最符合一定准则的四面体。这个准则被称为Delaunay条件,它要求四面体中不包含其他的点,同时四个顶点的外接圆不包含其他点。Delaunay四面体的存在性是由一个定理保证的,因此它是唯一的。Delaunay四面体在计算机形学、有限元分析等领域中有着广泛的应用。 Voronoi是由一组点构成的平面或空间中的分割。具体来说,对于给定的一组点,Voronoi将空间划分为一系列的区域,每个区域分别与一个点相关联,该点是该区域内离该点最近的点。Voronoi还可以表示为以点为中心的一组圆或球的并集,这些圆或球与彼此相邻的圆或球相切。Voronoi在计算机视觉、地理信息系统、计算机网络等领域中广泛应用。 Delaunay四面体和Voronoi之间的关联性体现在它们的对偶性上。具体来说,Delaunay四面体中的顶点对应着Voronoi中的区域的重心。反之,Voronoi中的边是由相应Delaunay四面体中的共享边定义的。这种对偶性使得Delaunay四面体和Voronoi可以相互转换,因此它们在实际应用中常常是一同使用的。 简而言之,Delaunay四面体和Voronoi是计算几何学中对点集的两种不同描述方式,它们通过对偶性相互关联,被广泛应用于许多领域中的空间分析和计算问题。 ### 回答2: Delaunay四面体和Voronoi是计算几何学中的两个重要概念,并且它们彼此密切相关。 Delaunay四面体是一个由一组点构成的特殊三维四面体。在形成Delaunay四面体时,我们要求通过这些点的圆内不包含其他点。因此,Delaunay四面体的特点是其外接圆包含了四面体上的所有点,且没有其他点位于这个外接圆内部。这个特性使得Delaunay四面体在计算几何学和三维重建中得到广泛应用,尤其是在网格生成和三角化方面。此外,Delaunay四面体有一些重要性质,如满足空圆性质和最大角性质等,这些性质使得它成为各种算法的重要基础。 与Delaunay四面体相对应的是Voronoi,也称为Voronoi剖分或泰森多边形。Voronoi根据一组点的位置将空间划分为若干个区域,每个区域包含离其最近的特定点,这些区域称为Voronoi区域。Voronoi的边界由相邻点之间的垂直平分线构成。Voronoi在计算几何学和空间分析中具有广泛的应用,例如网格生成、空间分析和地理信息系统等领域。Voronoi的性质使得它能够提供有关点集之间距离关系和邻近关系的信息,并在许多问题的求解中起到重要作用。 总之,Delaunay四面体和Voronoi可以看作是计算几何学中互为补充的两个概念。Delaunay四面体提供了一种三维空间中点集的表示方法和处理技术,而Voronoi则通过将空间划分为凸多面体来描述点集之间的距离关系。它们都在各自领域内发挥着重要的作用,并在许多计算问题的求解中发挥着重要的作用。 ### 回答3: Delaunay四面体和Voronoi是在计算几何中常用的两个概念。 Delaunay四面体是指在给定一组离散点的情况下,通过连接这些点形成的四面体网格结构。该网格由一组共面的四面体组成,满足以下条件:任意一个四面体的外接圆球不包含其他点。换句话说,Delaunay四面体网格是一种最优的三角化方法,它最大化了所有四面体的最小角度,并且具有唯一性。Delaunay四面体网格在计算机形学、有限元分析等领域中有广泛的应用,能够有效地处理离散点云数据。 Voronoi,又称为泰森多边形、Dirichlet或细胞分割,是指在给定一组点的情况下,通过将空间分割为多个区域的方法。每个点都有一个唯一的区域,该区域包含了离它最近的点。这种分割方式形成了一种形结构,称为VoronoiVoronoi的每个点都是由与它最近的离散点共享的两条边确定的,这些边称为Voronoi边。Voronoi在地理信息系统、像处理、计算机视觉等领域中有广泛的应用,能够提供空间数据的分段、分类和分析功能。 综上所述,Delaunay四面体和Voronoi是在计算几何中常用的两个概念。Delaunay四面体是通过给定一组离散点形成的最优四面体网格结构,而Voronoi是通过给定一组点形成的空间分割。它们在不同领域中有着广泛的应用,能够处理和分析离散点云数据以及提供空间数据的分割和分析功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值