CS 180

Face Morphing

By Evan Chang · CS 180 Project 3

Tech: Python, NumPy, SciPy, Matplotlib, Delaunay triangulation, PCA

Introduction

In this project, I explored face morphing and the concept of an “average face” over a population. I used an image of myself and morphed it into different images of other people and into average face geometry.

Part 1: Defining Correspondences

To morph one face into another, the images need to be aligned in terms of key facial features.

I manually selected corresponding points on both images and then used those points to define a triangulation. With corresponding triangles, I could compute transforms to warp each face to a shared geometry.

I implemented point selection with ginput from matplotlib, and used Delaunay triangulation to avoid overly skinny triangles. I ran triangulation on the average of the landmark points so the same triangulation could be used for both images.

Faces with keypoints plotted
Faces with keypoints plotted
Delaunay triangulation of faces
Delaunay triangulation of faces

Part 2: Computing the Mid-Way Face

After defining correspondences and triangulation, I computed the mid-way face between two people.

This is done by warping both faces into the average keypoint configuration and then averaging the two warped images across color channels. The warping uses affine transforms between corresponding triangles with inverse warping.

Here is the mid-way result between my face and George Clooney’s face:

Evan warped to midpoint geometry
Me warped
George Clooney warped to midpoint geometry
George warped
Mid-way face result
Mid-way face

Part 3: The Morph Sequence

Using a similar pipeline as Part 2, I produced a smooth morph sequence between two faces.

At each frame, I used linearly interpolated keypoints between the two faces and inverse warped each source image into that intermediate geometry, then blended colors according to the interpolation factor.

Morph sequence between Evan and George Clooney
Morph sequence

Part 4: The Mean Face of a Population

I computed the mean face of a population by averaging keypoints over all faces, warping each face into that mean geometry, and then averaging the warped images.

The dataset used was the FEI Face Database, using spatially normalized frontal images.

Examples from the dataset and their warped versions:

Example FEI images
Warped FEI images

Mean face result:

Mean face of FEI population
Mean face

I also warped my face to average geometry and warped the average face toward my geometry:

Average FEI face warped
Average face warped
Evan face warped
My face warped

Part 5: Caricatures

I extrapolated from population averages to create caricatures.

Using the mean from Part 4:

\[\text{extrapolated} = \text{average} + \alpha \cdot \text{img}\]

where operations are performed per pixel and \(\alpha\) controls extrapolation strength.

Caricatures of Evan for different alpha values
Caricatures of my face

Bells and Whistles: PCA Basis

I constructed a PCA basis for keypoints across the dataset to capture the major modes of variation.

After zero-centering keypoints for PCA, I added back the mean for visualization on the average face. Many keypoints appear similar because the dataset is already fairly well aligned.

I also visualized eigenvalues to inspect how variance is distributed across principal components.

PCA basis visualization on FEI average face
Visualization of PCA basis on FEI average face
Stem plot of PCA eigenvalues
Visualization of eigenvalues

Using PCA basis vectors, I generated caricature-style transformations:

PCA-based caricatures
PCA caricatures

Compared with the original caricatures, PCA-based caricatures appear less extreme in this setup:

Comparison of original and PCA caricatures
Comparison between caricatures (top: original, bottom: using first PCA vector)