Contour Lines¶

How the image is created¶
generate a regular grid of x and y positions
define x/y positions and widths of several hills
calculate the height of the hills as a Gaussian Mixture using the positions as means and the widths as standard deviations of a normal distribution, both for x and y separately
sum up the hills
scale and round the height to regular steps
You can put in any number of hills.
import numpy as np
from PIL import Image
# create a 400 x 400 grid
dim = np.linspace(-10, 10, 400)
x, y, _ = np.meshgrid(dim, dim, [1]) # the [1] adds an extra dimension
# positions and widths of the 'hills'
position_x = np.array([-3.0, 7.0, 9.0])
position_y = np.array([0.0, 8.0, -9.0])
width_x = np.array([5.3, 8.3, 4.0])
width_y = np.array([6.3, 5.7, 4.0])
# calculate height as a combination of Gaussians
d = np.sqrt(((x - position_x) / width_x) ** 2 + ((y - position_y) / width_y) ** 2)
z = np.exp(-d ** 2) # shape is (400, 400, 3) because we have 3 hills
z = z.sum(axis=2) # add the hills to get a single landscape
znorm = (z - z.min()) / (z.max() - z.min()) # normalize to range (0.0 .. 1.0)
# contour lines
contour = (znorm * 8).astype(np.uint8) * 32
im = Image.fromarray(contour, mode='L')
im.save('contour_steps.png')
# isolines
isolines = ((znorm * 100).round() % 16) == 0
isolines = (isolines * 255).astype(np.uint8)
im = Image.fromarray(isolines, mode='L')
im.save('contour_isolines.png')
Lines only¶
With a modulo instead of the rounded steps you get to see the contour lines or isolines:

Challenge¶
Generate random hill centers + sizes.