The previous lesson established that every linear map is a matrix and that an affine map is not linear. This one develops the practical consequences of both statements: which matrices produce the usual transformations of the plane, and how translation is accommodated when the definition excludes it.
The catalogue
The linear transformations of the plane reduce to a few families, each with its matrix. The parameters describing them determine their effect completely.
det = 1.00
The determinant, from its own lesson, classifies what happens. The rotation has : it preserves areas and orientation. The scaling chosen here does too, because the factors are reciprocal. The reflection has , and the negative sign is the reversal of orientation. The projection has , because it flattens the plane onto a line and loses information irreversibly.
The matrix projecting onto the line at angle is the one from the lesson on subspaces, with a unit vector, which expands to
Transforming a set of points
A single matrix transforms any number of points. Placing them as the columns of a matrix , the product transforms them all at once:
import numpy as np
t = np.pi / 2
R = np.array([[np.cos(t), -np.sin(t)],
[np.sin(t), np.cos(t)]])
P = np.array([[1., 0., 1.],
[0., 1., 1.]]) # three points, as columns
R @ P
# array([[ 0., -1., -1.],
# [ 1., 0., 1.]])
A clash of conventions surfaces here and is worth stating. In graphics and in most linear algebra texts, points are columns and the transformation multiplies from the left: . In machine learning the examples are rows, as the lesson on matrices established, and the same operation is written .
X = P.T # the same points, as rows
np.allclose(X @ R.T, (R @ P).T) # True
Neither convention is preferable; what causes errors is mixing them. Checking .shape remains the way to tell which one someone else's code uses.
Homogeneous coordinates
Translation is not linear: it moves the origin, and the previous lesson showed that is compulsory. No matrix translates the plane.
The usual solution is to work one dimension higher. A point is represented as , and translation becomes a product with a matrix:
These are homogeneous coordinates. The map is still not linear on , but it is linear on restricted to the plane . The upper-left block holds the linear part and the third column the translation.
The gain is in composition. With every affine transformation written as a matrix, composing them is multiplying them, and an arbitrary sequence of rotations, scalings and translations reduces to a single product. This is what graphics pipelines and image transformation libraries do.
The third column holds the translation; the third row keeps the block a matrix.
Order matters, and the figure makes it plain. rotates about the origin and then shifts; shifts first and rotates the result about the origin, so the figure sweeps an arc. The violet outline is whichever order is not selected.
The difference can be read off the matrix itself. With and , the third column is in and in : in the second case the translation has been rotated along with everything else, because it was applied first.
From this comes the recipe for rotating about a point other than the origin, which no matrix can express:
move the centre to the origin, rotate, and undo the translation. It reads right to left, like any composition.
Application: data augmentation
Data augmentation in vision consists of applying random geometric transformations to the training images, so that the model learns to recognise an object independently of its position, scale or orientation.
def random_affine(rng, scale=(0.9, 1.1), turn=15, shift=0.1):
t = rng.uniform(-turn, turn) * np.pi / 180
k = rng.uniform(*scale)
c, s = np.cos(t), np.sin(t)
R = np.array([[k * c, -k * s, rng.uniform(-shift, shift)],
[k * s, k * c, rng.uniform(-shift, shift)],
[0., 0., 1.]])
return R
Each call returns a matrix, and composing several transformations is multiplying them. The libraries in this area work exactly this way, and what they add is interpolation: applying the matrix to the pixel grid produces non-integer coordinates, and the value at each destination pixel has to be estimated from its neighbours.
The justification for the technique is a hypothesis about the problem, not about the algebra: the label is assumed invariant under those transformations. Rotating a handwritten digit by does not change which digit it is, but rotating it by can turn a into a . The range of the parameters encodes that assumption, and choosing it badly introduces mislabelled examples.
Exercise. Build the matrix rotating by about the point by composing in homogeneous coordinates, and check that it leaves that point fixed. Then verify that the upper-left block of the product equals and explain why.