Computer-generated Mondrian art #1

(1 comment)

Inspired by Michael Fogleman's blog post from 2011, here is a Python implementation of his algorithm for generating images which resemble the paintings of Dutch painter Piet Mondrian (1872 - 1944). A slightly different, object-oriented approach will be presented in a subsequent post.

Generated Mondrian image

The algorithm

We start with a canvas defined as the unit square $0 \le x \le1$, $0\le y \le 1$ (we will later map co-ordinates on this canvas to an SVG image). A line on this canvas is defined by the tuple (y, (x1,y2)) in the case of a horizontal line from (x1,y) to (x2,y) and by the tuple (x, (y1,y2)) in the case of a vertical line from (x,y1) to (x,y2). The lines are collected together in two lists associated with a dictionary, keyed by HORIZONTAL and VERTICAL which are the values True and False respectively. We start by setting down boundary lines along the edges of the canvas:

lines = {
     HORIZONTAL: [(0, (0,1)), (1, (0,1))],
     VERTICAL: [(0, (0,1)), (1, (0,1))]

Mondrian image generation: step 1

We add nlines lines in randomly-chosen orientations (horizontal or vertical) by first choosing a random point on an existing randomly-selected line to place the start point, and then finding the set of all the lines that can be reached by a perpendicular line from this point. The end point of our new line is the intersection of the perpendicular line with a randomly-chosen line from this set.

Of course, the first line to be added must cross the entire image:

Mondrian image generation: step 2

Subsequent lines may have several choices for their endpoints, however:

Mondrian image generation: step 3

Mondrian image generation: step 4

To colour the regions defined by the lines, we need to find the boxes defined by the intersections: to do this, we first sort the list of horizontal lines by their $y$-coordinate. Next, loop over this list and for each line find all the adjacent vertical lines which intersect it and extend above it: this gives the lower corners of the boxes with thier lower edges on this line.

Mondrian image generation: step 5

Next follow the vertical lines upwards and find their next intersections with a horizontal line to get the upper corners of the box. The boxes are stored as the tuple of coordinates (bx1, by1, bx2, by2) where (bx1, by1) is the lower lefthand corner and (bx2, by2) is the upper righthand corner.

Mondrian image generation: step 6

The box colour is selected at random from a weighted distribution: each colour is associated with a point on a cumulative probability distribution function (cdf) and a number chosen at random from a uniform distribution on [0,1). The value of this number then determines which colour is selected according to which range it falls into in the cdf.

colours = ['blue', 'red', 'yellow', 'white']
colours_cdf = [0.15, 0.3, 0.45, 1.0]

Thus, there is a probability of 0.15 that each of blue, red or yellow will be chosen and a probability of 0.65 for white.

Mondrian image generation: step 7

The SVG image is created by rendering a series of coloured rectangles for the "boxes" with rect element, followed by the lines. The canvas coordinates are simply multiplied by the desired SVG image width and height dimensions.

Current rating: 4


Comment deleted 2 years, 3 months ago

New Comment


required (not published)