我正在尝试创建一些像下面这样的艺术“图形”:![Red Voronoi art](https://istack.dev59.com/A2qU5.webp)
区域的颜色并不重要,我想实现的是沿着Voronoi区域的边缘的可变“厚度”(特别是它们在角落相遇时看起来像一个更大的圆形斑点,而在它们的中间点更薄)。我已经尝试通过手动“绘制”每个像素基于到每个质心的最小距离(每个关联一个颜色)来实现:
![Red Voronoi art](https://istack.dev59.com/A2qU5.webp)
![enter image description here](https://istack.dev59.com/2mBtF.webp)
n_centroids = 10
centroids = [(random.randint(0, h), random.randint(0, w)) for _ in range(n_centroids)]
colors = np.array([np.random.choice(range(256), size=3) for _ in range(n_centroids)]) / 255
for x, y in it.product(range(h), range(w)):
distances = np.sqrt([(x - c[0])**2 + (y - c[1])**2 for c in centroids])
centroid_i = np.argmin(distances)
img[x, y] = colors[centroid_i]
plt.imshow(img, cmap='gray')
或者使用scipy.spatial.Voronoi
,它也可以给我顶点的坐标,尽管我仍然不知道如何通过它们绘制具有所需变量厚度的线条。
from scipy.spatial import Voronoi, voronoi_plot_2d
# make up data points
points = [(random.randint(0, 10), random.randint(0, 10)) for _ in range(10)]
# add 4 distant dummy points
points = np.append(points, [[999,999], [-999,999], [999,-999], [-999,-999]], axis = 0)
# compute Voronoi tesselation
vor = Voronoi(points)
# plot
voronoi_plot_2d(vor)
# colorize
for region in vor.regions:
if not -1 in region:
polygon = [vor.vertices[i] for i in region]
plt.fill(*zip(*polygon))
# fix the range of axes
plt.xlim([-2,12]), plt.ylim([-2,12])
plt.show()
编辑:
我通过对每个单独区域进行腐蚀和角点平滑(如评论中建议的中值滤波器)来得到了比较满意的结果,然后将其绘制在黑色背景上。
res = np.zeros((h,w,3))
for color in colors:
region = (img == color)[:,:,0]
region = region.astype(np.uint8) * 255
region = sg.medfilt2d(region, 15) # smooth corners
# make edges from eroding regions
region = cv2.erode(region, np.ones((3, 3), np.uint8))
region = region.astype(bool)
res[region] = color
plt.imshow(res)