Computer vision

Geometric Transforms

Move every pixel somewhere else with one small matrix: shift, rotate, scale, shear, or change the point of view.

Affine transformations

Affine transform: a linear mapping (plus a shift) that keeps points, straight lines and planes.

Preserved:

  • Parallelism: parallel lines stay parallel
  • Ratios of distances along a line
  • Barycentres (centres) of weighted points

Not preserved: angles; distances (except along parallel lines).

Examples: translation, rotation, scaling, shearing. Note the grid: its lines stay straight and parallel.

The affine transform matrix

2×3 matrix

$$M = \begin{bmatrix} a & b & t_x \\ c & d & t_y \end{bmatrix}$$

Transformation

$$\begin{bmatrix} x' \\ y' \end{bmatrix} = \begin{bmatrix} a & b \\ c & d \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} + \begin{bmatrix} t_x \\ t_y \end{bmatrix}$$

Affine transform in OpenCV


        import cv2
        import numpy as np
        # define 3 points in the source
        pts1 = np.float32([[50, 50], [200, 50], [50, 200]])  # ans:
        # define 3 points in the destination
        pts2 = np.float32([[10, 100], [200, 50], [100, 250]])  # ans:
        # compute the affine matrix
        M = cv2.getAffineTransform(pts1, pts2)  # ans:
        # ans: M is a 2x3 matrix
        # apply the transform
        h, w = img.shape[:2]
        result = cv2.warpAffine(img, M, (w, h))  # ans:
      

Drag three points

img with pts1
cv2.warpAffine(img, M, (w, h)): drag pts2

Perspective transform

Perspective simulates a 3-D viewing angle.

Properties

  • Straight lines stay straight
  • Parallel lines may converge (a vanishing point)
  • Preserves collinearity

Use cases

Document scanning, bird's-eye view, rectification.

Matrix

A 3×3 homography matrix.

The perspective transform matrix

3×3 homogeneous matrix

$$H = \begin{bmatrix} h_{11} & h_{12} & h_{13} \\ h_{21} & h_{22} & h_{23} \\ h_{31} & h_{32} & h_{33} \end{bmatrix}$$

Transformation

$$\begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} = \frac{1}{w} \begin{bmatrix} h_{11} & h_{12} & h_{13} \\ h_{21} & h_{22} & h_{23} \\ h_{31} & h_{32} & h_{33} \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}$$

\(w = h_{31}x + h_{32}y + h_{33}\): dividing by it is what makes far things smaller.

You need 4 point pairs to solve for it (8 unknowns, since \(h_{33} = 1\)).

Perspective transform in OpenCV


        # define 4 points in the source (corners of a document)
        pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])  # ans:
        # define 4 points in the destination (a rectangle)
        pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])  # ans:
        # compute the perspective matrix
        M = cv2.getPerspectiveTransform(pts1, pts2)  # ans:
        # ans: M is a 3x3 homography matrix
        # apply the transform
        result = cv2.warpPerspective(img, M, (300, 300))  # ans:
      

Scan it: drag four corners

img: drag the four corners of pts1 (order 1, 2, 3, 4)
warpPerspective(img, M, (300, 300))

Affine vs perspective

Affine

  • 2×3 matrix (6 parameters)
  • Needs 3 point pairs
  • Preserves parallelism
  • Faster to compute

Perspective

  • 3×3 matrix (8 parameters)
  • Needs 4 point pairs
  • Allows vanishing points
  • More general

Rule: use affine if parallel lines stay parallel; perspective otherwise.

Shearing

Shear slants the shape of the image.

Horizontal

$$M = \begin{bmatrix} 1 & s_x & 0 \\ 0 & 1 & 0 \end{bmatrix}$$

Vertical

$$M = \begin{bmatrix} 1 & 0 & 0 \\ s_y & 1 & 0 \end{bmatrix}$$

Shearing in OpenCV


        # horizontal shear
        M = np.float32([[1, 0.5, 0],  # ans:
                        [0, 1,   0]])  # ans:
        sheared = cv2.warpAffine(img, M, (w + int(h*0.5), h))  # ans:
        # vertical shear
        M = np.float32([[1,   0, 0],
                        [0.5, 1, 0]])
        sheared = cv2.warpAffine(img, M, (w, h + int(w*0.5)))  # ans:
        # combined shear
        M = np.float32([[1,  0.3, 0],
                        [0.2, 1,  0]])
        sheared = cv2.warpAffine(img, M, (int(w*1.3), int(h*1.2)))  # ans:
        # ans: the output size grows so the slanted image still fits
      

Exercises

Answer first, then press → to check.

Exercises 1 · concepts

What is an affine transform?

A linear mapping that preserves parallelism and ratios.

What size is the affine matrix?

2×3 (6 parameters).

How many points define an affine transform?

3 point pairs.

What is a perspective transform?

A 3-D projection that allows vanishing points.

How many points for a perspective transform?

4 point pairs.

Exercises 2 · concepts

What does affine preserve?

Parallelism, ratios of distances, straight lines.

What does perspective NOT preserve?

Parallelism: parallel lines can converge.

When do you use affine vs perspective?

Affine if parallelism is kept; perspective for 3-D effects.

What is shearing?

A slanting transformation.

What size is the perspective matrix?

A 3×3 homography (8 free parameters).

Exercises 3 · coding


        # affine transform from 3 points
        pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
        pts2 = np.float32([[10, 100], [200, 50], [100, 250]])
        M = cv2.getAffineTransform(pts1, pts2)  # ans:
        h, w = img.shape[:2]
        result = cv2.warpAffine(img, M, (w, h))  # ans:
      

Exercises 4 · coding


        # perspective transform (document scan)
        pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
        pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])
        M = cv2.getPerspectiveTransform(pts1, pts2)  # ans:
        result = cv2.warpPerspective(img, M, (300, 300))  # ans:
      

Exercises 5 · mixed


        # horizontal shear by 0.3
        M = np.float32([[1, 0.3, 0],  # ans:
                        [0, 1,   0]])  # ans:
        h, w = img.shape[:2]
        sheared = cv2.warpAffine(img, M, (int(w + h*0.3), h))  # ans:
        # combine rotation and scaling in one affine
        center = (w // 2, h // 2)
        M = cv2.getRotationMatrix2D(center, 45, 1.5)  # ans:
        result = cv2.warpAffine(img, M, (w, h))  # ans: