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
.
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.
Below are the midpoints of each of my family members (and a younger version of myself) with myself.
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.
I used the Danes dataset for this portion of the project. To find the "mean" of the population, we follow the steps below.
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.
Below are some examples of individuals warped into the geometry of the "average person".
After finding this average, I also morphed my face into this average geometry and then morphed the average person into my geometry.
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.
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.