图1.左:使用dlib检测到具有标志性建筑的奥巴马总统图像。中心:地标的Delaunay三角剖分。右:对应的Voronoi图。

俄国数学家鲍里斯·尼古拉耶维奇·德劳内(Boris Nikolaevich Delaunay)用两种不同的方式拼写了他的姓氏-法劳德出版社的德劳内和其他地方的德隆。很少有人拥有以他们命名的算法或概念。但是Delaunay有一个数学概念是以他姓氏的每次拼写来命名的!— Delaunay三角剖分和Delone集。似乎还不够,到1913年,他成为俄罗斯三大登山家之一!

Delaunay博士 顾问是乔治·沃罗诺伊(Georgy Voronoy),后被命名为沃罗诺伊图。还有另一个有趣的琐事-Voronoy的博士学位。顾问是安德烈·马可夫(Andrey Markov)(是的,是马可夫链的马可夫,马可夫成名)。

什么是Delaunay三角剖分?

图2:Delaunay三角剖分偏爱小角度

给定平面中的一组点,三角剖分指的是将平面细分为三角形,这些点为顶点。在图1中,我们在左侧图像上看到了一组地标,在中间图像上看到了三角剖分。一组点可以有许多可能的三角剖分,但是Delaunay三角剖分之所以突出是因为它具有一些不错的特性。在Delaunay三角剖分中,选择三角形时应确保没有点位于任何三角形的外接圆之内。图2.显示了四个点A,B,C和D的Delaunay三角剖分。在顶部图像中,为了使该三角剖分成为有效的Delaunay三角剖分,C点应该在三角形ABD的外接圆之外,而A点应该在三角形的外侧。三角形BCD的外接圆。

Delaunay三角剖分的一个有趣特性是它不支持“瘦”三角形(即,一个大角度的三角形)。

图2显示了在移动点时三角剖分如何变化以拾取“胖”三角形。在顶部图像中,点B和D在x = 1.5处具有x坐标,在底部图像中,它们向右移至x = 1.75。在顶部图像角度中,ABC和ABD的角度较大,而Delaunay三角剖分在B和D之间创建了一条边缘,将两个大角度分为较小的角度ABD,ADB,CDB和CBD。另一方面,在底部图像中,角度BCD太大,并且Delaunay三角剖分创建了边缘AC以划分大角度。

有很多算法可以找到一组点的Delaunay三角剖分。最明显(但不是最有效)的方法是从任何三角剖分开始,然后检查任何三角形的外接圆是否包含另一个点。如果是这样,则翻转边缘(如图2所示)并继续直到没有外接圆包含点的三角形。

关于Delaunay三角剖分的任何讨论都必须包括Voronoi图,因为一组点的Voronoi图是其Delaunay三角剖分的数学对偶。

什么是Voronoi图?

图3. Voronoi图

给定平面中的一组点,Voronoi图会划分空间,以使边界线与相邻点等距。图3.显示了根据显示为黑点的点计算的Voronoi图的示例。您会注意到,每条边界线都经过两个点的中心。如果将相邻的Voronoi地区中的点连接起来,则会得到Delaunay三角剖分!

Delaunay三角剖分和Voronoi图之间的联系不止一种。乔治·沃罗诺伊(Georgy Voronoy)是鲍里斯·德劳内(Boris Delaunay)的博士学位。顾问。

给定一组点,您可以使用Subdiv2D类计算Delaunay三角剖分或Voronoi图。步骤如下。下一部分显示了一个完整的工作示例。

1.收集向量中的所有点。

C++

vector<Point2f> points;
// This is how you can add one point.
points.push_back(Point2f(x,y));

Python

points = []
# This is how you can add one point.
points.append((x, y))

2.使用矩形(rect)定义要分区的空间。如果您在上一步中定义的点是在图像上定义的,则此矩形可以是(0,0,width,height)。否则,您可以选择一个包围所有点的矩形。

C++

Mat img = imread("image.jpg");
Size size = img.size();
Rect rect(0, 0, size.width, size.height);

