I was planning to add profile pictures to my now defunct social-app for musicians Riff on That and I wanted to offer a randomly generated picture as a default option. I had a look around for existing solutions in python and couldn’t find anything to my liking, so I came up with randimage
. This is a simple procedure that looks good to me, is simple to understand and is modular enough to experiment in the future with new variations. You can find the code and instructions on github - this post is meant as a more detailed explanation of how the procedure works.
How randimage works
At the core the procedure is composed of two simple steps:
- generate a random region-filling path
- color the pixels along the path using a colormap from matplotlib.
The idea is to leverage the many beautiful colormaps available in matplotlib to avoid reinventing the wheel — these offer a convenient way to continuously map any number between 0 and 1 to a color belonging to a specific curve in color-space. It is then enough to vectorize the image along some random path (step 1) and map point k in the path to k/N (where N is the length of the path), coloring the corresponding pixel with the value of the chosen colormap for k/N.
Finding a path with EPWT
I had several ideas in mind on how to find an interesting path (some of which I mention in the last section of this post), but to my delight the first try — the EPWT [1] applied to a randomly generated mask — gave quite interesting results so I decided to publish it as-is and maybe down the line play with other variants.
EPWT stands for “Easy Path Wavelet Transform” and it was proposed in [1] by my PhD supervisor Gerlind Plonka. The procedure is used for sparse image representation (e.g. image compression) and consists in applying a 1‑dimensional wavelet transform to a vectorized version of the image obtained through a greedy path-finding procedure, aimed at obtaining a succession of pixel values with minimal variation (which is a good thing for compression). It is a cool idea and there are many details and possible variants (including my own Region Based variant, the RBEPWT [2]).
More specifically the EPWT greedy path-finding procedure always picks as next point (among the available neighbors) the one that gives the minimum absolute value difference in pixel values. Generally speaking it will thus try to first fill in regions with similar pixel values before making a jump and moving on to much lighter or darker regions.
Mask -> EPWT -> color map -> profit
Summarizing, the idea is then to:
- create a random gray-valued mask image with same dimensions as the final image
- apply the EPWT path-finding procedure (starting from a randomly chosen point)
- pick a random color map
cmap
- map point k in the path to
cmap(k/N)
(wher N is the length of the path) - … hope to get a cool result.
Generating a mask
One way to generate the mask is to sum various Gaussian functions centered randomly in the image (in the code I do this by convolving a Gaussian filter with an array that is zero everywhere except for the chosen centers, where it is one). This often results in a structured EPWT path that approximately follows the level curves of the mask; here you can see one such mask and the image obtained using the EPWT path and the Spectral colormap:
If instead we use a so-called salt and pepper noise mask (each pixel is 1 with 0.5 probability and otherwise 0) we obtain a more noisy image:
Notice however the color still seems somewhat organized, going approximately from the bottom left to the the upper right of the image. This is probably due to the path getting temporarily stuck in the small contiguous regions of white or black. In fact the path gets even more noisy if instead we use Normal noise as mask:
A variant: stochastic EPWT
I also implemented a stochastic path finding procedure in the ProbabilisticPath
. Like the EPWT, at each step the pixel values of the available neighbors of a point are considered, however now the next point is chosen randomly among these using the pixel values as weights for the choice. In the following picture you can see a mask (generated with the GaussianBlobMask
class), the EPWT path and the probabilistic one:
Since the white areas in the mask correspond to higher probabilities, these act as sort of attractors for the probabilistic path.
What now?
The modularity of the procedure means we can try to substitute various parts of it to obtain new types of images. For example I thought of generating a random image segmentation and then applying the RBEPWT, which defines a path-finding procedure that will fill a region based on its shape rather than its pixel values:
You can read about the RBEPWT in [2] or in even more detail in Chapter 3 of my PhD disertation [4].
Given that the images with structure seem to look cooler and have more wow-effect, I would like experiment to with more rule-based procedures to generate paths taking inspiration for example from the flood fill algorithm or from cellular automaton.
About me
I’m a Math PhD currently working in Blockchain Technical Intelligence. I also have skills in software and data engineering, I love sports and music! Get in contact and let’s have a chat — I’m always curious about meeting new people.