Aligning, straightening and augmenting images all rely on warps, and the matrix conventions are easy to get wrong.
An affine transform (rotation, scale, translation, shear) keeps parallel lines parallel and is a 2x3 float matrix. Build one and apply it:
M = cv2.getRotationMatrix2D(center, angle_deg, scale) # positive = counter-clockwise
out = cv2.warpAffine(img, M, (w, h))cv2.getAffineTransform(src3, dst3) builds the matrix from three point pairs. The output size is the canvas: rotating within the original size cuts off corners, so for a full rotation compute the new bounding size and add a translation to the matrix.
A perspective transform (homography) is a 3x3 matrix that maps any quadrilateral to any other. It is how you turn a photo of a tilted document or a whiteboard into a flat top-down view: cv2.getPerspectiveTransform(src4, dst4) from four corners (float32 arrays), then cv2.warpPerspective(img, H, (w, h)).
To transform points rather than images, use cv2.transform(pts, M) for affine matrices and cv2.perspectiveTransform(pts, H) for homographies; points need shape (n, 1, 2) and a float dtype.
Warps sample source pixels for each destination pixel, so flags= picks interpolation (INTER_NEAREST for masks), and borderMode/borderValue fill uncovered regions. cv2.invertAffineTransform and np.linalg.inv(H) map back.
Example
import cv2
import numpy as np
img = np.zeros((100, 200, 3), np.uint8)
cv2.rectangle(img, (80, 30), (120, 70), (255, 255, 255), -1)
M = cv2.getRotationMatrix2D((100, 50), 90, 1.0) # 90 deg counter-clockwise
print(M.shape) # (2, 3)
rot = cv2.warpAffine(img, M, (200, 100))
print(rot.shape) # (100, 200, 3) same canvas
src = np.float32([[20, 10], [180, 30], [190, 90], [10, 80]]) # tilted quad
dst = np.float32([[0, 0], [300, 0], [300, 200], [0, 200]]) # flat page
H = cv2.getPerspectiveTransform(src, dst)
page = cv2.warpPerspective(img, H, (300, 200))
print(page.shape) # (200, 300, 3)
pts = src.reshape(-1, 1, 2)
print(cv2.perspectiveTransform(pts, H).reshape(-1, 2).round().astype(int))
# [[ 0 0] [300 0] [300 200] [ 0 200]]Remember
- Affine = 2x3 matrix, applied with warpAffine; perspective = 3x3, warpPerspective
- getRotationMatrix2D uses degrees, positive is counter-clockwise
- Four point pairs give a homography that can flatten a document
- Transform points with cv2.transform / perspectiveTransform, shape (n, 1, 2) float
Watch out for
- Passing int32 point arrays to getPerspectiveTransform, which requires float32.