Next: General Pixel Transformation, Previous: Scaling, Up: Simple Image Processing [Contents][Index]

#### 37.7.7 Warping

Image warping (or texture mapping in 2D) refers to the transformation of pixel coordinates. Rotation, scaling and shearing etc. are examples of (linear and non-perspective) image warping. In typical applications some of the commonly used pixel coordinate transformations are implemented using more efficient algorithms instead of a general warping. For example, image rotation is often implemented using three shears rather than a general warp (Forms Library implements rotation via image warping).

Non-perspective linear image warping in general is characterized by a 2x2 warp matrix `W` and a translation vector `T` with two elements as follows

           P' = W * P + T

where `P` is a vector describing a position via it’s x and y coordinates and `P'` is the position after warping.

The elements `w[i][j]` of the warp matrix are constants (if the warp matrix isn’t constant or is of higher order, we usually call such a transformation morphing rather than warping). Since our destination for the warped image is an array of pixels rather than a properly defined coordinate system (such as a window) the translation has no meaning. For the following discussion, we assume the translation vector is zero. (In doing the actual warping, the warped image is indeed shifted so it starts at the (0,0) element of the array representing it).

Although, theoretically, any 2D matrix can be used as a warp matrix, there are practical constraints in image warping due to the discreteness of pixel coordinates. First of all, we have to snap all pixel coordinates onto a 2D rectangular integer grid. This in general will leave holes in the warped image because two pixels may get mapped to a single destination location, leaving a hole in the destination image. Secondly, truncation or rounding the resulting floating point values introduces errors. Because of these reasons, image warping is performed in reverse. That is, instead of looping over all pixel coordinates in the original image and transforming those into new coordinates, we start from the new coordinates and use inverse warping to obtain the coordinates of the pixel in the original image. This requires that the inverse of the warp matrix must exist (which is the case if `w[0][0] * w[1][1] != w[0][1] * w[1][0]`, i.e., the warp matrix has a non-vanishing determinante). With inverse warping the transformation becomes a re-sampling of the original image, and subpixel sampling (anti-aliasing) can be easily implemented.

The following function is available in the library to perform warping

    int flimage_warp(FL_IMAGE *im, float matrix[][2],
                     int neww, int newh, int subpixel);

where `matrix` is the warp matrix. `neww` and `newh` specify the warped image size. To have the warp function figure out the minimum enclosing rectangle of the warped image you can pass zeros for the new width and height. Nevertheless, you can specify whatever size you want and the warp function will fill the empty grid location with the fill color. This is how the aspect ratio preserving scaling is implemented.

In general, the warped image will not be rectangular in shape. To make the image rectangular the function fills the empty regions. The fill color is specified by setting the `image->fill_color` field with a packed RGB color.

The last argument, `subpixel` specifies if subpixel sampling should be used. Although subpixel sampling adds processing time, it generally improves image quality significantly. The valid values for this parameter is any logical OR of `FLIMAGE_NOSUBPIXEL`, `FLIMAGE_SUBPIXEL` and `FLIMAGE_NOCENTER`.

`FLIMAGE_NOCENTER` is only useful if you specify an image dimension that is larger than the warped image, and in that case the warped image is flushed top-left within the image grid, otherwise it is centered.

To illustrate how image warping can be used, we show how an image rotation by an angle `deg` can be implemented:

    float m[2][2];
    m[0][0] = m[1][1] = cos(deg * M_PI / 180.0);
    m[0][1] = sin(deg * M_PI / 180.0);
    m[1][0] = -m[0][1];

    flimage_warp(im, mat, 0, 0, FLIMAGE_SUBPIXEL);

Please note that the transformation is done in-place, i.e., after the function returns the image structure pointer, `im`, points to the rotated image.

If you specify a warp matrix with the off-diagonal elements being zero (scaling matrix), the image will only be scaled (in x-direction by `m[0][0]` and in y-direction by `m[1][1]`) without being also rotated.

By experimenting with various warp matrices you can obtain some interesting images. Just keep in mind that large values of the warp matrix elements tend to make the final image larger.

Next: General Pixel Transformation, Previous: Scaling, Up: Simple Image Processing [Contents][Index]