Python 将Voronoi图单元格区域转换为像素坐标列表

Python 将Voronoi图单元格区域转换为像素坐标列表,python,numpy,image-processing,scipy,voronoi,Python,Numpy,Image Processing,Scipy,Voronoi,我正在使用Voronoi图进行图像处理()。 为了做到这一点,我需要创建一个元组(x,y像素位置)列表(coords_In_cell)的列表(cells) 我已经开发了一些蛮力算法来实现这一点(见下文),但它们太慢,无法处理10点以上的数据。scipy空间实用程序的效率似乎提高了1000倍以上。因此,我想使用scipy生成Voronoi图: 使用scipy生成Voronoi图相当简单,但不幸的是,我无法理解如何将单元格区域转换为像素坐标。最好的方法是什么 我发现了一个相关问题,但没有答案,因此

我正在使用Voronoi图进行图像处理()。 为了做到这一点,我需要创建一个元组(x,y像素位置)列表(coords_In_cell)的列表(cells)

我已经开发了一些蛮力算法来实现这一点(见下文),但它们太慢,无法处理10点以上的数据。scipy空间实用程序的效率似乎提高了1000倍以上。因此,我想使用scipy生成Voronoi图:

使用scipy生成Voronoi图相当简单,但不幸的是,我无法理解如何将单元格区域转换为像素坐标。最好的方法是什么

我发现了一个相关问题,但没有答案,因此被删除:

蛮力算法1(太慢)

导入数学
随机输入
从PIL导入图像
def距离(x1、y1、x2、y2):
返回数学缩聚(x2-x1,y2-y1)
#定义x和y边界的大小
屏幕宽度=1260
屏幕高度=1260
#定义应使用的点数
点数=16
#在给定的x和y边界内随机生成n个点的列表
点x坐标=随机样本(范围(0,屏幕宽度),点的数量)
点y坐标=随机样本(范围(0,屏幕高度),点数)
点=列表(zip(点x坐标、点y坐标))
#每个点都需要有相应的像素列表
点_像素=[]
对于范围内的i(len(点)):
点像素。追加([])
#对于边界内的每个像素,确定其最接近的点,并将其添加到点\像素的对应列表中
对于范围内的像素坐标(屏幕高度):
对于范围内的像素x坐标(屏幕宽度):
距离最近点的距离=浮动('inf')
最近点指数=1
对于点索引,枚举点(点):
距离点=距离(像素x坐标,像素y坐标,点[0],点[1])
如果(到点的距离<到最近点的距离):
最近点指数=点指数
距离最近点=距离最近点
点像素[最近点索引]。追加((像素x坐标,像素y坐标))
#每个点都需要有相应的质心
点\像素\质心=[]
对于点像素中的像素组:
x_和=0
y_和=0
对于像素组中的像素:
x_sum+=像素[0]
y_和+=像素[1]
x_平均值=x_总和/透镜(像素组)
y_平均值=y_总和/透镜(像素组)
点\像素\质心。追加((圆形(x \ U平均值)、圆形(y \ U平均值)))
#显示生成的voronoi图
display\u voronoi=Image.new(“RGB”(屏幕宽度、屏幕高度)、“白色”)
对于点像素中的像素组:
rgb=random.sample(范围(0255),3)
对于像素组中的像素:
显示\u voronoi.putpixel(像素,(rgb[0],rgb[1],rgb[2],255))
对于点\像素\质心中的质心:
打印(质心)
显示_voronoi.putpixel(质心,(1,1,1255))
display_voronoi.show()
蛮力算法2(也太慢):

