[Toy]自动生成Low Poly风格图像 —— 基于Edge Drawing和Delaunay

 

大概是暑假期间,和学弟讨论了一下这个问题,当时只草草分析了一下问题的解决思路,但是自己一直没有功夫动手实现。刚好国庆期间浪完返校,就想写个程序收收心。于是就把这个Low Poly做了一下。

还是惯例先贴一下实现结果:

一、本文提供的资源

程序的百度网盘链接:https://pan.baidu.com/s/1YlTIMPv4VjxOtUmkdRiF5w 密码:ufwu

bilibili程序演示视频:https://www.bilibili.com/video/av33758221

二、程序信息

编程语言:C++(Qt)。程序除了自动生成Low Poly图像外,还允许用户使用鼠标对Polygon进行编辑调整。具体使用操作见我录制的的Bilibili视频

程序的界面如下:

程序界面
图像的编辑模式

三、参考文献:
[1] Meng Gai, Guoping Wang. Artistic Low Poly Rendering for Images.

[2] Cihan Topal, Cuneyt Akinlar. Edge Drawing:A Combined Real-time Edge and Segment Detector.

四、程序的算法流程

这里简单的介绍了本程序所采用的算法思路,重点说明了采用文献[2]的Edge Drawing方法的单像素边缘提取方法。

1. 高斯模糊

     同传统的图像处理程序一样,我们首先对原始图像进行高斯模糊(Gaussian Blur),以减弱图像噪声并平滑图像。关于这一步的处理,可以参考我的另一篇博客

2. Edge Drawing - 单像素宽度的边缘检测

     Edge Drawing是Topal等[2]提出的一种有效的边缘检测算法。同Canny、Sobel等传统边缘提取算法相比,Edge Drawing的一个优势是:能够提出到干净的单像素宽的边缘线条,并且在算法中能够准确的获取到这些数据结构。

      图1是两种算法的对比图,能够发现Edge Drawing算法能够更加有效的获取边缘信息。

图1   Sobel算法(左)和EdgeDrawing算法(右)的对比

    Edge Drawing算法的详细流程如下:

   (1)计算Gradient map(map G)。map G用来反映图像亮度梯度的变化。这里可以采用任意梯度计算的算子进行计算,如Sobel、Prewitt等。map G中的每个像素的梯度变化可由公式G= \sqrt{Gx^{2}+Gy^{2}}计算得到。

   (2)计算Direction map(map D)。mapD可与Gradient map同时计算得到。如果|Gx|\geqslant |Gy|,则一条竖直方向的边通过该像素;如果|Gx|< |Gy|,则一条水平方向的边经过该像素。

   (3)锚点提取(Extraction of Archors)。这里archors中的顶点,被用于作为图像边缘edges的起始分析点。我们对原始图像进行二次求导,即对Gradient map进行一次求导。此时计算结果反映的是亮度梯度的变化率。我们采用亮度梯度变化率较大的点作为图像的archor点。其算法流程如图2所示:

图2 对像素(x,y)判断是否为锚点archor

  (4)边缘路径追踪。这里我们对每个锚点进行边缘路径追踪,以生成图像的edges。首先Direction map反映了通过某点的edge方向,因此对于水平、竖直两方向的点有如下几个探测方向,如图3所示:

图3 水平方向的探测方向和竖直方向的探测方向

          之后,我们对每个archor进行相反方向的路径追踪,这可以是一个递归算法。图4反映了向左追踪的算法流程,其余几个方向与之类似。图5反映了以点(4,8)为起点的路径追踪结果。

图4  向左追踪的处理
图5 以点(4,8)为起点的路径追踪结果

3. 三角形顶点提取

    此处的顶点提取,我们采取一种简单的策略。即在Edge Drawing中获取到的各个边缘,限制每条Edge在经过minLen个像素宽度时变发生断裂(例如minLen = 5),这时所有Edge在断裂后余下的点就是我们Delaunay三角剖分的输入。

4. Delaunay三角剖分

   Delaunay三角剖分是一种很常见的将离散点转变成三角网格的处理算法,其实现也较为简单。不过需要提的一点是,建议参考维基中提及的flipped优化方法来实现,该策略能够将算法耗时显著降低。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章