Face Morphing

Shivansh Baveja

Project Description

Throughout this project we will we use Delaunay triangulations and affine warping to smoothly and quickly morph facial structures into each other.

Part 1. Defining Correspondences

To perform the required warping, we first need to define correspondences between any two images we would like to warp. For a smooth warp on a reasonably sized image, 30-45 corresponding points are necessary. We define a "reasonably sized image" as being on the order of hundreds of pixels in either dimension. Before defining correspondences, I ensured that the images were the exact same pixel dimensions, along with having their subjects reasonably well aligned. The following tool from a previous student was used to generate json files containing correspondence data. I used images of my family for this project, and as such their correspondences and Delaunay triangulations are depicted below. Each of the images below is 580px x 580px x 3 channels.

Shiv1
Me
Shiv2
Me, Circa 2017
Shiv3
Sister
Peeps
Father
Meems
Mother
Shiv Shiv 1
Shiv Meems 1
Shiv Peeps 1
Shiv Did 1
Shiv Shiv 2
Shiv Meems 2
Shiv Peeps 2
Shiv Did 2

Part 2. Computing the "Mid-way Face"

Here we begin our warping endeavours by finding the "midpoint" of two images. Note that we define the midpoint of images through the following procedure.

  1. Finding the "average" shape by averaging across correspondences.
  2. Morphing both the first and second images into these averaged keypoints.
  3. Cross-dissolving (interpolating) color between the two images.

Below are the midpoints of each of my family members (and a younger version of myself) with myself.

Shiv 5
Morph Source Image 1
Middle Warp
Midpoint of Morph Images (above and below)
Family
Morph Source Image 2

Part 3. The Morph Sequence

We write a morphing function that takes in two images, their respective correspondences, and a specific delauney triangulation and produces a gif of their simultaneous morph. Notice that my implementation of computeAffine(tri1_pts,tri2_pts) is fully vectorized and computes the affine transformations for all triangles simultaneously, allowing for a runtime of ~1 sec/frame.

Both the cross-dissolve and warping parameters were varied linearly on [0, 1] and the generated gif is 60 frames at 30 fps. Note that these affine transformations were calculated using homogenous coordinates across various triangular masks. These masks were generated using skimage.draw.polygon.

Below is the morphing animation from me to my mom. Note that I used a median smoothing filter to get rid of any artifacts resulting from the polygon borders and cropping 20px off each edge for smoothness of transitions, as our clothing pieces were different.

Animation GIF
Morphing Animation

Part 4. The "Mean face" of a population

I used the Danes dataset for this portion of the project. To find the "mean" of the population, we follow the steps below.

  1. Compute the average shape of the population by averaging across correspondences.
  2. Morphing each individual to this average shape.
  3. Take a pixelwise average of this morphed population.

The results of this averaging and morphing are shown below. Notice that the average person is highly biased to the male average since there are 30 males in the sample and only 7 females. Further note that the code used to generate these images cannot be run without first downloading the above linked dataset and placing it in the /data folder.

Average Person
Average Person
Average Woman
Average Woman
Average Man
Average Man

Below are some examples of individuals warped into the geometry of the "average person".

Image 1
Original (Left), Warped (Right)
Image 2
Original (Left), Warped (Right)
Image 3
Original (Left), Warped (Right)
Image 4
Original (Left), Warped (Right)
Image 5
Original (Left), Warped (Right)

After finding this average, I also morphed my face into this average geometry and then morphed the average person into my geometry.

Average Me
me, warped into the average person's geometry
Me Average
the average person, warped into my geoemetry

Part 5. Caricatures: Extrapolating from the mean

Below are two caricatures, both of which were created by using the previously created middle_warp(points, images, alpha_warp, alpha_dissolve) function with alpha_dissolve=0 and alpha_warp either greater than 1 or less than 0.

Image 1
alpha_warp=-1
Image 2
alpha_warp=1.2

Part 6: Bells & Whistles

Below I have created a continuous morphing animation of my entire family. It loops smoothly, and follows the following order: me -> mother -> sister -> dad -> me and continues to loop.

Animation GIF
Entire Family Continuous Morphing Animation