...or, what nowadays one might call "non-AI generative art." Over this Memorial Day weekend, I played with a few simple algorithms, inspired by an old Stack Exchange code golf. The intention here isn't to stomp on AI-based generative art, but just to remember the simple pleasures of creating pretty pictures with math.
The details are all at the github repository, but I thought I'd share some examples here.
Generate Images with Color Similarity #
This is inspired by the code golf submission from user fejesjoco, though it's not the same. I pick a initial pixel and color at random, then place each subsequent color such that it's nearest to the colors of its filled neighbors. The "neighbor distance" metric is the minimum distance from all of a pixel's filled neighbors.
The original list of colors was the 32768 15-bit colors, and the idea was to fill a 256x128 image such that every pixel had a unique color. Here's what that looks like (resized to a square):
I can also generate images using another image as the color source. You can see more examples in my example notebook.
This algorithm generates lovely pictures, but it's fairly slow, since it must visit every point on the canvas multiple times, and do calculations each time.
Generate Images with a Series of Random Walks #
Again, the goal here is to fill the image with unique pixel colors. I pick a start point and a start color at random, then sort the colorlist by distance from the starting point. Then the starting point picks a random direction (up/down/left/right) to go. If the next pixel hasn't been filled, then we step there, filling it with the next color on the list. This continues until we reach a dead end (a point where all the neighbors are already filled). Then we pick another random (unfilled) starting point and (unused) starting color, and take another walk. This continues until every color has been used, which also colors every pixel.
That looks like this (again, resized to a square):
This one is not quite as pretty (to my mind), but it's a little faster. With good bookkeeping, you only visit every point once, with no calculation, other than the color re-sorting at the beginning of a walk. The problem is that (as we will see), a random walk crosses itself quite frequently if left alone, and we do reach dead ends quite a lot with this procedure. So I wouldn't call it fast.
There are more examples in the example notebook.
Random Walk of a Bug in Paint #
Let's give up on filling every pixel of the image, though we will walk through all the colors on our colorlist. This time, we'll put a "bug" (a point) on a square plate, and let it randomly walk around (up/down/left/right), with crossings. Each footstep is a different color from the colorlist. This is quite fast, and can produce some pretty pictures.
Here, I started at a random point with a random color from the 15-bit colorlist, and then sorted the colorlist by distance from the starting color. You can also get some interesting effects by walking the colors from a source image with no re-sorting. Here's what happened when I used this image
and traversed the colors from the painting in order, line by line, as my bug wandered its plate:
The primary reason I implemented this was to animate the walk, so my function produces (fairly large) animated gifs, in addition to the final image. Here's an animation of the above image being created. You can see how often the bug walks over the same area of the plate. This will give you an idea of why filling the image space by random walk takes so long.
You can see more examples in the example notebook. There's also more here, including the gif-to-mp4 conversion code. The mp4s tend to be much smaller than the original gifs.
And that's my weekend so far! Hope yours has been fun, too.