Loading spinner
Image Mosaic
Apr. 8th, 2021ยท7 min read

Introduction

We've all seen images where when you zoom in you realize that it's made up of many smaller images and harkens to some greater theme. While cool, I found the problem of actually creating this mosaic quite interesting so this weekend project is me doing so. The dream was to replicate starry night made of galaxies but we'll see it didn't quite work out that way!

Code

I'll go through my steps for solving this problem by creating a mosaic of UCSD's beloved CSE bear! For those that don't know, right outside CSE at UCSD, there is a large stone bear art piece!

CSE Bear
CSE Bear

Importing Base Image

The first step is just importing your target image, this is easily done using OpenCV.

Tiling

The next step is to tile the base image into all the spots where new images will replace the original pixels. I opted to specify square tiles of a given number of pixels on each side and then cropped the image to the largest region occupied by the specified tile size.

This looks extremely similar to the original image as the number of pixels removed is quite small in the scale of the image. In the case of this image and the prior sizes we have tiles!

Example Top Left Tile
Example Top Left Tile

Resizing Image

Now that we have a tile size in the original image we can either make our entire dataset of sample images match the tile size or scale up the original image such that the original tile size maps to the dataset image size. I opted to do the latter to maintain resolution and not have to resize many thousands of images.

Dataset Import

I opted to use the cifar dataset as there is a wide range of colors and textures that I believed will replace the original tiles well! For my convenience I aggregated all the images into one large list.

Comparison and Replacing

To replace every tile with an appropriate sample image we need a means of comparing the tile to the dataset. Initially I had the idea of using a mean pixel color metric and finding the most similar example in the dataset but I found that even for a small tile the texture across the tile is important to making a realistic looking image. I opted instead to do a pixel-wise comparison of each tile against the entire dataset, which is simply the L2 norm of the difference between the tile and sample image. To aid in speeding this process up, I used the multiprocessing library in Python.

While this is quite slow it gets the job done! If you have any ideas to make it faster let me know! The result is quite nice for our bear!

Cifar Bear
Cifar Bear

Other Examples

Galaxy Starry Night

As mentioned before, my original idea was to create a rendition of Starry Night using galaxies. Using one of the astroNN datasets I attempted to do this.

Original Starry Night
Original Starry Night

Galaxy Night (not really...)
Galaxy Night (not really...)

The problem is the diversity of images and the textures from images of galaxies is not enough to have decent replacements for the original tiles. Other people have solved this problem with tinting and other image augmentations to make them work but I did not want to do this.

Cifar Starry Night

I opted to try the same image but now with cifar and the results were MUCH better. Even with a coarser tile arrangement it still looks quite nice.

Original Starry Night
Original Starry Night
Cifar Night (Tile Size: 4)
Cifar Night (Tile Size: 4)
Cifar Night (Tile Size: 8)
Cifar Night (Tile Size: 8)
Cifar Night (Tile Size: 12)
Cifar Night (Tile Size: 12)

I really enjoy the art style that you get from different mosaics like this, and plan to try out other dataset and image combinations. If you have a request let me know and I may just run it!