## Posts Tagged ‘Morph’

### Image Morph Windows App

November 30, 2006

I resurrected source code from a Windows App that I wrote back in 1993.

The app uses a source image, an 8X8 source mesh, a destination image and an 8X8 destination mesh to generate a series of morphing images. I will try to post a revised version of the program soon.

It is written mostly in C. The image morph algorithm, called "meshwarp", was taken from a 1993 Dr. Dobbs Journal article. The meshwarp code was written by George Wolberg and you can read more about it here.

The attached image shows the mesh editor functionality that I wrote before MFC was the defacto standard.

Here’s a snippet of George Wolberg’s meshwarp code.

/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* meshWarp:
*
* Warp I1 with correspondence points given in meshes M1 and M2.
* Result goes in I2.
*
* See "Digital Image Warping" by George Wolberg (IEEE Computer Society
* Press, 1990) for details.
* Based on Douglas Smythe’s algorithm (in "A Two-Pass Mesh Warping Algorithm
* for Object Transformation and Image Interpolation", ILM Technical Memo
* #1030, 1990).
*/
void meshWarp( imageP I1, imageP M1, imageP M2, imageP I2 )
{
int I_w, I_h, M_w, M_h;
int x, y, u, v, n;
float *x1, *y1, *x2, *y2;
float *xrow, *yrow, *xcol, *ycol, *coll, *indx, *map;
uchar *src, *dst;
imageP Mx, My, I3;

I_w = I1->width;
I_h = I1->height;

M_w = M1->width;
M_h = M1->height;

/* allocate enough memory for a scanline along the longest dimension */
n = MAX(I_w, I_h);
indx = (float *) WINmalloc(n * sizeof(float));
xrow = (float *) WINmalloc(n * sizeof(float));
yrow = (float *) WINmalloc(n * sizeof(float));
map = (float *) WINmalloc((n*2) * sizeof(float));

/* create table of x-intercepts for source mesh’s vertical splines */
Mx = allocImage(M_w, I_h, MESH);
for(y=0; y < I_h; y++) indx[y] = y;
for(u=0; u < M_w; u++) { /* visit each vertical spline */
/* store column as row for spline fct */
xcol = (float *) M1->ch + u;
ycol = (float *) M1->ch + u;
coll = (float *) Mx->ch + u;

/* scan convert vertical splines */
for(v=0; v < M_h; v++, xcol+=M_w) xrow[v] = *xcol;
for(v=0; v < M_h; v++, ycol+=M_w) yrow[v] = *ycol;
catmullRom(yrow, xrow, M_h, indx, map, I_h);

/* store resampled row back into column */
for(y=0; y < I_h; y++, coll+=M_w) *coll = map[y];
}

/* create table of x-intercepts for dst mesh’s vertical splines */
for(u=0; u < M_w; u++) { /* visit each vertical spline */
/* store column as row for spline fct */
xcol = (float *) M2->ch + u;
ycol = (float *) M2->ch + u;
coll = (float *) Mx->ch + u;

/* scan convert vertical splines */
for(v=0; v < M_h; v++, xcol+=M_w) xrow[v] = *xcol;
for(v=0; v < M_h; v++, ycol+=M_w) yrow[v] = *ycol;
catmullRom(yrow, xrow, M_h, indx, map, I_h);

/* store resampled row back into column */
for(y=0; y < I_h; y++, coll+=M_w) *coll = map[y];
}

/* first pass: warp x using tables in Mx */
SendGenStatus( "1st Pass: Interpolating and Resampling…" );

I3 = allocImage(I_w+1, I_h+1, BW); // +1 for testing purposes
x1 = (float *) Mx->ch;
x2 = (float *) Mx->ch;
src = (uchar *) I1->ch;
dst = (uchar *) I3->ch;
for(x=0; x < I_w; x++) indx[x] = x;
for(y=0; y < I_h; y++) {
/* fit spline to x-intercepts; resample over all cols */

catmullRom(x1, x2, M_w, indx, map, I_w);

/* resample source row based on map */
resample(src, I_w, 1, map, dst);

/* advance pointers to next row */
src += I_w;
dst += I_w;
x1 += M_w;
x2 += M_w;
}
freeImage(Mx);

/* create table of y-intercepts for intermediate mesh’s hor splines */
SendGenStatus("Interpolating horizontal splines of intermediate mesh…");
My = allocImage(I_w, M_h, MESH);
x1 = (float *) M2->ch;
y1 = (float *) M1->ch;
y2 = (float *) My->ch;
for(x=0; x < I_w; x++) indx[x] = x;
for(v=0; v < M_h; v++) { /* visit each horizontal spline */
/* scan convert horizontal splines */
catmullRom(x1, y1, M_w, indx, y2, I_w);

/* advance pointers to next row */
x1 += M_w;
y1 += M_w;
y2 += I_w;
}

/* create table of y-intercepts for dst mesh’s horizontal splines */
SendGenStatus("Interpolating horizontal splines of destination mesh…");
x1 = (float *) M2->ch;
y1 = (float *) M2->ch;
y2 = (float *) My->ch;
for(v=0; v < M_h; v++) { /* visit each horizontal spline */
/* scan convert horizontal splines */
catmullRom(x1, y1, M_w, indx, y2, I_w);

/* advance pointers to next row */
x1 += M_w;
y1 += M_w;
y2 += I_w;
}

/* second pass: warp y */
SendGenStatus( "2nd Pass: Interpolating and Resampling…" );

src = (uchar *) I3->ch;
dst = (uchar *) I2->ch;
for(y=0; y < I_h; y++) indx[y] = y;
for(x=0; x < I_w; x++) {
/* store column as row for spline fct */
xcol = (float *) My->ch + x;
ycol = (float *) My->ch + x;
for(v=0; v < M_h; v++, xcol+=I_w) xrow[v] = *xcol;
for(v=0; v < M_h; v++, ycol+=I_w) yrow[v] = *ycol;

/* fit spline to y-intercepts; resample over all rows */
catmullRom(xrow, yrow, M_h, indx, map, I_h);

/* resample source column based on map */
resample(src, I_h, I_w, map, dst);

/* advance pointers to next column */
src++;
dst++;
}

freeImage(My);
freeImage(I3);

WINfree((char *) indx);
WINfree((char *) xrow);
WINfree((char *) yrow);
WINfree((char *) map);
} 