Skip to content

Perspective Distortion

Perspective distortion allows to transform images in such way that some part of image become looking closer and the other part looking closer. In perspective distortion straight lines remains straight, but parallel lines may not remain parallel.

Use cases

The use cases of perspective distortion are e.g.

Theory

Perspective distortion is defined by following equations:

Xd=sxXs+ryYs+txpxXs+pyYs+1Yd=rxXs+syYs+typxXs+pyYs+1

where Xd, Yd are destination image coords, Xs, Ys are source image coords and sx,ry,tx,rx,sy,ty,px,py,1 are coefficients of equations that can be written in matrix form:

(sxrytxrxsytypxpy1)

The first 6 values of matrix is in fact the same coefficients to that of the affine matrix, though they are slightly reordered to be more logical (in 'matrix math' terms, the first 6 elements have been diagonally transposed).

The extra two arguments px,py form a scaling divisor to the whole distortion which causes the image to look smaller in the specific direction according to the values given, and thus giving the distorted image the perspective 'distance' effect. If these two values are set to zero, perspective distortion becomes equivalent to affine distortion.

Best-fit viewport

Perspective Distortion supports best-fit output image virtual viewport calculation to contain whole distorted image:

ts
const result = await distort(image, "Perspective", args, {
  viewport: "bestFit", // or true
});

Usage

Perspective distortion comes in two forms of usage:

Using control points

ts
const result = await distort(image, "Perspective", controlPoints);

where controlPoints is flat array of control points mappings.

INFO

Control points mapping is 4 numbers: U, V, X, Y, where U and V are corresponding x and y coordinates of source image point, and X and Y are corresponding x and y coordinates of that point in result image.

Perspective distortion requires at least 4 sets of control points (16 values).

If more than 4 sets of control points are given, Least Squares method will be used to determine most accurate fitting for distortion.

Using forward mapping perspective matrix

You can pass array of Perspective matrix coefficients as distortion arguments for "PerspectiveProjection" distortion.

These coefficient are (from equations above): [sx, ry, tx, rx, sy, ty, px, py]. You don't need to pass 9th coefficient, as it is constant 1.

ts
const matrix = [sx, ry, tx, rx, sy, ty, px, py];
const result = await distort(image, "PerspectiveProjection", matrix);

Internally, this forward matrix will be inverted to get reverse pixel mapping perspective matrix.

Viewing distant horizons

TIP

See Viewing Distant Horizons at ImageMagick distortions guide for examples.

If you adjust control points or forward matrix to produce vanishing point inside image bounds, a 'horizon' will appear, which is the line on one side of which lies image plane — image pixels itself and virtual pixels; and on the other side lies 'sky' — pixels which coords maps to infinity in the source image.

The 'sky' will only appear in perspective distorted images when the resulting image is highly foreshortened by the distortion.

These invalid pixels are transparent by default in Lens. You can change their color by specifying custom color at matteColor option:

ts
const result = await distort(image, "Perspective", args, {
  matteColor: "#f00", // Red
});