For some reason, photoshopping people’s faces onto other people’s heads is funny.

I don’t know why, it just is.

I was thinking about this, and it occurred to me that it should be possible to do it completely automatically, with face detection. So, instead of searching the literature to find the inevitable excellent team of researchers who had done it years ago far better than I ever could, I did what I used to do. I jumped in and started writing code.

A basic solution turns out to be pretty easy; I had a working prototype within an hour.

How it Works

The program is only 90 lines long, and its operation is very simple. It identifies the faces in the image, picks one at random, and pastes that face onto all the other face locations, adjusting the colour and blending a little at the edges.

Finding Faces

To automatically detect faces in the image, I used OpenCV, which has handy python bindings and includes a nice face detection system using a Haar Feature-based Cascade Classifier.

I don’t fully understand how a Haar Feature-based Cascade Classifier works, but for the purposes of this application, that’s not really required. The important thing is that it scans over the image in increasingly large windows, looking for things that look like faces. When it’s done, it returns a list of boxes which it thinks have faces in them.

Blending

Once you know where the faces are, swapping them is just a matter of copying the contents of one face box into the location of another. But that of course that looks terrible, because you can easily see the boundary. I did two things to deal with this:

Before pasting, the colour of the image is adjusted so there’s no sharp colour change at the boundary. This is done very simply, by taking the average colour of both faces, and adjusting the brightness levels of the channels in the new face such that it has the same average colour as the place it’s about to be pasted. (Later I wrote a more complex version that used K-Means Clustering to find the skin tone and adjust based on that, but it didn’t work noticeably better than the mean-colour method, so I reverted to the simpler system).

The other thing I did to hide the boundary is use an alpha mask when pasting, so the face isn’t just pasted in a square. The mask I used is very simple, just a circle with smoothly fading edges.

Considering the program’s simplicity, I was surprised at the quality of the results:

Simon and River don’t have their heads pointed straight at the camera, so the system pretty much fails completely for them. I think Mal is my favourite here though; to me he kind of looks like Teal'c from SG-1.

Here’s the result of attempting a more challenging image, a group photo of my research group, The Intelligent Modelling and Analysis Group at UoN CS:

You can click on the picture for the full size version.

So, some are better than others here. One face isn’t recognised, and there are a few false positives on people’s clothing. But all in all, for a quick hack and zero human input, I think it’s not bad.

Code

Here’s the full code listing. It’s written for Python 2.6. To get the dependencies, run something like:

sudo apt-get install python-opencv libcv-dev opencv-doc

You’ll also need to download the alpha mask image and put it in the same directory, renamed as circlemask.png .

I want to give credit and thanks to the various StackOverflow users and blogs whose code snippets and inspiration I used, but I sadly didn’t keep track of them, because I never thought this program would work well enough to share. So, here’s to you, unnamed internet heroes.