Skip to content
AI360Xpert
Beta

Perspective Transformations

A perspective map applies a 3 by 3 homography with eight degrees of freedom, dividing by depth to model viewpoint change and flatten tilted planes.

A homography divides mapped coordinates by a depth term, so far points shrink and a tilted square becomes a rectangle again.
A homography divides mapped coordinates by a depth term, so far points shrink and a tilted square becomes a rectangle again.

Why Does This Exist?

Cameras tilt. A document photographed at an angle is a trapezoid, a road narrows toward the horizon, and two photos of one wall differ by viewpoint, not content. Affine maps keep parallels parallel, so they cannot undo any of this. The perspective transformation adds the one missing ingredient, division by depth, which models how far points project smaller. It powers document flattening, bird's-eye road views and panorama stitching.

The prerequisite is the affine page: same matrix-multiply idea, one row taller. This page covers the 3 by 3 homography, why four points solve it, and the flat-plane assumption that bounds it.

Think of It Like This

Photographing a tile floor from ankle height

Lie near the floor and photograph tiles stretching away: near tiles look huge, far tiles shrink to slivers, and the parallel grout lines converge. Now stand on a ladder directly above and shoot straight down: every tile is square again. The homography is the math that converts the ankle-height photo into the ladder photo, undoing exactly the shrinking-with-distance.

The analogy stops at flatness. It works because tiles share one plane. A chair leg sticking out of that plane has true 3D height, and no flat-plane warp can un-tilt it correctly.

How It Actually Works

The 3 by 3 homography

A homography maps (x,y)(x, y) through a 3×33 \times 3 matrix HH, then divides by the third component:

[x′y′w′]=H[xy1],xnew=x′w′,  ynew=y′w′\begin{bmatrix} x' \\ y' \\ w' \end{bmatrix} = H \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}, \quad x_{new} = \frac{x'}{w'},\; y_{new} = \frac{y'}{w'}

That division is the whole difference from affine: w′w' varies per pixel and encodes depth, so distant points shrink. HH has nine entries but scale does not matter (doubling HH cancels in the division), leaving eight degrees of freedom, with h33h_{33} conventionally fixed at 1.

Worked example with HH rows [1,0,0][1, 0, 0], [0,1,0][0, 1, 0], [0.01,0,1][0.01, 0, 1] on the point (100,50)(100, 50): the product is (100,50,2.0)(100, 50, 2.0) since w′=0.01⋅100+1=2.0w' = 0.01 \cdot 100 + 1 = 2.0, and dividing gives (50,25)(50, 25). The point halves its distance from the origin, which is foreshortening in one line of arithmetic.

Four points solve it

Each correspondence gives two equations, so four point pairs with no three collinear determine the eight unknowns. cv2.getPerspectiveTransform(src4, dst4) solves it for hand-picked corners (document scanners), while real stitching finds many candidate matches with a feature detector and fits robustly with RANSAC, which discards the mismatches first. cv2.warpPerspective applies the result by inverse mapping, so output pixels pull from the source with no holes.

The flat-plane limit

A homography exactly relates two views of the same plane, or two shots from the same camera center. Anything off the plane (pedestrians on the road you warped to top-down) smears, because one plane's warp is wrong for other depths. Parallax is the diagnostic: if foreground and background need different warps, no single homography fits and you need depth-aware reconstruction instead.

Code

import numpy as np
H = np.array([[1, 0, 0], [0, 1, 0], [0.01, 0, 1]], dtype=float)q = H @ np.array([100, 50, 1], dtype=float)print(q.tolist())# -> [100.0, 50.0, 2.0]print((q[:2] / q[2]).tolist())  # divide by w: foreshortening# -> [50.0, 25.0]

Watch Out For

Vanishing w near zero

When w′w' approaches zero for pixels inside the frame, the division explodes and smears content toward infinity. The symptom is streaks shooting off one side of the warp. It usually traces to near-collinear calibration points or heavy outliers, so validate point geometry and use RANSAC on noisy matches.

One homography for a 3D scene

Warping a street photo to top-down with a road-plane homography stretches cars and people vertically, because they were never on that plane. The symptom is smeared upright objects in an otherwise clean warp. Restrict homographies to planar surfaces or pure camera rotation, and reach for depth methods otherwise.

The Quick Version

  • A homography is a 3 by 3 matrix plus division by w′w', modeling viewpoint change with depth.
  • Scale invariance leaves eight degrees of freedom; four point pairs solve it.
  • getPerspectiveTransform fits hand-picked corners; RANSAC fits noisy feature matches.
  • Exact for one plane or pure rotation; wrong wherever real 3D relief sticks out.
  • Watch for w′w' near zero, which smears the warp toward infinity.