Python

img = cv2.imread("image.jpg");
size = img.shape
rect = (0, 0, size[1], size[0])

3.使用在上一步中获得的矩形创建Subdiv2D实例。

C++

Subdiv2D subdiv(rect);

Python

subdiv  = cv2.Subdiv2D(rect);

4.使用subdiv.insert(point)将点插入subdiv中。上面的视频显示了在细分中添加点时的三角剖分动画。

5.使用subdiv.getTriangleList获取Delaunay三角形的列表。

6.使用subdiv.getVoronoiFacetList获取Voronoi构面的列表。

Delaunay三角剖分和Voronoi图的OpenCV示例

这是一个完整的工作示例。我已经从OpenCV附带的示例中复制了一些代码,并对其进行了简化和修改,以适应我们的目的。OpenCV附带的python示例使用旧的(丑陋的)接口,因此我从头开始编写了它。此代码假定图像存储在image.jpg中,点存储在points.txt中。points.txt的每一行都包含一个点的x和y坐标,这些点之间用空格隔开。例如

207 242

210 269

214 297

220 322

229 349

C ++示例

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <fstream>using namespace cv;
using namespace std;// Draw a single point
static void draw_point( Mat& img, Point2f fp, Scalar color )
{circle( img, fp, 2, color, CV_FILLED, CV_AA, 0 );
}// Draw delaunay triangles
static void draw_delaunay( Mat& img, Subdiv2D& subdiv, Scalar delaunay_color )
{vector<Vec6f> triangleList;subdiv.getTriangleList(triangleList);vector<Point> pt(3);Size size = img.size();Rect rect(0,0, size.width, size.height);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]));// Draw rectangles completely inside the image.if ( rect.contains(pt[0]) && rect.contains(pt[1]) && rect.contains(pt[2])){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);}}
}//Draw voronoi diagram
static void draw_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(), CV_FILLED, CV_AA, 0);}
}int main( int argc, char** argv)
{// Define window namesstring win_delaunay = "Delaunay Triangulation";string win_voronoi = "Voronoi Diagram";// Turn on animation while drawing trianglesbool animate = true;// Define colors for drawing.Scalar delaunay_color(255,255,255), points_color(0, 0, 255);// Read in the image.Mat img = imread("image.jpg");// Keep a copy aroundMat img_orig = img.clone();// Rectangle to be used with Subdiv2DSize size = img.size();Rect rect(0, 0, size.width, size.height);// Create an instance of Subdiv2DSubdiv2D subdiv(rect);// Create a vector of points.vector<Point2f> points;// Read in the points from a text fileifstream ifs("points.txt");int x, y;while(ifs >> x >> y){points.push_back(Point2f(x,y));}// Insert points into subdivfor( vector<Point2f>::iterator it = points.begin(); it != points.end(); it++){subdiv.insert(*it);// Show animationif (animate){Mat img_copy = img_orig.clone();// Draw delaunay trianglesdraw_delaunay( img_copy, subdiv, delaunay_color );imshow(win_delaunay, img_copy);waitKey(100);}}// Draw delaunay trianglesdraw_delaunay( img, subdiv, delaunay_color );// Draw pointsfor( vector<Point2f>::iterator it = points.begin(); it != points.end(); it++){draw_point(img, *it, points_color);}// Allocate space for Voronoi DiagramMat img_voronoi = Mat::zeros(img.rows, img.cols, CV_8UC3);// Draw Voronoi diagramdraw_voronoi( img_voronoi, subdiv );// Show results.imshow( win_delaunay, img);imshow( win_voronoi, img_voronoi);waitKey(0);return 0;
}

Python

