Project P4 for CS4496, instructor Jarek Rossignac

 

Daniel King

Purpose:

The purpose of this project was to create a morph sequence by interpolating the control points between morphs in the sequence.

The control points define the morph applied upon an image in the sequence.

The transparency of the images is also interpolated to fade from one image to the next in the sequence.

Applet: Click Here

Instructions:

General Interface Layout:

Selected options are shown by yellow buttons, while un-selected options are shown by blue buttons.

Morph points turn green when selected. Un-selected morph points are red.

 

Editing Controls Close-up:

 

A morph from a caricature of Captain Kirk to normal Kirk to me to a caricature of me is already stored as Morph Sequence 1.

To define features, click and drag points to desired features in the image, such as an eye or mouth.

To define a shape for easier visualization of control points, click on the points in order to draw lines between.

To finish a shape, click back on Define Features. Then to define another shape, click on New Shape again.

To morph features, drag the features to the desired locations, morphing the image.

 

Steps to Making a Morph Sequence:

  1. Select the first segment and load the desired image.

  1. Define major features in the image.

  1. Save the constraints to 1.

  2. Switch to Morph Features and load the constraints.

  3. Optionally draw shapes to better visualize the features.

  1. Morph the features by moving them as desired.

  1. Set the transparency of this segment so that the second segment is visible.

  2. Select the second segment and load the desired image.

  3. Define major features in the image, or load the constraints from 1.

  1. If shapes were created in the previous segment, they will be shown here, helping to align the features to the new image.

  1. Save the constraints to 2, if changed from 1.

  2. Switch to Morph Features and load the constraints.

  3. Morph the features by moving them as desired.

  1. Repeat for segment 3 and 4 as desired.

  2. Once done, save the morph sequence.

 

Implementation Details:

Morph Segment Grids:

Each morph segment is an instance of a Grid object that can be modified independently.

The Grid object encapsulates a 3D mesh grid made up of triangles along with the methods to modify it. A corner table and opposite corner table are used to traverse the vertices in the grid when performing operations on it.

Because of this structure, this tool could be used with 3D objects, rather than just 2D grids, but there is currently no interface for such functionality.

 

Interpolation:

The interpolation between morph segments was achieved by:

  1. Making a temporary copy of the vertices in the Grid
     
  2. Moving the morph points a given percentage towards the destination morph points
     
  3. Smoothing the curve a specified number of times, and
     
  4. Setting the alpha transparency to the inverse of the percentage in the sequence to the next morph segment.
 
/* Interpolates the control points between
 * this segment and another segment. */
void interpolateTo(Grid finalGrid, float amount, 
   float alpha, int smoothTimes) {

    for (int v = 0; v < numVertices; v++) {
      // If a vertex is pinned in either grid, it is 
      // pinned in the interpolation.
      // Pinned vertices are the points to interpolate.
      if (pinned[v] || finalGrid.pinned[v]) {
        interPinned[v] = true;
        // Interpolate the vertex position.
        interpolated[v] = between(vertices[v], 
          amount, finalGrid.vertices[v]);
      } 
      // If a vertex is not pinned in either grid, 
      // then it is not pinned in
      // the interpolation.
      else {
        interPinned[v] = false;
        interpolated[v] = vertices[v];
      }
    }
    // Swap vertices and pinned lists.
    pt[] temp = vertices;
    boolean[] tempPinned = pinned;
    vertices = interpolated;
    pinned = interPinned;
    
    // Smooth the interpolated grid.
    smooth(smoothTimes);
    
    // Draw the grid with the given alpha transparency.
    drawGrid((int)(alpha * 255));
    
    // Draw the vertices if enabled.
    if (showVertices) {
      drawVertices(blue);
    }
    // Draw the edges if enabled.
    if (showEdges) {
      drawEdges(blue);
    }
    
    // Swap the vertices and pinned lists back.
    vertices = temp;
    pinned = tempPinned;
  }

Smoothing Methods:

Bilaplace:

The constrained bilaplace smoothing is best for large changes, as in these face morphs, since it has a wide area of effect.

It takes the average of the displacements from each vertex to its adjacent vertices.

Then it moves 30% towards this average and moves back by 20% of the average divided by the valence of the vertex.

 

Tuck-Tuck:

The tuck-tuck smoothing is best for large changes, like making a character smile, since it has a small area of effect.

The tuck-tuck smoothing simulates a tuck of 1/2, followed by an un-tuck of 1/2. This is similar to the cubic-fit tuck-tuck method used to smooth 2D polyloops.

It takes the average of the displacements from each vertex to its adjacent vertices.

Then it moves half-way towards this average and calculates the new average of displacements.

The vertices are then moved half-way backwards from this new average.

Tuck-Tuck in action (notice the smile):