Face Morphing

CS194-26: Intro to Computer Vision and Computational Photography

Author: Michael Sparre

Project Overview

Getting Facial Keypoints and Triangulating Face

I utilized matplotlib.pyplot's ginput function to define points on images and get the triangulation. This part was horrible... I kept trying to make around 40-50+ points while clicking the photos side by side but every time I finished, they would be off by 1... Eventually I figured out you could use the keyboard to click instead of the mouse (which I believe double clicks every now and then). Anyways, here are my photos with landmarks and their resulting Delaunay triangulations.

Jack keypoints

61 keypoints

Jack triangulation

Delaunay triangulation on Jack

Derek triangulation

Delaunay triangulation on Derek

Derek keypoints

61 keypoints

Midway Face

The midway face was calculated by finding an affine transformation matrix that mapped from the Delaunay triangles back to the source image, then we use inverse warping along with our affine matrix to find the source pixels colors that would be interpolated into the final morphed image. Lots of math happened behind the scenes here but simply, we used triangles to solve for our affine matrix and eventually map all the coordinates from our final image back to the source images to sample the right colors. Here is the result:

Original Jack

Base image

Midway Face

Warp_frac = .5

Original Derek

Base image

Morph Sequence

I built a gif detailing the morph sequence of the two faces over 45 frames. Warp_frac and dissolved_frac start at 0 and build up to 1 in increments of 1/45. Here is the gif:

Morph Sequence

Derek -> Jerek/Dack -> Jack

"Mean Face" of a Population

I used the Danes dataset for this part of the project. To get consistent keypoints on their photos and mine in this part, I made use of the dlib module to get 72 facial keypoints on all the photos in a short amount of time. Then, I calculated the average shape of their faces by taking the mean of their facial keypoint vectors. I then warped all of their faces to this average shape (since no one has an average face, some of these look unnatural). After that, I just took an average of all their warped faces to find what the average face looks like for their group. Then, I applied the average shape warp to a photo of mine to see what it would look like as well as morphing the average face into a photo of mine's facial geometry. Here are the results:

Warped Danes photo

23-1m.bmp

Warped Danes photo

31-1m.bmp

Warped Danes photo

33-1m.bmp

Warped Danes photo

38-1m.bmp

Warped Danes photo

39-1m.bmp

Warped Danes photo

40-1m.bmp

Average Danes Face Manipulation

Mean Face

Mean Face Warped to Jack Geometry

Jack Warped to Mean Face Geometry

Caricature

In this part, I subtracted Jack's facial keypoint vector from the average keypoint vector to get their difference, then multiplied this diff vector by 2 and added it back to the mean vector and warped Jack's face to this geometry. This is basically exaggerating the characteristics/keypoints of the photo that are disparate from the average face. Operation: mean vector + 2 * (jack vector - mean vector) = 2 * jack vector - mean vector ;;; (i.e. jack's vector is much greater than average face's)

Jack Caricature

Bells and Whistles

In this part, I chose to morph Jack's face with an average baby face I found online (credit: here). I used the dlib library to make the same ordering/number of facial keypoints of both photos. Then I used these vectors to morph Jack's face to the average baby: shape, color, and finally appearance. Here are the results:

Average Baby Face

Baby Jack

Jack

Baby Shape Jack

Baby Jack Gif

Baby Color Jack