#!/usr/bin/pythonimport cv2
import numpy as np
import random# Check if a point is inside a rectangle
def rect_contains(rect, point) :if point[0] < rect[0] :return Falseelif point[1] < rect[1] :return Falseelif point[0] > rect[2] :return Falseelif point[1] > rect[3] :return Falsereturn True# Draw a point
def draw_point(img, p, color ) :cv2.circle( img, p, 2, color, cv2.cv.CV_FILLED, cv2.CV_AA, 0 )# Draw delaunay triangles
def draw_delaunay(img, subdiv, delaunay_color ) :triangleList = subdiv.getTriangleList();size = img.shaper = (0, 0, size[1], size[0])for t in triangleList :pt1 = (t[0], t[1])pt2 = (t[2], t[3])pt3 = (t[4], t[5])if rect_contains(r, pt1) and rect_contains(r, pt2) and rect_contains(r, pt3) :cv2.line(img, pt1, pt2, delaunay_color, 1, cv2.CV_AA, 0)cv2.line(img, pt2, pt3, delaunay_color, 1, cv2.CV_AA, 0)cv2.line(img, pt3, pt1, delaunay_color, 1, cv2.CV_AA, 0)# Draw voronoi diagram
def draw_voronoi(img, subdiv) :( facets, centers) = subdiv.getVoronoiFacetList([])for i in xrange(0,len(facets)) :ifacet_arr = []for f in facets[i] :ifacet_arr.append(f)ifacet = np.array(ifacet_arr, np.int)color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))cv2.fillConvexPoly(img, ifacet, color, cv2.CV_AA, 0);ifacets = np.array([ifacet])cv2.polylines(img, ifacets, True, (0, 0, 0), 1, cv2.CV_AA, 0)cv2.circle(img, (centers[i][0], centers[i][1]), 3, (0, 0, 0), cv2.cv.CV_FILLED, cv2.CV_AA, 0)if __name__ == '__main__':# Define window nameswin_delaunay = "Delaunay Triangulation"win_voronoi = "Voronoi Diagram"# Turn on animation while drawing trianglesanimate = True# Define colors for drawing.delaunay_color = (255,255,255)points_color = (0, 0, 255)# Read in the image.img = cv2.imread("image.jpg");# Keep a copy aroundimg_orig = img.copy();# Rectangle to be used with Subdiv2Dsize = img.shaperect = (0, 0, size[1], size[0])# Create an instance of Subdiv2Dsubdiv = cv2.Subdiv2D(rect);# Create an array of points.points = [];# Read in the points from a text filewith open("points.txt") as file :for line in file :x, y = line.split()points.append((int(x), int(y)))# Insert points into subdivfor p in points :subdiv.insert(p)# Show animationif animate :img_copy = img_orig.copy()# Draw delaunay trianglesdraw_delaunay( img_copy, subdiv, (255, 255, 255) );cv2.imshow(win_delaunay, img_copy)cv2.waitKey(100)# Draw delaunay trianglesdraw_delaunay( img, subdiv, (255, 255, 255) );# Draw pointsfor p in points :draw_point(img, p, (0,0,255))# Allocate space for Voronoi Diagramimg_voronoi = np.zeros(img.shape, dtype = img.dtype)# Draw Voronoi diagramdraw_voronoi(img_voronoi,subdiv)# Show resultscv2.imshow(win_delaunay,img)cv2.imshow(win_voronoi,img_voronoi)cv2.waitKey(0)

实现效果

相关源码下载地址:关注“图像算法”微信公众号,回复Delaunay,即可获取

