首页 文章

渲染Voronoi图到numpy数组

提问于
浏览
2

我想根据中心列表和图像大小生成Voronoi区域 .

我尝试了下一个代码,基于https://rosettacode.org/wiki/Voronoi_diagram

def generate_voronoi_diagram(width, height, centers_x, centers_y):
    image = Image.new("RGB", (width, height))
    putpixel = image.putpixel
    imgx, imgy = image.size
    num_cells=len(centers_x)
    nx = centers_x
    ny = centers_y
    nr = list(range(num_cells))
    ng = nr
    nb = nr
    for y in range(imgy):
        for x in range(imgx):
            dmin = math.hypot(imgx-1, imgy-1)
            j = -1
            for i in range(num_cells):
                d = math.hypot(nx[i]-x, ny[i]-y)
                if d < dmin:
                    dmin = d
                    j = i
            putpixel((x, y), (nr[j], ng[j], nb[j]))
    image.save("VoronoiDiagram.png", "PNG")
    image.show()

我有所需的输出:

但是生成输出需要太多 .

我也尝试了https://stackoverflow.com/a/20678647这很快,但我没有知道如何将图像大小参数提供给scipy Voronoi class .

有没有更快的方法来获得此输出?不需要中心或多边形边缘

那么,是否可以使用一组点而不是单个点来生成每个区域?我想为图片中的形状生成Voronoi区域 . 到目前为止,我正在使用每个形状的质心,但我更喜欢使用形状的轮廓点作为其区域 .

提前致谢

1 回答

  • 4

    快速解决方案

    以下是如何将链接的fast solution based on scipy.spatial.Voronoi的输出转换为任意宽度和高度的Numpy数组 . 给定从链接代码中的 voronoi_finite_polygons_2d 函数输出的 regions, vertices 的集合,这里是一个将该输出转换为数组的辅助函数:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
    
    def vorarr(regions, vertices, width, height, dpi=100):
        fig = plt.Figure(figsize=(width/dpi, height/dpi), dpi=dpi)
        canvas = FigureCanvas(fig)
        ax = fig.add_axes([0,0,1,1])
    
        # colorize
        for region in regions:
            polygon = vertices[region]
            ax.fill(*zip(*polygon), alpha=0.4)
    
        ax.plot(points[:,0], points[:,1], 'ko')
        ax.set_xlim(vor.min_bound[0] - 0.1, vor.max_bound[0] + 0.1)
        ax.set_ylim(vor.min_bound[1] - 0.1, vor.max_bound[1] + 0.1)
    
        canvas.draw()
        return np.frombuffer(canvas.tostring_rgb(), dtype='uint8').reshape(height, width, 3)
    

    测试一下

    以下是 vorarr 的完整示例:

    from scipy.spatial import Voronoi
    
    # get random points
    np.random.seed(1234)
    points = np.random.rand(15, 2)
    
    # compute Voronoi tesselation
    vor = Voronoi(points)
    
    # voronoi_finite_polygons_2d function from https://stackoverflow.com/a/20678647/425458
    regions, vertices = voronoi_finite_polygons_2d(vor)
    
    # convert plotting data to numpy array
    arr = vorarr(regions, vertices, width=1000, height=1000)
    
    # plot the numpy array
    plt.imshow(arr)
    

    输出:

    如您所见,生成的Numpy数组确实具有 (1000, 1000) 的形状,如 vorarr 的调用中所指定的那样 .

    如果要修复现有代码

    以下是如何更改当前代码以使用/返回Numpy数组:

    import math
    import matplotlib.pyplot as plt
    import numpy as np
    
    def generate_voronoi_diagram(width, height, centers_x, centers_y):
        arr = np.zeros((width, height, 3))
        imgx,imgy = width, height
        num_cells=len(centers_x)
    
        nx = centers_x
        ny = centers_y
        nr = list(range(num_cells))
        ng = nr
        nb = nr
    
        for y in range(imgy):
            for x in range(imgx):
                dmin = math.hypot(imgx-1, imgy-1)
                j = -1
                for i in range(num_cells):
                    d = math.hypot(nx[i]-x, ny[i]-y)
                    if d < dmin:
                        dmin = d
                        j = i
                arr[x, y, :] = (nr[j], ng[j], nb[j])
    
        plt.imshow(arr.astype(int))
        plt.show()
        return arr
    

相关问题