When I decided to leave jayway I wanted to leave something behind, I opted for a picture on the wall of some of my colleagues. Unfortunately I didn’t manage to get everyone in the picture, due to fractal limitations and lack of photos/time. I used a L-system or Lindenmayer systems for drawing line fractals and superimposing photos on the line. The whole thing evolved over time and became something different from what I envisaged when I started working on it.
My first goal was to render a Heighway dragon curve since I like the shape of it, turns out that it’s not ideal for the task at hand, but who cares if its a cool looking fractal that takes you in the right direction!
When I show a image and precede it with a “gradle run” line (like below), this is the repo I’m executing “gradle run” in: https://github.com/carlemil/LSystems
>gradle run -PlsArgs="['-i 12','-S 400','-b true','-t black']"
I will not show any code from the repo and the current state of the codebase where you can run it from the command line evolved over time as I needed new functionality. The command line options for the gradle run command can be seen here.
The black dragon fractal looks nice on its own, but I figured that some color seldom hurts the eye. Having used palettes (a subset of the full color space put in a array for easy picking by index) to color fractals and whatnot back in the nineties I decided that this old and tried technique should be used to get the job done once more. Below is a image showing my first palette, blending from one maxed out rgb value to another. If you want to see the colors/settings used in a palette you should have a look in the Theme.kt class.
>gradle run -PlsArgs="['-i 400','-S 400','-t fullbrights','-s Line','-w 4']"
And the colored version of the dragon fractal looks way cooler that the black version!
>gradle run -PlsArgs="['-i 12','-S 400','-b true','-t fullbrights']"
I soon got the idea to color it using a photo and just pick a color from the photo corresponding to the x, y position that the starting point of a line segment was located at. This could look pretty cool but the dragon curve didn’t seem particularly well suited for showing a image superimposed on the line itself since it is mostly empty space and not so much line (as mentioned just at the start). The Hilbert curve is a curve that really fills out space and this was perfect for my next goal of superimposing a image on top of the curve, or rather to color each segment of the line that makes up the curve so that the whole will resemble a image from far away.
>gradle run -PlsArgs="['-i 6','-S 400','-t fullbrights','-s HilbertCurve','-w 2']"
Now for the superimposing of a image, I tested with just a gray-scale image of myself to get a idea of what it could look like. The superimposition was done by converting the image to hsb format and looking up the pixel in the image that corresponds to the starting x, y of each line segment and then I used the brightness value from that pixel as brightness for the line segment.
>gradle run -PlsArgs="['-i 6','-S 400','-t white','-s HilbertCurve','-w 2','-p cekj.jpg']"
Combining the two techniques for coloring and shading a fractal I could now produce a photo superimposed on the colored fractal. To better visualize the fractal and the way the line wind its way through the image I added a checker pattern to the palette by making odd colors of the palette slightly darker. By using a palette size that is of the size 2^(x*2) (x being a positive integer) we maintain a checker pattern on the Hilbert curve. (this will not work on other versions of the fractal since the fractal dimension differs, so a different spacing of the dark colors is needed for each fractal, I have yet to generalize this in my codebase)
>gradle run -PlsArgs="['-i 6','-S 400','-t fullbrights','-s HilbertCurve','-w 2','-p cekj.jpg']"
This is starting to look promising. If we where to take a 2×2 or 4×4 or 8×8 montage of photos of my colleagues and use that as the brightness image we might get something worth putting on the wall. Again, the number of photos needs to be on the form 2^(n*2) to match the fractals structure and not look crappy like the image above where my head is cut in the middle by the light brown and blue/purple parts of the fractal.
Starting with 64 (8×8) photos of my colleagues in high res I had to scale them down to a smaller size (both for making them more manageable and also for smoothing out any noisy pixels I might pick up to high or low brightness values from while shading the image) and crop them to make them square before making a 8×8 montage of them. At fmwconcepts.com I found a script that uses imagemagick to crop and resize images, very handy to have this step already automated by someone else.
>for f in *.jpg; do ./squareup -m crop -s 128 "$f" "$f" ; done
And to create a montage of the images 8×8 in size I used imagemagicks montage option.
>magick montage -tile x8 -background #aaaaaa *.jpg ../montage.jpg
The -tile x8 option specifies that each line of images in the output should be 8 images wide, and given 64 total images that will result in a 8×8 output image. The -background #aaaaaa is there just to create a gray grid around the images, to slightly separate the images from each other.
Using this image as a brightness source for the Hilbert curve fractal I was now ready to render a montage of my colleagues. But I was so not happy with the palette so I opted for a pastel color palette instead. This palette just sweeps through the whole h range 0-360 of the hsb colorspace with fixed s = 30 and b = 100 values giving us a nice flow of pastel like colors.
>gradle run -PlsArgs="['-i 400','-S 400','-t hsv_gradient','-s Line','-w 4']"
After checking that the output looks similar to what I was looking for at a lower resolution and iterations count I started the final rendering. I changed to usingacheckerd version forthe final output.
>gradle run -PlsArgs="['-i 10','-S 20000','-t hsv_gradient_checkered','-s HilbertCurve','-w 2']"
Shown below is a scaled version of the 20000×20000 output image (at about 6% of the original size you can’t make you the line anymore) as well as a cutout from the full size image to give a idea of the actual resolution and size.
Pretty neat I think!
If you want to play around with this yourself just check out the repo and go nutts, and if you want to contribute please do, I still haven’t gotten around to adding the full syntax described here. The github repo for this project can be found here.
So long, and Thanks for all the fish!