Stretching

Image resizing

Intuitively, image resizing is the operation which performs the reduce or increase of the image dimensions.

Digital images consist of pixels organized such as a matrix or a plane (flat surface). In this plane, each pixel has got coordinates (x,y) which are the indices of its position in this matrix.

In a cartesian system, we can consider the coordinates (x,y) such as the coordinates of a vector, and then we can apply geometrical transformations by the use of some mathematical tools (such as homothetic transformation).

The matrices below are used to perform such an operation, the first one preserves the aspect ratio, the second one allows the use of different dilatation factors according to the x axis and the y axis.

 

The resulting transformations are illustrated by the picture below:

For a more versatile usage, we need an offset given by a translation transformation:

Rounding errors

It is possible to use the mathematical expression described above but , as the use of fixed point operations introduces rounding errors, some of the pixels of the destination image could not be set. The idea is then to compute, for each pixel of the destination image, the pixel coordinates of the original image that matches with. So, it seems better to go from the destination to the source and in this case to test if the computed coordinates are inside the source image.

Going from destination to source may also introduce unwanted behaviors such as pixel overlappings. Always due to the rouding errors, it is possible that one destination pixel matches with two source pixels. In this case the corresponding colors will be overlayed one over the other and that may impact on the global rendering quality.

This is a typical problem encountered in digital computations.

From destination to source

If kx or ky (not exclusive) is not equal to zero, the transformation matrix M introduced above is invertible (nonsingular) as its determinant is not equal to zero.

that means it exists a matrix M-1 such as M-1M=MM-1=I2

Such a matrix M-1 is used to compute source pixel coordinates knowing the destination pixel coordinates. The inverse matrix and the relation between the coordinates of the pixels of destination and those of the source is described below:

Finally, the expression of the source pixel coordinates, for given destination pixel coordinates, is given by:

This is the formula used in the pno code, by taking care that the computed coordinates are inside the source image, otherwise the pixel color is set to the background color.

Rounding computed values

For computations, I use fixed point operations. In the provided code, I simply truncate the computed coordinates in fixed point format for having their equivalent values in integer format. It is possible to use a rounding formula by adding the value 0.5 (in fixed point format):

// fixed point constant
#define FixedPoint    12    // 20:12 fixed point format
const long ONEFixedPoint = 1<< FixedPoint;       // 1.0
const long HalfFixedPoint = 1<< (FixedPoint-1);  // 0.5

// wihtout rounding
js = FixedPointToInt(FPS_MUL(IntToFixedPoint(jd-OffY),FactH));
is = FixedPointToInt(FPS_MUL(IntToFixedPoint(id-OffX),FactW));

// with rounding
js = FixedPointToInt(FPS_MUL(IntToFixedPoint(jd-OffY),FactH) 
                     + HalfFixedPoint);
is = FixedPointToInt(FPS_MUL(IntToFixedPoint(id-OffX),FactW)
                     + HalfFixedPoint);