将Voronoi图渲染为numpy数组

vir*_*ilo 4 python voronoi numpy scipy

我想根据中心列表和图像尺寸生成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,ng,nb=[],[],[]
    for i in range (num_cells):
        nr.append(randint(0, 255));ng.append(randint(0, 255));nb.append(randint(0, 255));

    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()
Run Code Online (Sandbox Code Playgroud)

我有所需的输出:

在此处输入图片说明

但是生成输出要花费太多时间。

我也尝试过/sf/answers/1447505321/, 它速度很快,但是我没有找到将其转换为img_width X img_height的numpy数组的方法。通常,因为我不知道如何为scipy Voronoi class设置图像大小参数。

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

提前致谢

编辑2018-12-11:使用@tel “快速解决方案”

在此处输入图片说明

代码执行速度更快,似乎中心已经转换。可能是这种方法在图像上增加了空白

tel*_*tel 6

快速解决方案

这是将链接到的快速解决方案scipy.spatial.Voronoi的输出转换为任意宽度和高度的Numpy数组的方法。给定regions, vertices您从voronoi_finite_polygons_2d链接代码中的函数获得的输出集合,下面是一个帮助函数,该函数会将输出转换为数组:

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)
Run Code Online (Sandbox Code Playgroud)

测试出来

这是一个实际的完整示例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 /sf/answers/1447505321/
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)
Run Code Online (Sandbox Code Playgroud)

输出:

在此处输入图片说明

如您所见,生成的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
Run Code Online (Sandbox Code Playgroud)