导入数学
随机输入
从PIL导入图像
def距离(x1、y1、x2、y2):
返回数学缩聚(x2-x1,y2-y1)
#定义x和y边界的大小
屏幕宽度=500
屏幕高度=500
#定义应使用的点数
点数=4
#在给定的x和y边界内随机生成n个点的列表
点x坐标=随机样本(范围(0,屏幕宽度),点的数量)
点y坐标=随机样本(范围(0,屏幕高度),点数)
点=列表(zip(点x坐标、点y坐标))
#每个点都需要有相应的像素列表
点_像素=[]
对于范围内的i(len(点)):
点像素。追加([])
#对于边界内的每个像素,确定其最接近的点,并将其添加到点\像素的对应列表中
#通过从点向外不断增加圆圈来实现此目的
#如果圆圈重叠,那么谁是他们的第一个声称的位置
#跟踪像素是否已被使用
#这是通过一个布尔值的2D列表来完成的
是否绘制于=[]
对于范围内的i(屏幕宽度):
是否在.append([])上绘制
对于范围内的j(屏幕高度):
是否在[i]上绘制[u]。追加(False)
圆圈在增长=真
半径=1
当(圆圈在增长时):
圆圈正在增长=错误
对于点索引,枚举点(点):
对于范围内的i(点[0]-半径,点[0]+半径):
对于范围内的j(点[1]-半径,点[1]+半径):
#打印(str(i)+“vs”+str(len(正在绘制)))
如果(i>=0且i=0且j如果(不是在[i][j]和距离(i,j,点[0],点[1])上绘制的,而不是直接构建和查询Voronoi图,则更容易构建和查询标准搜索树。下面是我对代码的修改,使用scipy.spatial.KDTree确定每个像素位置的最近点,然后是结果的图像(带有500个Voronoi点的500x500图像)

代码仍然有点慢,但现在在Voronoi点的数量上可以很好地扩展。如果您避免为每个Voronoi单元构建像素位置列表,而只是直接在图像中设置数据,则速度可能会更快

最快的解决方案可能包括构建Voronoi diagam,一次遍历一个像素,关联最近的Voronoi单元,在需要时查看相邻的Voronoi单元(因为上一个像素提供了一个很好的猜测,可以找到下一个像素的Voronoi单元).但这将涉及到编写更多的代码,而像这样天真地使用KDTree可能不会产生巨大的收益:目前代码的缓慢部分是构建所有可以独立清理的每像素阵列/数据

import math
import random
from PIL import Image 
from scipy import spatial
import numpy as np

# define the size of the x and y bounds
screen_width = 500
screen_height = 500

# define the number of points that should be used
number_of_points = 500

# randomly generate a list of n points within the given x and y bounds
point_x_coordinates = random.sample(range(0, screen_width), number_of_points)
point_y_coordinates = random.sample(range(0, screen_height), number_of_points)
points = list(zip(point_x_coordinates, point_y_coordinates))

# each point needs to have a corresponding list of pixels
point_pixels = []
for i in range(len(points)):
    point_pixels.append([]) 

# build a search tree
tree = spatial.KDTree(points)

# build a list of pixed coordinates to query
pixel_coordinates = np.zeros((screen_height*screen_width, 2));
i = 0
for pixel_y_coordinate in range(screen_height):
    for pixel_x_coordinate in  range(screen_width):
        pixel_coordinates[i] = np.array([pixel_x_coordinate, pixel_y_coordinate])
        i = i+1

# for each pixel within bounds, determine which point it is closest to and add it to the corresponding list in point_pixels
[distances, indices] = tree.query(pixel_coordinates)

i = 0
for pixel_y_coordinate in range(screen_height):
    for pixel_x_coordinate in  range(screen_width):
        point_pixels[indices[i]].append((pixel_x_coordinate, pixel_y_coordinate))
        i = i+1

# each point needs to have a corresponding centroid
point_pixels_centroid = []

for pixel_group in point_pixels:
    x_sum = 0
    y_sum = 0
    for pixel in pixel_group:
        x_sum += pixel[0]
        y_sum += pixel[1]

    x_average = x_sum / max(len(pixel_group),1)
    y_average = y_sum / max(len(pixel_group),1)

    point_pixels_centroid.append((round(x_average), round(y_average)))


# display the resulting voronoi diagram
display_voronoi = Image.new("RGB", (screen_width, screen_height), "white")
for pixel_group in point_pixels:
    rgb = random.sample(range(0, 255), 3)
    for pixel in pixel_group:
        display_voronoi.putpixel( pixel, (rgb[0], rgb[1], rgb[2], 255) )

for centroid in point_pixels_centroid:
    #print(centroid)
    display_voronoi.putpixel( centroid, (1, 1, 1, 255) )

#display_voronoi.show()
display_voronoi.save("test.png")

T
import math
import random
from PIL import Image 
from scipy import spatial
import numpy as np

# define the size of the x and y bounds
screen_width = 500
screen_height = 500

# define the number of points that should be used
number_of_points = 500

# randomly generate a list of n points within the given x and y bounds
point_x_coordinates = random.sample(range(0, screen_width), number_of_points)
point_y_coordinates = random.sample(range(0, screen_height), number_of_points)
points = list(zip(point_x_coordinates, point_y_coordinates))

# each point needs to have a corresponding list of pixels
point_pixels = []
for i in range(len(points)):
    point_pixels.append([]) 

# build a search tree
tree = spatial.KDTree(points)

# build a list of pixed coordinates to query
pixel_coordinates = np.zeros((screen_height*screen_width, 2));
i = 0
for pixel_y_coordinate in range(screen_height):
    for pixel_x_coordinate in  range(screen_width):
        pixel_coordinates[i] = np.array([pixel_x_coordinate, pixel_y_coordinate])
        i = i+1

# for each pixel within bounds, determine which point it is closest to and add it to the corresponding list in point_pixels
[distances, indices] = tree.query(pixel_coordinates)

i = 0
for pixel_y_coordinate in range(screen_height):
    for pixel_x_coordinate in  range(screen_width):
        point_pixels[indices[i]].append((pixel_x_coordinate, pixel_y_coordinate))
        i = i+1

# each point needs to have a corresponding centroid
point_pixels_centroid = []

for pixel_group in point_pixels:
    x_sum = 0
    y_sum = 0
    for pixel in pixel_group:
        x_sum += pixel[0]
        y_sum += pixel[1]

    x_average = x_sum / max(len(pixel_group),1)
    y_average = y_sum / max(len(pixel_group),1)

    point_pixels_centroid.append((round(x_average), round(y_average)))


# display the resulting voronoi diagram
display_voronoi = Image.new("RGB", (screen_width, screen_height), "white")
for pixel_group in point_pixels:
    rgb = random.sample(range(0, 255), 3)
    for pixel in pixel_group:
        display_voronoi.putpixel( pixel, (rgb[0], rgb[1], rgb[2], 255) )

for centroid in point_pixels_centroid:
    #print(centroid)
    display_voronoi.putpixel( centroid, (1, 1, 1, 255) )

#display_voronoi.show()
display_voronoi.save("test.png")