This project was coded mostly in MatLab, the exception was one function, 'mytsearch,' that was
written in C and compiled to work from the MatLab environment.
Labeling
The first step in a successful warp is identifying the common points between the two images.
This process is where a lot of the fine tuning can occur, as to where and how many labels you use.
The labels must match for each of the images. For example if label 10 in image A correlates to the
right eye of the image, then it is essential for label 10 in image B to be the right eye. I decided
to use more than the recommended 43 labels for each face, I ended up using 50 labels for a little more detail.
For selecting the labels, I wrote a function that walked the user, point by point, through
the process. In addition to the face labels, I added labels around the outside of the image
to help with the morph, this makes the computation a little longer for each step, but it
results in an overall smoother morph.
Triangulation
The next step in the morphing process is to define triangles between all of the labels.
For each set of images a median label is computed, and thrown in to MatLab's 'delaunay'
function which computes the DeLaunay triangles for the labels. These triangles give the
frame work for the morph.
The Morph
The actual morph function gets a little complicated, I will try to explain it the most
logically without the use of pictures. The first process is to compute afine transformations
for each of the triangles. The triangles in image A will correlate to the same triangles
in image B, the morph involves warping the two images in to a common 'geometry,' so that
their modified triangles end up overlapping each other. These transformations can be
defined by the following system:
a * x + b * y + c = x'
d * x + e * y + f = y'
or
[x] [ a b c ] [x']
[y] * [ d e f ] = [y']
[1] [ 0 0 1 ] [1 ]
In common English, given the input coordinates (x,y) the output is translated to the
new points (x' , y') buy the afine transformation matrix. This transform ends up being
a shift and a translation.
Once a transform is computed for every triangle, at every point in your output image
a correlating pixel in the source image is found using the afine transformation.
Two different warped images end up being computed, one forcing image A to the common
geometry, and one forcing image B to the common geometry. The intensity of each pixel
from each of the warped images are averaged together according to a dissolve rate, and
the output morph is computed. Now this is repeated over and over again, with different
weights on the dissolve and on how to compute the common geometry. On the time line,
images that are closer to image A will be closer to image A's geometry then image B.
This process is repeated over and over again to give the smooth warp from one image to another.
Average Face
The concept behind this is to find the 'average' face in a set of pictures. This ends up
being fairly simple once you have the above morph figured out.
Taking all of the labels, you can compute a 'mean geometry,' a set of triangles that
is evenly influenced by all of the faces. Once this average geometry is found, each
of the images are warped to fit this geometry, and then all of the warps are blended
together to give the output image. This works better than just taking a blending of
all of the images due to the fact that all of the images are not the same format,
this way all of the information is normalized, and then blended.
The Bearding Function
This ends up being a rather elegant process. The target stays the same from the stand
point of a morph, but the 'beard' is morphed to fit the geometry of the target.
First a user must define what the beard is, which produces a mask to be used by the
morphing function. Then just that part is warped to the target geometry. This warped
beard is just blended (I used a Poisson blend from project 2) back on the the target
image. You really could do this for most features, you could add glasses, you could
change eye color, you could transfer earrings. The options are vast!
I ran in to a little bit of a problem using my own image for the beard source.
I was sort of 'frowning' which made rather interesting results when pushed on to
a smiling face. To overcome this, I also selected the lips in the beard, so that
only the 'hair' is used. You can see the results are fairly impressive.
Computation Time
One singe morph, using two 1166x1400 images : 1 mins 40 seconds
Average Face: 13 minutes
Reflection
This was a very amusing program to work on. The first output, which was a
50/50 morph from my face to Skanda's, was ridiculous. The half Indian,
half Caucasian with a beard and odd looking glasses would make anyone laugh.
Wrapping my head around the 'inverse' transformation took a little bit,
but looking back, it makes perfect sense now. As you could see, I really
enjoyed playing around with the morph function, I can foresee using it in
the future just simply for fun.
Good Morphs:
-Super cool outputs
-Fun applications
Bad Morphs:
-wrestling with compilers and MatLab (ate up about 6 hours) UGG!
-Labeling.... and more labeling.... and more labeling.
|