如何使用OpenCV进行Delaunay三角剖分和Voronoi图相关推荐

  1. 基于C++(MFC)的二维Delaunay三角剖分与Voronoi图的算法及代码

    一. Delaunay三角网 Delaunay三角网的特性: (1)空圆性,任一三角形外接圆内部不包含其他点. (2)最接近:以最近临的三点形成三角形,且各线段(三角形的边)皆不相交. (3)唯一性: ...

  2. 数字图像处理 Delaunay三角剖分和Voronoi图

    一.什么是Delaunay三角剖分? 给定平面中的一组点,三角测量是指将平面细分为三角形,以这些点为顶点.在下图1中,我们在左图像中看到一组地标,在中间图像中看到三角剖分.一组点可以有许多可能的三角剖 ...

  3. openCV【实践系列】5——使用OpenCV进行Delaunay三角剖分

    使用OpenCV进行Delaunay三角剖分和Voronoi图 图1:左图奥巴马总统使用dlib检测到标志点,中间Delaunay三角剖分的标志点,右图:相应的Voronoi图     在面部标志的众 ...

  4. OpenCV delaunay三角剖分和voronoi镶嵌的实例(附完整代码)

    OpenCV delaunay三角剖分和voronoi镶嵌的实例 OpenCV delaunay三角剖分和voronoi镶嵌的实例 OpenCV delaunay三角剖分和voronoi镶嵌的实例 # ...

  5. 【opencv450-samples】delaunay 三角剖分和 voronoi 细分

    该程序演示了 delaunay 三角剖分和 voronoi 细分的迭代构造. This program demonstrates iterativeconstruction of delaunaytr ...

  6. TIN的构建、Delaunay三角网、Voronoi图

    一.TIN的三角剖分准则 (1)空外接圆准则 过每个三角形的外接圆均不包含点集的其余任何点. (2)最大最小角准则 两三角形中的最小内角>交换z凸四边形对角线后三角形的最小角. (3)最短距离和 ...

  7. 【计算几何】Delaunay 三角剖分原理与实现

    摘 要: 平面点集的三角剖分在数值分析以及图形领域,都是极为重要的一项预处理技术.作为一种广泛应用的三角剖分技术,Delaunay三角剖分通过最大化最小角确保接近与规则的三角网和唯一性.本文通过概述 ...

  8. 加权voronoi图 matlab,加权voronoi图matlab

    广义Voronoi图的快速生成算法_电力/水利_工程科技_专业资料.27 卷第 ... Voronoi图理论与应用新成... 3页 免费 Voronoi图理论与应用新成... 3页 免费 Vorono ...

  9. Matlab:Voronoi 图

    Matlab:Voronoi 图 绘图二维 Voronoi 图和 Delaunay 三角剖分 计算 Voronoi 图 离散点集 X 的 Voronoi 图将每个点 X(i) 周围的空间分解成影响区域 ...

最新文章

  1. Adam 又要“退休”了?耶鲁大学团队提出 AdaBelief,却引来网友质疑
  2. centos php svn,centos7中搭建svn服务器(示例代码)
  3. ArrayList的几种初始化方法
  4. 简单好用的PHP无限分类
  5. weblogic中设置数据源的注意点
  6. linux 返回非法指令,linux – ARM Cortex A7在内核模式下返回PMCCNTR = 0,在用户模式下返回非法指令(即使在PMUSERENR = 1之后)...
  7. ubuntu中文设置
  8. linux终端打开文本编辑器,linux - Linux打开默认终端文本编辑器 - 堆栈内存溢出
  9. 小白python语言基础
  10. Visual Studio Code配置
  11. ANSYS CFD网格划分笔记3
  12. 如何获取股票数据接口?
  13. 高新计算机考试培训 ppt,全国计算机高新技术考试.ppt
  14. ftp客户端安装,六款可以安装的ftp客户端
  15. Spark2.1.0 + CarbonData1.0.0集群模式部署及使用入门
  16. 浅论独立解决问题的能力的重要性
  17. hive建表(一)创建外部表
  18. 打峡谷之巅有眼缘 那不如我们自己写个猜数字 C语言
  19. AC自动机+状压dp hdu2825 Wireless Password
  20. 智能卷发器的原理和功能

热门文章

  1. 字典类型用于表示一维和二维数据?
  2. 工程师如何拥抱数字化转型?
  3. 在Excel中创建彩色的Harvey球
  4. JVM - 直接内存
  5. 主定理的证明及应用举例
  6. 实践是检验真理的唯一标准!!LoopBack 设置案例!
  7. 04-前端技术_ javaScript内置对象与DOM操作
  8. 正则表达式——python对字符串的查找匹配
  9. 【VS】InstallerProjects.vsix下载 Microsoft Visual Studio Installer Projects
  10. Java中的数组Array