Project 3 - Face Morphing

Eric Tang

Defining Correspondences

For this project I decided to morph between my face and a picture of my mom from when she was around my current age. I cropped and aligned the the images using the align_images code from the previous assignment. I then defined keypoints on both images using ginput, defining 45 points, and trying to outline major facial features. The images below show the original images, the keypoints I defined, and the images overlayed with the Delaunay triangulation of the mean of the two sets of keypoints.

image
Me
image
My mom at 20
image
Keypoints
image
Keypoints
image
Keypoints
image
Keypoints

Computing the "Mid-Way Face"

For calculating the mid-way face, I took the mean of the two sets of keypoints, and used the Delaunay triangulation over the mean of the keypoints in order to define triangles with which pixel values from the images would be sampled. I then calculated the transformation matrix that would translate a triangle in a source image to a triangle in the delaunay triangulation. I then applied the inverse of this transformation matrix to each triangle in the aforementioned Delaunay triangulation, and used RectBivariateSpline in order to interpolate pixel values based on the transformed triangle coordinates. Finally, I assigned the retrieved pixel values to the positions of the triangles from the delaunay triangulation.

image
Me
image
Midway
image
My mom at 20

The Morph Sequence

For creating the morph sequence, I computed 45 frames of images, which gradually cross dissolves from the source image into the destination image. I set the warp_frac to go from zero to one with the np.linspace function, and gradually warped the source image towards the average face, and the destination image from the average face to the original destination image. Overlaying these two images at every timestep using a cross dissolve yielded the morph sequence below.

image
Morph

The "Mean Face" of a Population

For this section, I used the dataset containing 37 faces of Danes. I calculated the mean of each of the keypoints defined for all of the faces, and used the Delaunay triangulation to define targets for warping the original faces into the average shape. Below are 6 Danes and their faces after being warped to the average face of the 37 danes in the dataset.

image
Dane 1
image
Dane 2
image
Dane 3
image
Dane 4
image
Dane 5
image
Dane 6
image image image image image image

I then used similar techniques as before in order to warp my face to the average shape of the Danes, and calculated a Delaunay triangulation over the keypoints defined on my face in order to create targets for warping the mean Dane face into the shape of my face.

Below are images of my face, of the average danish face, my face warped to the shape of the average dane, and the average dane face warped to my face shape.

image
Me
image
Avg Dane
image
Me -> Dane
image
Avg Dane -> Me

Caricature

For the caricature, I scaled the warp_frac to be greater than 1 and less than 0. I ran into some issues here with the triangulations overlapping while doing the extrapolations for the caricature, but the general idea still seems to be there, with features becoming more accentuated.

image
alpha = -0.5
image
alpha = 1
image
alpha = 1.5

Bells and Whistles - Change Ethnicity to Danish

For two different images of myself I tried changing my ethnicity to danish. I got noticeably different results based on the initial size of my face in the image relative to the size of the average Dane. The first image in each row is found by warping my face to the shape of the mean Dane face. The second image in each row is created by warping the average dane's face to be the shape of my face, and averaging pixel values with the image of my face. The third image warps the shape of my face to be the shape of the average dane's face, then averages pixel values to generate the final image.

image
Just the shape
image
Just the appearance
image
Both
image
Just the shape
image
Just the appearance
image
Both