Morphin' than a barrel of monkeys

22 January 1997

Computer software is a popular albeit expensive mechanism for generating special effects in movies and TV shows. One effect you probably recognize despite its absence from Webster's is morphing. In 1988 morphing was used in "Willow", and in 1989 in "The Abyss." Then, in 1991, it was used extensively in "Terminator 2" as well as taking center stage in Michael Jackson's video "Black and White." Today, morphing is very commonplace, appearing even in commercials.


Try the morph applet to make your own morph.
As an inquisitive1 individual, I set out to find out how morphing works, and to implement my own morphing software. I did find one other morpher written in Java, and while it was fast, it lacked editing capabilities, and was limited to three control points2. You can also search gamelan for new morphing-related entries to see what might have shown up since this article was written. Since I originally wrote this, an excellent morpher has appeared.

There are numerous commercial morphing packages that range in complexity from two dimensional image morphers to professional quality three dimensional model morphers. There are a few freely available morphing packages3 for Unix on the Net, but I decided to see if I could just figure it out for myself and write a quick-and-dirty 2D morphing program.

Morphing is a combination of two image effects. The first is fading one color into another, and the second is warping. The fading seemed simple. I took the red, green, and blue components of a pixel before and after the transformation and interpolated those values for each frame. If a certain part of the picture is red, but would be yellow after the morph, I intended to fade from red to yellow at each step of the morph. It turned out that fading was somewhat more involved than this because the warping changed the locations of the colors. I'll explain how I addressed that issue momentarily.

Warping is considerably more complicated. It requires moving pieces of the images around, compressing some areas and stretching others in order to make the two images match up. There are a number of ways that it could be done, and I considered a few before selecting one that I believed would yield good results along with being manageable to program in a reasonable amount of time.

Resident Internet personality Paul Phillips morphing into resident magic maker, Michael D. Bayne

Originally I thought that I would allow the user to place "control points" on the images. These points would be used to align regions of the two images. For example, if the images to be morphed were two faces, then the user would put a control point on each eye, the nose, the mouth, and other important facial features. My software would then move these points so that the control point on the first person's nose would move a little each frame until the final frame, in which it would be on the second persons nose.

That would account for the warping of the control points, but what about the other pixels? My idea was that that they would follow the control points, to a certain extent. For each pixel, the control points would be weighted according to their distance, and would then move according to these weights. For example, if there were only two control points, one which moved 10 pixels up and another which moved ten to the left, then a pixel very close to the first point might move up 9.7 pixels, and very slightly left. A point directly between them at the outset would move equally in both directions.

This seemed appealing, but upon further consideration I realized that it would not do. Imagine many control points in a vertical row, which all move to the left. Now add a single control point to the right of the vertical row, which will move right. A pixel very near this lone control point should intuitively move to the right, but the sheer number of nearby leftward moving points will induce it to the left. Clearly I needed some kind of locality of effect.

I came up with what I call the "two-quilt" method, in which each pixel is seen as a stretchable "patch" that starts out in a square shape, but is then increasingly deformed as the morph progresses. These patches taken together make up a quilt. The user is presented with an adjustable grid, whose points of intersection make up the control points. The grid is used to align features of the two images. When it's morphing time, the vertices of each patch on the grid are used to control the movement for that patch of the quilt.

The two quilts are separate from the frames of the morph. Before being warped, the quilts look exactly like the first and second image. When calculating the morph, the first quilt gets progressively more warped as the morph proceeds, while the second begins the process maximally warped and heads back toward relative normality. To determine how to draw the intermediate frames, we examine each pixel and identify which patch from each quilt is over that pixel at that moment. Then, each quilt's color is taken into account when calculating the color of the pixel. Additionally, the first image has higher priority early in the morph and the second image has higher priority later.

If your understanding of this process is patchy, don't worry, I know this is a warped explanation, but I think this example will make everything morph or less clear. Focus on the second frame of the morph. At this point the first quilt is just beginning to deform, and the second quilt is beginning its journey very deformed. Let's say the first quilt has a patch of white over one pixel and the second quilt has a large ugly patch of blue. Since we are closer to the beginning of the morph, we use mostly the white patch as our source color and mix in a little blue. We color that pixel a very light blue. The next pixel might be under a red patch on the first quilt, but it is still under the same giant patch of blue on the second quilt. This pixel will turn out a strong red with a hint of purple.

Enough about coloring, let's examine the warping process that actually

[diagram image]
The patchwork quilt becomes warped.
moves the patches around on each quilt. Each control point must move from its position in the before image to its position in the after image. Since we know how many frames we are going to be generating and how far the control point will ultimately move, we can calculate the amount it will change in the x and y directions for each frame. Each control point for a given patch corner is weighted by the inverse of its distance from the corner, and then a change in x and y is calculated for each corner. The rest is easy. As we step through the morph, each corner of each patch is adjusted a little, moving in its prescribed direction. The pixels, or patches, that are defined by four corners are thus moved along, and individually deformed in different ways.

That accounts for one quilt, but what about the other one? After all, I did call this the two quilt method. The second quilt is going the other way. It is made up originally of patches which coincide with the pixels of the *second* image, and go backward, warping their way towards the first image. Each patch in each quilt is associated with a color -- the color of the pixel that coincided with it in its beginning state. I start out with a frame completely colored like the first quilt, and as the two quilts glide over each other, I progressively blend in more color from the second quilt. The last frame is colored completely like the second quilt. Without the second quilt, the morph would look like the first image deforming and slowly moving around as the the second image statically faded in.

Morph Marc Andreessen into Andre the Giant!

Sorry- you can't save your morph in this applet version. You may also want to stop the other morph applet in this article (by clicking on it) before playing with this one.

If you haven't already done so, please play around with the applet! Because of the security restrictions placed on applets, you won't be able to load your own pictures or save your results, but I have provided the source code, which includes an application class that will allow you to do both of those things.

While my morphing software may not be the highest of tech, it is cool, and can certainly be improved upon by an interested individual with some time on their hands. The grid could be replaced by a polygon of arbitrary complexity, and some method of allowing the user to add control points and connect them with lines to existing control points could be implemented. The calculation of how to move each pixel point would essentially remain the same. There are probably some optimizations one could make to the code to make the whole process faster. Also, since I did come up with this algorithm on my own, there might be a vastly superior way of doing this whole thing. Describing it is left as an exercise for the reader.

Irregardless of the fact that irregardless is not a word, this should provide a good introduction and an amusing toy. Morph out. *

-- Ray <ray@go2net.com> is a Dreamer of Dreams at go2net. If you told him he was gullible, he'd probably believe you.

Source code for the morph editor applet and player, including an application version that allows you to save your morphs, are included below.

Adjustor.java, EditorApp.java, EditorApplet.java, EditorPanel.java, Grid.java, Line.java, Morph.java, MorphPlayer.java, and Quilt.java.