In this project we will explore using affine transformations of a triangular mesh to morph faces between a source and a target.

The basic concept behind all the morphs to follow is explained below:

  1. First we want to mark corresponding points on the source and target image. (Eye corner to eye corner, etc.) I made a Python tool using matplotlib to do this.
  2. Then we compute a "midway" point between each corresponding point pair previously marked.
  3. Then we compute a Delaunay triangulation of all the points we computed in order to generate a mesh.
  4. For each triangle in the mesh of the source image, we want to compute the affine transformation that takes it to the corresponding triangle in the target image. We use 3 points from each image and compute the affine matrix A by writing A * S = T, where S and T are the augmented matrices from the 3 (S)ource and (T)arget points. Then compute A = T * Inv(S) and save the matrix to compute all further transformations.
  5. We also need to repeat the previous step to compute the affine transform to the source image, since our final image will be somewhere in the middle.
  6. Then we write functions to interpolate across each of the R, G, and B color channels of both the source and the target images since the transformed coordinates will be non-integer.
  7. Finally we perform a cross-dissolve of the pixel intensities between the source image and the target image, using a fraction of one and the remaining fraction of the other. Overlaying the two partial images gives us the final warp.

Morph Sequence

Here we compute a morph sequence of 40 frames between me and a koala.

ken koalagif koala
Pretty bizarre

Average Dane

In this section I first compute the average face of a smiling Dane. I selected 16 photos from the collection featuring danes who all had open smiles and front facing faces. This would produce the best looking average image. Then, we parse the point information and compute the average coordinates for each corresponding point. Then, we warp all 16 pictures to the average mesh and compute an average across all of them. This is the result.

average_dane
average_dane
Average Dane

Then I compute a morph between my face and the average Dane.

average_dane average_dane average_dane
Average Dane (left is shape warp 100%, cross dissolve 0%; right is the opposite; middle is 50/50)

Caricature

In this part I compute a caricature of my face by first taking the difference between points on my face to the points on the average Dane's face. This difference is then partially added back to my own points (akin to the sharpening method) in order to "enhance" distinguishing features.

caricature caricature
o__o

Ethnicity Transform

Here I explore warping my face to the average Korean male's.

ken_korean ken_korean ken_korean
Korean guy (left is shape warp 100%, cross dissolve 0%; right is the opposite; middle is 50/50)