To define the correspondences, we followed the template (pictured below) and used Delauney triangulation from scipy.spacial to automatically generate triangles between all the points. Points were marked by hand with a simple tool created using matplotlib (choose_points in my main.py). An example is also shown below
To compute the midway face, there are a couple of steps. First, we take in correspondences and Delauney triangulations of the start face and end face, as well as an alpha (which weighs the final output image by alpha * start and (1 - alpha) * end). Then, we compute a weighted average of the correspondence points, for which we also generate a Delauney triangulation. Finally, we blend the images.
In the blend step, we iterate over every triangle in the computed average triangulation. For each of those triangles, we compute an affine transformation from the associated triangle on the start image and from the associated triangle on the end image. Then, we create a binary mask of the image, whose values are 1 in pixels the midway triangle covers, and 0 elsewhere. We then apply the mask, by inverting the affine transformation and applying it to the mask, which gives us the pixels from the start image to copy over to their new position on the blended image. We do this for every triangle, eventually filling in the whole shape. Finally, we blend the colors in another weighted average.
Below, you can see the Mid-Way face between me and George Clooney
Because most of the heavy lifting was done in the previous part, the algorithm for this is fairly simply. We simply create a range of equally spaced numbers from 0.0 to 1.0 (the number of numbers = the number of frames we want). Then, we simply create a mean face for the starting image and final image for every number, which we use as a weight. Thus, the first few frames will be almost entirely me and the final few frames will be almost entirely Clooney, with a smooth transition connecting them. See below (the slight graininess you may see is due to downsampling to reduce file size).
To compute the mean face of a population, we use the algorithm from "Computing the Mean Face," however each image has a constant weight of 1/(size of image set), which is all normalized and added to a blank starting image, creating the mean. See below for a mean face computed from FEI Frontal and Manually Aligned images (it's not the Danes set, despite what the filename implies). Unfortunately, there were a few minor bugs in the triangulation or point selection that I was not able to fix in the time I had (I'm writing this less than an hour away from passing 3 days late haha), although I am fairly sure they are simply the result of poor precision on my end when selecting points. My face is slightly distorted vertically due to having to adjust the aspect ratio to match image dimensions.
Below are some faces from the mean set warped into the mean.
And here is my face warped into the mean and vice versa.
To create a caricature, I blended my own face with the mean shown above, except with an alpha of 1.5, which overdistorts my features in the direction of the mean face's. I look... not the greatest, worsened by an unflattering aspect ratio.
I choose to change my ethnicity to white, and found a composite "young white male" image online. Below is the morph and midway face.