CS 194-26 Project 4

Preetham Gujjula (cs194-26-adt)

Overview

In this project, we use affine transformations to smoothly transform one face to another, as well as compute the “average” face of a population. We also transform individual faces to conform and diverge from the average face.

Computing the Midway Face

Instead of using my own face, I decided to use Steph Curry’s face as “me”. (An instructor confirmed this was acceptable on Piazza: link). The other face I used was George Clooney’s. It was useful that both subjects were photographed in by the same photographer, in the same style.        

Steph Curry

George Clooney

I used 44 correspondence points to define the triangulations on my subjects faces. The Delaunay triangulations showed good cover of their entire face:

Steph Curry

George Clooney

To compute a midway image of these two faces, I first computed the average of the two sets of correspondence points, and computed a triangulation on that average set. Then I applied that

triangulation to each subject, and warped each triangle of a subject’s triangulation to the corresponding triangle in the triangulation of the average set. Then I averaged the two warped images to obtain the final midway face. Here is the resulting image.

The Morph Sequence

To compute the morph sequence, I applied the same process as in the previous part, but with 41 different weighted averages of the images, ranging from entirely the first image, to entirely the second image. These midway faces correspond to the 41 frames of the gif. I used a simple gif tool (imageio.mimwrite) to combine the images into a single gif.

The "Mean face" of a population

I used the Danish data set for this section. To compute the mean face, I read in the correspondence points for each image, and computed the set of average correspondence points. I defined a triangulation on this average set, and applied the triangulation to each image. Then I warped each image to the average set using these triangulations, and averaged all the warped images to get the final mean image:

Warped example 1

Warped example 2

Warped example 3

I looked up how the correspondence points were defined on the Danish faces, and created a respective set of points for Steph Curry. Then I warped Steph Curry and the Danish average to fit each other:

Steph Curry’s forehead looks bad in this example since the correspondence points defined in the Danish data set don’t covert the forehead area at all, and instead focus on facial features. Ignoring Steph’s forehead, he does look a bit Danish!

Caricatures: Extrapolating from the mean

To create a caricature of Steph Curry relative to the Danish set, I computed the caricature vector as the difference between his correspondence points and the correspondence points of the average face. Then I scaled this vector by a factor of 0.7 (empirically determined) and added it back into his correspondence point vector. I treated this new set of correspondence points as the set of points of Steph’s caricature, and used the standard warping techniques to morph Steph into his caricature:

Bells and Whistles: Change of Gender

To change Steph’s gender to female, I filtered the Danish data set for only female faces, and computed the mean of those faces, using the same techniques as the previous part:

Then I cross-dissolved Steph and the female average, warped him to the average, and also cross-dissolved his warped face with the average. The results of these three morphs are summarized below.

Cross-dissolve

Warp

Cross-dissolve + warp

The cross-dissolved + warped image is fairly convincing! (except for the forehead and the beard)

Bells and Whistles: Morphing Music Video

I used the morphing technique to create a chain of gifs that morphed successive images in the Danish set. Then I used some command-line tools (gifsicle and ffmeg) to convert these gifs into a mp4 file, and to add music.

I chose “Immigrant Song” by Led Zeppelin because it contains Scandinavian imagery, which I thought was appropriate for this image set of Danish people.

Note: to create these gifs, I used the Python multiprocessing library to parallelize the frame computation, and also created a Digital Ocean instance with 32 cpus to do the heavy lifting. Even then, the whole process took over an hour!

The video is here: