Yet Another PhotoMosaic Generator
Update: Mon 25 Feb 2013 11:38:47 AM CST add classic style. More refer to github
Python是面向对象的?没有对象面向毛对象。
——Anonymous
Several weeks ago, I saw a poster of presidential campaign for Obama, in which Obama’s portrait was made up of many voter’s photos. It really attracted me, somedays later, I want to make one myself.
The completed code host here. It is much more functional than object-oriented…
Search the Internet
First of all, I searched the Google to find out how others achieve it, then I found many interesting implement and post on it.Along with them, there are pretty demos around.One of the demo of Foto-Mosaik-Edda striked me.It declaims as follows in their site:
The Chaos Mosaic Picture is a new form of photo mosaic which can, at present, only be created by Foto-Mosaik-Edda.
Uhm…Foto-Mosaic-Edda is an open-source project that really impressive.But it was an C# project. Linux users don’t like it however.I don’t like mono
.
I searched other open-source implement on photomosaic. I get some simple programs only use gray photos, and some complex ones can make beautiful classic photomosaic(like metapixel, even chaos style which it calls collage style), But none has as beautiful demos as Foto-Mosaic-Edda.(metapixel really amazing, it is robust and quickly.)
However, I saw many enthusiastic people write one themselves, it really looks interesting for me. I’ve used PIL for processing images when I tried to decode captchas several days ago, so I believe with the help of PIL, someone can achieve photomosaic simply.
So I just read the documentation of PIL, then start my hack.
Write My Own PhotoMosaic Generator
It’s not hard, however, what you should do is clear and simple:
- analyse the image to be made mosaic, get a dict in which position as key and color as value.
- use a bunch of images to get a dict, in which image name as key and colors as value.
- thumbnail bunches of images and paste it in the right position, so that the big image looks like it consists of many small one.
I’d like to got the chaos style, so some other requirements:
- frame and shadow for small images
- random paste small images onto large one
Now, let’s go.
Frame, Shadow and Rotate
first add frame, shadow to small images
1 |
def add_frame(image): |
Then a function to rotate images.
1 |
def rotate_image(image, degree): |
‘RGBA’ mode is to support transparency. What’s matter here is that jpeg/jpg does not support transparency. So you can’t get transparency shadows and rotate pictures if you just use jpg/jpeg images.So, write a function to process images with jpg/jpeg format, transpose it into png.
1 |
def process_image(filename, newname): |
Really poor work… But it works for me: )
We have to thumnail bunches of images, It’s easy to thumbnail with PIL:
1 |
def thumbnail(im, size): |
Let’s have a fun with them. To get heaps of images randomly on the desktop, I hardcoded these parameters to get my photos work, you HAVE TO find yours:
1 |
# Just for fun |
Calculate Images And Compare
Get average colors of an image
1 |
def average_image(im): |
to compare images? Compare the (r,g,b) value of them.
1 |
def compare_vectors(v1, v2): |
I just use distance in (R, G, B) space to calculate similarity, someone advice compare in other space, you can change it just like the example in PIL’s documentation:
1 |
# May not useful |
But I find many implements just use R,G,B, and it works well.
Next, get a dict of image in current path, in which filename as key, average (R,G,B) colors as value.
1 |
def tile_dict(path): |
We don’t need to calculate every pixel of the large picture, just thumbnail it to get a nearest color of different regions.
1 |
def thumbnail_background(im, scale): |
For every pixel in the thumbnailed large image, find most similar small image filenames.(top ten):
1 |
def find_similar(lst, dic): |
Poor hack, but it really works…
Final Work
Now it’s the final magic.
Get the small image in order, the order imply where it should be. Then rotate, add shadows and frames for small images, finally paste it onto the large one randomly in the right position:
1 |
def get_image_list(im, dic): |
I try it like this, I know parameter n
is tricky, it was the scale it thumbnail the large image. Maybe I’ll change it to something more clear later…
1 |
def main(filename, n, scale, iteration, path='./'): |
Demo
Do you like it?
Can you see it?
Demo Download(45.8M)
More examples here(Chinese)
Thanks
My family, It supports me.Never let me down, never pour cold water, never scold for insignificance.