# Generating Voronoi cells in Python

Voronoi cells are basically the shape you see soap suds make. They have a lot of cool properties that I wanted to use for image generation, but I didn’t want to have to figure out the math myself. I found this really excellent tutorial on generating Voronoi cells, which goes into some interesting history about them, too!

However, the Python code was a little out-of-date (and I think the author’s primary language was C++), so I wanted to clean up the example a bit.

It’s always a little tricky combining numpy and cv2, since numpy is column-major and cv2 is row-major (or maybe visa versa?) so I’m doing a rectangle instead of a square to make sure the coordinates are all ordered correctly. I started with some initialization:

``````import cv2
from matplotlib import pyplot as plt
import numpy as np

random.seed(42)
width = 256
height = 128
num_points = 25``````

Then we can use the Subdiv2D class and add a point for each cell:

``````subdiv  = cv2.Subdiv2D((0, 0, width, height))

def RandomPoint():
return (int(random.random() * width), int(random.random() * height))

for i in range(num_points):
subdiv.insert(RandomPoint())``````

Then it just spits out the cells!

``````# Note that this is height x width!
img = np.zeros((height, width, 3), dtype=np.uint8)

def RandomColor():
"""Generates a random RGB color."""
return (
random.randint(0, 256),
random.randint(0, 256),
random.randint(0, 256))

# idx is the list of indexes you want to get, [] means all.
facets, centers = subdiv.getVoronoiFacetList(idx=[])
for facet, center in zip(facets, centers):
# Convert shape coordinates (floats) to int.
ifacet = np.array(facet, int)

# Draw the polygon.
cv2.fillConvexPoly(img, ifacet, RandomColor(), cv2.LINE_AA, 0)

# Draw a black edge around the polygon.
cv2.polylines(img, np.array([ifacet]), True, (0, 0, 0), 1, cv2.LINE_AA, 0)

# Draw the center point of each cell.
cv2.circle(
img, (int(center), int(center)), 3, (0, 0, 0), cv2.FILLED, cv2.LINE_AA, 0)``````

Finally, write img to a file or just it display with:

``plt.imshow(img)``

If you use 42 as the seed, you should see exactly: