package com.mindfock.blog {

Photographic mosaics

Posted: October 23rd, 2009 | Author: John del Rosario | Filed under: Experiments, Programming and Development, Python | Tags: , , | 2 Comments »

I haven’t posted in a long while, mostly because of school. I managed some free time the past few days and wrote a photographic mosaic generator in Python. Why not call it by its more popular name? Because it is trademarked and patented. But I don’t think I’ll get into any trouble by posting this, as this is merely for learning purposes, right?

This is a relatively simple solution. I didn’t use any complex algorithms like edge-detection, dithering or whatever (maybe I could add those later), just plain old RGB matching. I’ll try to explain the process as best and as simply as I can.

Creating the image pool

The first step is to create your image pool.  The image pool is a directory of all the tiles that will be used in your mosaic, and every tile must be of the same size. The more tiles you have, the better results you get.

I used Irfanview to resize, crop, rotate and rename 1,983 photos for my image pool, plus a Python script I wrote to separate the portrait oriented photos from the landscape oriented ones.

Next, I wrote another Python script to create an SQLite database which stores all the data I need to create a photomosaic, instead of calculating each value every time I want to create a mosaic. It holds a reference to an image file, and 9 RGB values.

To calculate the RGB values of a tile, I didn’t just get the average color of the entire tile, instead I divided the tile into a 3×3 grid, then calculated the average RGB value of each cell in the grid (resulting in 9 values). I think this method is called “sub-sampling”. This helps in making more accurate matches. (Pardon the crappy images, I’m making these in Paint.NET)

tile-sub-ave

Subdivided tile –> (Pseudo) Average colors

Generating the mosaic

Now that I have my image pool ready, I can start generating the photographic mosaic itself. I won’t go into the too much detail but basically I subdivide the source image with the size of my tiles. I then iterate over the subdivisions and further subdivide each cell into a 3×3 sub-grid to match against the tiles. I calculate and compare the RGB differences between every tile in my image pool, and get the best result (least difference). I then place the best tile into its proper position in the mosaic.

match

Subdivided cell –> Average colors of cell   =   Average colors of tile –> Best matching tile

I added an extra method that starts matching from the middle of the source image, going outward. This generates a mosaic where the best matches are in the center, and leftover tiles go to the edges, resulting in a better looking mosaic, especially for portraits.

mosaic5 mosaic7

Top-down matching vs. Inside-out matching

In the first one, by the time I got to the center, I ran out of good tiles to use. For the second one, the best tiles are used in the center.

Results

mona-lisa-mosaic eljohn1

eljohn2 mosaic8

Try it out

This is just a bunch of Python scripts, so there is no executable to run.

Just type

>python photomosaic.py path\to\source.jpg path\to\output.jpg path\to\imagepool\dir [-options]

on the command line. Type --help to see possible options.

Of course, preparing the image pool is the most difficult part of creating a mosaic. You can use the create_image_pool.py script to do that for you. Just make sure all your tiles are of the same size, and it will automatically create an SQLite file inside your pool directory which the photomosaic generator can use.

>python create_image_pool.py path\to\imagepool\dir

If you don’t have 2,000 images lying around, you can go to this page. At the bottom of his post he has a link to .zip of photos of chemical elements. It’s already resized for you.

Right now, generating a 1,600 tiles mosaic from ~2,000 tiles takes about ~5 minutes on my slow-ish machine. My next goal would have to be speed and better matching algorithms.

Download photomosaic.zip