What is this?
A
simulated annealing like optimization algorithm, a reimplementation of
Roger Alsing's excellent idea.
The goal is to get an
image represented as a collection of overlapping polygons of various colors and transparencies.
We start from random 50 polygons that are invisible. In each optimization step we randomly modify one parameter
(like color components or polygon vertices) and check whether such new variant looks more like the original image.
If it is, we keep it, and continue to mutate this one instead.
Fitness is a sum of pixel-by-pixel differences from the original image. Lower number is better.
Displayed fitness is now a percentage of how close the new image is to the original one (1-current difference/maximum difference). The best possible is 100%.
This new fitness is normalized so that it's easier to compare different images and different sizes.
This implementation is based on Roger Alsing's description, though not on his code. There are probably some subtle differences
in how the mutations are done, how the polygons are represented and how the fitness is computed as I tried to figure out how to
have it running reasonably fast in JavaScript + <canvas> environment.
How does it look after some time?
- 50 polygons (4-vertex)
- ~15 minutes
- 644 benefitial mutations
- 6,120 candidates
- 88.74% fitness
- 50 polygons (6-vertex)
- ~15 minutes
- 646 benefitial mutations
- 6,024 candidates
- 89.04% fitness
- 50 polygons (10-vertex)
- ~15 minutes
- 645 benefitial mutations
- 5,367 candidates
- 87.01% fitness
- 50 polygons (6-vertex)
- ~45 minutes
- 1,476 benefitial mutations
- 23,694 candidates
- 93.35% fitness
- 50 polygons (6-vertex)
- ~60 minutes
- 1,595 benefitial mutations
- 28,888 candidates
- 93.46% fitness
- 50 polygons (6-vertex)
- ~120 minutes
- 1,966 benefitial mutations
- 50,500 candidates
- 93.89% fitness
- 50 polygons (6-vertex)
- ~4 hours
- 4,134 benefitial mutations
- 807,890 candidates
- 95.59% fitness
- Thanks to Sergei.
- 50 polygons (6-vertex)
- ~2 days
- 7,425 benefitial mutations
- 5,288,801 candidates
- 96.36% fitness
- Thanks to Julian.
- 1,000 polygons (12-vertex)
- ~7 days
- 21,135 benefitial mutations
- 8,143,969 candidates
- 97.12% fitness
- Thanks to Bogdan.
Does it work on all images?
It depends, success varies. The best seem to be color images with well defined features.
- 50 polygons (6-vertex)
- 4,358 benefitial mutations
- 227,852 candidates
- 95.97% fitness
- Thanks to Quialiss.
- Images from different runs.
- 50 polygons (6-vertex)
- 718+ benefitial mutations
- 22,440+ candidates
- 95.24% fitness
- Images from different runs.
- 100 polygons (6-vertex)
- 9,686 benefitial mutations
- 1,220,569 candidates
- 96.21% fitness
- Thanks to Steven.
- 100 polygons (5-vertex)
- 10,490 benefitial mutations
- 2,161,018 candidates
- 95.03% fitness
- Thanks to Asa, Will, Nic & Yuku.
- Images from different runs.
- 50 polygons (6-vertex)
- 6,280 benefitial mutations
- 683,806 candidates
- Thanks to alexs for the final image.
- Images from different runs.
- 100 polygons (5-vertex)
- 6,974 benefitial mutations
- 2,056,467 candidates
- 95.68% fitness
- Thanks to Yuku.
- 100 polygons (6-vertex)
- 6,557 benefitial mutations
- 44,212,346 candidates
- 99.43% fitness
- Thanks to Alex.
- 50 polygons (6-vertex)
- 4,296 benefitial mutations
- 2,404,942 candidates
- 97.6% fitness
- Thanks to Kyle.
- 50 polygons (6-vertex)
- 10,605 benefitial mutations
- 11,104,153 candidates
- 93.84% fitness
- Thanks to KRHAiNOS.
- 50 polygons (6-vertex)
- 11,147 benefitial mutations
- 1,021,165 candidates
- 95.04% fitness
- Thanks to Simon.
See also Firefox logo evolution video. Thanks to Brooss.
- Distributed computing effort: original image size 600px X 900px, divided into 24 parts each 150px X 150px
- 24 x 100 polygons (6-vertex)
- 109,438+ benefitial mutations (total)
- 8,243,441+ candidates (total)
- Fitness: min 95.01%, max 99.08%, mean 96.59%, median 96.65%
- Thanks to Agro momusuindo.net (Indonesia).
- Full resolution final image
- 6,278 benefitial mutations
- 267,623 candidates
- 96.95% fitness
- 4,208 benefitial mutations
- 8,451,873 candidates
- 97.88% fitness
- 6,250 benefitial mutations
- 10,418,975 candidates
- 98.38% fitness
- 6,281 benefitial mutations
- 226,689 candidates
- 96.75% fitness
- Thanks to Marinka for South Park characters.
What is DNA import/export?
Warning: Another experimental (that is not tested at all) feature. Most of the bugs should be fixed now.
Click Export DNA to copy polygon representation of the current best image to the clipboard. You can use it to save your optimization state,
for example to send it to somebody by mail or post it on the web.
If you have such saved DNA string, you can later on paste it into the clipboard and click on Import DNA. This should reproduce the optimization state
from the time it was saved via export.
Please note that DNA is independent of the original image. It means that if you used a custom image, you should also set this image (via image form) to reproduce
a complete state. (Or you could play with switching images/DNA midway)
Click Export DNA as SVG to get vector image from your current best DNA.
Thanks to Martin for SVG export.
Requirements
Unfortunately, due to required
<canvas>
getImageData method support, this particular implementation works only on few browsers.
Tested and works on (example mutation speed for Mona Lisa at the start of optimization on my notebook):
- Chrome 3.0.196.2 (~93 mutations per second)
- Safari 4.0.2 (~75 mutations per second)
- Firefox 3.5.2 (~36 mutations per second)
- Firefox 3.0.13 (~13 mutations per second)
- Opera 9.64 (~8 mutations per second)
Tested and doesn't work on:
- Safari 3.1.2
- Chrome 0.4.154.29 / 1.0.154.36
- Explorer 7 / 8
It may work on development versions of Safari and be faster on development versions of Firefox and Opera.
Feel free to improve on my implementation. The code is rather ugly, though some ugliness is there for performance reasons.