CS 194-26 Project 3: Face Morphing and Modelling a Photo Collection

1. Defining Correspondences

Before we can begin to morph our images together we need to define our corresponding point by hand. I was able to do this via picking 40 points on both the images by using python's ginput function. It is important to note that in order for the morph to work correctly we needed to have a consistent labeling of the two faces. After picking the key points that I was going to be working with, I took the average of the two sets of points and applied a Delaunay triangulation mesh on the images. The reason for using Delaunay triangulation is because it minimizes the construction of overly skinny triangles.

Original Images

image

image

Images with triangulation on the average of the keypoints

image image

2. Computing the "Mid-Way Face"

Before creating the full morph, I wanted to compute and create the "Mid-Way Face". I began with computing the average shape, which was just the average of each keypoint we chose in the two images and had found in the previous section. From there, I was able to use the Delaunay triangulation and warp both faces into that shape. Lastly, average the colors together.

Diving into a bit more detail about the warping, after I was able to apply Delaunay triangulation I could extract the vertices/points of the triangles. Then, I could create the inverse transformation matrix that we need to apply to all the coordinates for an inverse-warp. The inverse-warp was completed with the help of the mask, and lastly as mentioned above I was able to cross-dissolve the colors to create the mid-way face shown below.

Original Image of Me

image

Mid-Way Face

image

Original Image of Giannis

image

3. The Morph Sequence

In order to complete the Morph Sequence, I began with finding the triangle points that we needed for each image and the average shape. From there, I found our inverse transformation matrix for each image. I was able to use these matrices to warp both our images before using (warp1 x warp_frac) + (warp2 x (1-warp_frac)) as discussed in lecture. I created 45 frames and stitch them together using os.walk to get all the frames from the directory they were in and then imageio.mimsave to create the gif of me turning into Gannis as shown below.

image

4. The "Mean Face" of a Population

I decided to work with the dataset with the Danish faces. The first task was to extract the keypoints that we needed, I was able to do this through unzipping the dataset and passing all the files by their names into a directory called "Danish". The approach I decided to take was to create a large dataframe that had all the points, which I then separated into all the x and all the y points. This was key as it allowed me to find the means and append them to the dataframe as well. Once, I had the means I was able to apply Delaunay triangulation on the first danish man's image, which worked fairly well as seen below.

image

Once I had the triangulation, I was able to modify my morph function a bit from before and use a for loop to iterate through 40 of the danish face images and morph each of the faces in the dataset into the average shape.

Examples:

image

image

image

image

image

image

From here, finding the average face of the population was not that difficult. I was able to as before for the gifs, use os.walk to go through the danish images and append them. Once I had this I was able to add a bit of all 40 of them together to produce the average population face we see below.

image

Lastly, the other two task were to warp my face to the average geometry and the average face warped to my geometry. I had to first resize and crop my image to be similar to the average population for this to work effectively. Once completed, I just had to apply the triangulation and call the image warping function I used before. The results are shown below.

My Face Warped to the Average Geometry

image

The Average Face Warped to My Geomoetry

image

Caricature

The last task of the project was to produce a caricature of my face by extrapolating from the population mean that we had just calculated above. I was able to use basic list comprehension to form an image that was 40% me and 60% danish and the results can be seen below.

image

Bells and Whistles