Next: General Pixel Transformation, Previous: Scaling, Up: Simple Image Processing [Contents][Index]
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]