Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Move, scale and rotate with matrices

After this lesson: I can move, scale and rotate a shape by multiplying its points by a matrix.

60 min lesson4 commandsComputer vision lab: pixels, thresholds and counting objects in JupyterLab

A transformation moves every corner of a shape

A 2D transformation is a rule that moves every point of a shape: slide it, resize it or turn it. Games and design tools use them every frame.

In this lesson you write each move as a matrix, a small grid of numbers, and apply it to the corners of a triangle.

By the end of this lesson

Note

I can move, scale and rotate a shape by multiplying its points by a matrix.

Key words

WordWhat it means
Matrixa grid of numbers in rows and columns
Translateto slide a shape without turning it
Scaleto make a shape bigger or smaller
Rotateto turn a shape about the origin
Homogeneous coordinatesa point written with an extra 1

The cells students fill in are left blank in this preview.

Three moves change every point

A shape is a list of corner points. To translate it, add the same amount to every x and every y. To scale it, multiply every x and y by a factor. To rotate it, turn each point about the origin.

Move the corners and the lines between them follow, so we only ever move the corners.

Worked example: a triangle after each move

MoveCorner (4, 0) becomesCorner (0, 3) becomesMatrix rows
Translate by 2 and 3(6, 3)(2, 6)[1 0 2] [0 1 3] [0 0 1]
Scale by 2(8, 0)(0, 6)[2 0 0] [0 2 0] [0 0 1]
Rotate 90 degrees(0, 4)(-3, 0)[0 -1 0] [1 0 0] [0 0 1]

The cells students fill in are left blank in this preview.

An extra 1 lets a matrix translate

Scaling and rotating multiply a point, but a translation adds to it, and a plain 2 by 2 matrix cannot add. The trick is homogeneous coordinates: write the point (x, y) as three numbers, x, y and 1.

Now the third column of a 3 by 3 matrix multiplies that 1, so it acts as an addition. Every move, even a slide, becomes one matrix.

Rotate a point with NumPy

Command
docker exec jupyter python3 -c "import numpy as np; m = np.array([[0, -1, 0], [1, 0, 0], [0, 0, 1]]); print((m @ np.array([4, 0, 1])).tolist())"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A matrix times a point moves it

The Run prints [0, 4, 1]. The point (4, 0) is written as [4, 0, 1], and the @ symbol multiplies the matrix by it.

The first two numbers are the new point, (0, 4). The last number stays 1. This matrix turns the point 90 degrees about the origin, as the table shows.

The order of two moves matters

To do two moves, multiply their matrices into one. The matrix next to the point acts first, so for a times b times point, b happens first.

Order changes the result. Scaling by 2 and then moving by (2, 3) differs from moving first and then scaling. The scale also stretches the move.

Worked example: the point (1, 1) both ways

Order of movesMatrix to usePoint (1, 1) ends at
Scale by 2, then translate by (2, 3)translate times scale(4, 5)
Translate by (2, 3), then scale by 2scale times translate(6, 8)

The cells students fill in are left blank in this preview.

Try both orders in NumPy

Command
docker exec jupyter python3 -c "import numpy as np; t = np.array([[1, 0, 2], [0, 1, 3], [0, 0, 1]]); s = np.array([[2, 0, 0], [0, 2, 0], [0, 0, 1]]); p = np.array([1, 1, 1]); print((t @ s @ p).tolist(), (s @ t @ p).tolist())"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people think the order of two moves does not matter. Only some pairs swap safely, such as two translations. A translation and a scale do not, and neither does a rotation and a translation. Write the matrices so the first move sits closest to the point.

Apply a matrix to a triangle

Code: python
triangle = [[0, 0], [4, 0], [0, 3]]

# Move 2 across and 3 down: the last column holds the move.
matrix = [
    [1, 0, 2],
    [0, 1, 3],
    [0, 0, 1],
]

for point in triangle:
    x = point[0]
    y = point[1]
    new_x = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2]
    new_y = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2]
    print(point, "->", [new_x, new_y])
# Change the matrix to [[2, 0, 0], [0, 2, 0], [0, 0, 1]] and press Run.

Python turns angles with radians

A 90 degree turn has a cosine of 0 and a sine of 1, which is why its matrix is all whole numbers. For other angles the matrix uses the cosine and the sine of the angle, and Python measures angles in radians.

A radian is another unit for an angle. A half turn is 180 degrees, or about 3.14159 radians. math.radians converts for you.

Cosine and sine of 90 degrees

Command
docker exec jupyter python3 -c "import math; a = math.radians(90); print(round(math.cos(a), 6), round(math.sin(a), 6))"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Draw a triangle before and after a move

Command
docker exec jupyter python3 -c "from PIL import Image, ImageDraw; p = Image.new('L', (60, 40), 0); d = ImageDraw.Draw(p); d.polygon([(2, 2), (22, 2), (2, 17)], fill=120); d.polygon([(30, 10), (50, 10), (30, 25)], fill=255); p.save('move.png'); print(p.size, p.getpixel((5, 5)), p.getpixel((33, 12)), p.getpixel((50, 30)))"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Open move.png in JupyterLab

The Run prints (60, 40) 120 255 0 and saves move.png. Open it from the file list.

You see a black picture with two triangles of the same shape. The left one is dark grey, near the top left corner. The right one is white and lower, as if the first had been slid right and down.

About this lab and its source: Computer vision lab: pixels, thresholds and counting objects in JupyterLab

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.