Project 3 - Face Morphing

Filip Malm-Bägén


Hero

Introduction

This project goes though into the techniques of seamlessly transitioning between two images by manipulating the mesh of corresponding points and blending the colors. By performing these operations, it is possible to compute the average face of a group and create caricatures derived from this average face.

Defining Correspondences

Approach

The corresponding points between two images were defined thoguh this tool. I visualized these points on both faces using OpenCV. Then, I calculated the average positions to create a midway shape and applied Delaunay triangulation to these points. This triangulation will guide the smooth transition during the morphing process.

Result

Face A and Face B with correspondance points
Face A and Face B with correspondance points
Face A and Face B with triangualtion
Face A and Face B with triangualtion
Midway shape of face morphing
Midway shape of face morphing

Computing the "Mid-way Face"

To compute the "mid-way face", I follow three steps: (1) computing the average shape, (2) warping both faces to that shape, and (3) averaging the warped images' colors.

Approach

Step 1: Computing the Average Shape

The average shape is calculated by taking the element-wise mean of the keypoints from both images: avg_points = (points_a + points_b) / 2. I thereafter applied Delaunay triangulation using the average points to create triangles for warping.

Step 2: Warping the Faces

For each triangle, we compute an affine transformation matrix between corresponding triangles in both faces and the average shape: A = compute_affine(tri_a, tri_avg). Using inverse warping, we map the pixels from the source image triangles to the average shape. This is applied to both images, creating warped versions warped_a and warped_b.

Step 3: Averaging Colors

Finally, the mid-way face was computed by averaging the warped images: midway_face = (warped_a + warped_b) / 2. This produces a blended face that combines both images' geometry and color.

As seen in the result, there is a slight error in the mid-way face, especially around the hair and shoulders. I think this might be due to the points I selected not being perfectly positioned. If one zooms in, there are artifacts around the face, and a horizontal line across the nose.

Result

Midway face of face morphing
Midway face of face morphing

The Morph Sequence

Approach

The morphing process involves two main components: shape warping and cross-dissolving. For each frame in the sequence, both images are warped to an intermediate shape defined by a warp_frac parameter, which linearly increases from 0 to 1 over the course of the video. The warping is achieved by applying affine transformations to corresponding triangles from the Delaunay triangulation of the average shape. After warping, the color values of the warped images are cross-dissolved using a weighted average based on dissolve_frac, which also linearly increases from 0 to 1. The final frame is produced by blending the morphed face with the background.

Result

Morph Sequence Animation
Morph Sequence Animation

The "Mean face" of a population

Approach

For this task i used the IMM Face Database. The code works by loading the facial images and their landmark points into images and landmarks, normalizing the landmarks to the image dimensions. It computes the average shape average_shape, then uses Delaunay triangulation and affine transformations to morph each image towards this average. Finally, it combines the morphed images to create and display an average male face with a neutral expression.

Result

Mean face of a population
Mean face of a population

Here are a few examples of faces in the dataset warped to fit the average face. The result looks somewhat good, but there are still some artifacts around the eyes and mouth.

Faces warped to fit the average face
Faces warped to fit the average face

Part 5. Caricatures: Extrapolating from the mean

Approach

To create the caricature, I started by collecting and averaging the landmarks of female happy faces using load_images_and_landmarks and compute_average_shape. After normalizing these landmarks, I created a caricature of my face by exaggerating the difference between my landmarks and the average using the formula caricature = scale * me + (1 - scale) * avg. Finally, I warped my face to fit these caricatured landmarks with morph_to_average_shape and displayed the result.

Result

Caricature of my face
Caricature of my face

Bells and Whistles

I created a morph-video-chain of my friends in Sweden. To to this, I used the tool to define the corresponding points between each image in a sequence, so i first tagged face_a with face_b, then face_b with face_c, and so on. I then used the same approach as in the previous sections to create the morphing sequence. The result is a fun video of my friends morphing into each other. The result is fun, but it is not great. I used images a had laying around, which resulted in some bad morphs. The morphing is not very smooth, and the faces are not perfectly aligned. It would have been much better if I used better images, or aligned the faces better.

It is also clear on which images I've been sloppy with the correspondance points. On these morphings, the faces are not perfectly aligned, and the morphing is not smooth. I should have placed a lot more points, especially around the contour of the face. On some transitions, it just looks like the faces are sliding around.

Hero

This webpage design was partly made using generative AI models.