Computer vision
A hand holding a lens in front of a lake identity

Image Transforms

Move, turn, resize, mirror and cut images by changing where every pixel goes.

Types of transforms

Geometric transforms change pixel positions without changing the content.

Translation

Shift the image position.

Rotation

Rotate around a point.

Scaling

Resize the image.

Flipping

Mirror horizontally or vertically.

Affine

Any mix of the above. Parallel lines stay parallel.

Perspective

A 3-D-like change of viewpoint.

The dashed outline is the original; each card animates its transform as it appears.

Translation

Translation shifts the image by \((t_x, t_y)\) pixels.

Transformation matrix

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

Translation in OpenCV


        import cv2
        import numpy as np
        # translation matrix (shift right 100, down 50)
        M = np.float32([[1, 0, 100],  # ans:
                        [0, 1, 50]])  # ans:
        # apply translation
        height, width = img.shape[:2]
        translated = cv2.warpAffine(img, M, (width, height))  # ans:
        # shift left (negative tx)
        M = np.float32([[1, 0, -50],
                        [0, 1,  0]])
        # ans: shifts 50 pixels left
      

Rotation

Rotation turns the image by an angle \(\theta\) around a centre \((c_x, c_y)\), optionally scaling by \(s\).

$$M = \begin{bmatrix} \alpha & \beta & (1-\alpha)\,c_x - \beta\,c_y \\ -\beta & \alpha & \beta\,c_x + (1-\alpha)\,c_y \end{bmatrix} \qquad \alpha = s\cos\theta,\ \ \beta = s\sin\theta$$

Rotation in OpenCV


        # get image center
        height, width = img.shape[:2]
        center = (width // 2, height // 2)
        # rotation matrix (45 degrees, no scaling)
        M = cv2.getRotationMatrix2D(center, 45, 1.0)  # ans:
        # ans: angle=45°, scale=1.0 (no resize)
        # apply rotation
        rotated = cv2.warpAffine(img, M, (width, height))  # ans:
        # rotate 90 degrees
        M = cv2.getRotationMatrix2D(center, 90, 1.0)
        rotated = cv2.warpAffine(img, M, (width, height))
        # ans: 90° anticlockwise: positive angles turn anticlockwise
      

warpAffine, live

img
cv2.warpAffine(img, M, (620, 349))
M (2×3)

Scaling (resizing)

Scaling changes the image size. New pixels fall between old ones, so their values must be interpolated.

Nearest neighbour

Fast, blocky.

INTER_NEAREST

Bilinear

Smooth, fast. The default.

INTER_LINEAR

Bicubic

Smoother, slower.

INTER_CUBIC

Lanczos

Best quality, slowest.

INTER_LANCZOS4

The same pixels, four ways

A 40×24 crop from inside the lens, enlarged 8× with each flag.
Click the photo to pick another spot.
NearestINTER_NEAREST
BilinearINTER_LINEAR
BicubicINTER_CUBIC
LanczosINTER_LANCZOS4

Resizing in OpenCV


        # resize to specific dimensions
        resized = cv2.resize(img, (640, 480))  # ans:
        # ans: width=640, height=480 (exact size)
        # resize by scale factor
        scaled = cv2.resize(img, None, fx=0.5, fy=0.5)  # ans:
        # ans: fx=fy=0.5 means 50% of original size
        # resize with interpolation
        resized = cv2.resize(img, (320, 240), interpolation=cv2.INTER_CUBIC)  # ans:
        # ans: INTER_CUBIC for smooth downscaling
        # upscale 2x
        scaled = cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
        # ans: doubles size with bilinear interpolation
      

Note the order: cv2.resize takes (width, height), but img.shape is (height, width).

Flipping

Flipping mirrors the image across an axis.

  • Horizontal: flipCode = 1 (left ↔ right)
  • Vertical: flipCode = 0 (top ↔ bottom)
  • Both: flipCode = -1 (same as a 180° rotation)
  • Use cases: data augmentation, mirror effects.
img

Flipping in OpenCV


        # horizontal flip (left-right)
        flipped_h = cv2.flip(img, 1)  # ans:
        # ans: flipCode=1 for horizontal
        # vertical flip (up-down)
        flipped_v = cv2.flip(img, 0)  # ans:
        # ans: flipCode=0 for vertical
        # both axes (180° rotation)
        flipped_both = cv2.flip(img, -1)  # ans:
        # ans: flipCode=-1 for both axes
      

Transpose

Transpose swaps rows and columns: it reflects the image across its main diagonal, so width and height swap.

Original, 3×4

Transpose
cv2.transpose(img)

Rotate 90° clockwise
ROTATE_90_CLOCKWISE

Both are 4×3, but the pixels differ: a transpose is a 90° rotation plus a flip.

Transpose in OpenCV


        # transpose (swap width and height)
        transposed = cv2.transpose(img)  # ans:
        height, width = img.shape[:2]
        # ans: new shape = (width, height, channels)
        # transpose vs rotate 90°
        transposed = cv2.transpose(img)
        rotated = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
        # ans: different results! transpose reflects across the diagonal
        # convenient rotation functions
        rot_90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)  # ans:
        rot_180 = cv2.rotate(img, cv2.ROTATE_180)  # ans:
        rot_270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)  # ans:
      

Cropping

Cropping extracts a region of interest (ROI) with NumPy slicing: img[y1:y2, x1:x2]. No special OpenCV function needed.

Drag on the photo to choose a region

Cropping in OpenCV


        # crop region [y1:y2, x1:x2]
        cropped = img[100:300, 50:250]  # ans:
        # ans: rows 100-300, columns 50-250
        # crop center region
        height, width = img.shape[:2]
        x = width // 4
        y = height // 4
        w = width // 2
        h = height // 2
        cropped = img[y:y+h, x:x+w]  # ans:
        # ans: center half of image
      

Rows come first: y before x. A slice is a view, so use .copy() if you will modify it.

Exercises

Answer first, then press → to check.

Exercises 1 · concepts

What does translation do?

Shifts the image position by \((t_x, t_y)\).

What is the rotation centre?

The point the image rotates around.

Which interpolation is best for downscaling?

INTER_AREA or INTER_CUBIC (best quality).

What is flipCode=1?

A horizontal flip (left ↔ right).

What is the difference between transpose and rotate?

Transpose reflects across the diagonal; rotate turns without mirroring.

Exercises 2 · concepts

What happens to the size during rotation?

The output keeps the given size, so content may be clipped at the edges.

What are fx and fy in resize?

Scale factors for the x and y directions.

The fastest interpolation method?

INTER_NEAREST (nearest neighbour).

The best quality interpolation?

INTER_LANCZOS4 (slowest but best).

What is warpAffine used for?

Applying affine transformations: translation, rotation, scaling, shear.

Exercises 3 · coding


        # translate right 50, down 30
        M = np.float32([[1, 0, 50],  # ans:
                        [0, 1, 30]])  # ans:
        h, w = img.shape[:2]  # ans:
        translated = cv2.warpAffine(img, M, (w, h))  # ans:
        # rotate 30 degrees around center
        h, w = img.shape[:2]
        center = (w // 2, h // 2)
        M = cv2.getRotationMatrix2D(center, 30, 1.0)  # ans:
        rotated = cv2.warpAffine(img, M, (w, h))  # ans:
      

Exercises 4 · coding


        # resize to 800x600
        resized = cv2.resize(img, (800, 600))  # ans:
        # scale down to 25%
        scaled = cv2.resize(img, None, fx=0.25, fy=0.25)  # ans:
        # flip horizontally
        flipped = cv2.flip(img, 1)  # ans:
        # flip vertically
        flipped = cv2.flip(img, 0)  # ans:
      

Exercises 5 · coding


        # rotate 90 degrees clockwise
        rotated = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)  # ans:
        # rotate 180 degrees
        rotated = cv2.rotate(img, cv2.ROTATE_180)  # ans:
        # transpose image
        transposed = cv2.transpose(img)  # ans:
        # crop top-left 100x100 region
        cropped = img[0:100, 0:100]  # ans:
      

Exercises 6 · mixed


        # upscale 3x with cubic interpolation
        scaled = cv2.resize(img, None, fx=3, fy=3, interpolation=cv2.INTER_CUBIC)  # ans:
        # rotate with scale
        h, w = img.shape[:2]
        M = cv2.getRotationMatrix2D((w//2, h//2), 45, 0.8)
        # ans: 45° rotation + 80% scale
        rotated = cv2.warpAffine(img, M, (w, h))  # ans:
        # combine flip and rotate
        flipped = cv2.flip(img, 1)
        rotated = cv2.rotate(flipped, cv2.ROTATE_90_CLOCKWISE)  # ans:
      

Exercises 7 · mixed


        # resize maintaining aspect ratio
        h, w = img.shape[:2]
        new_w = 640
        new_h = int(h * (new_w / w))
        resized = cv2.resize(img, (new_w, new_h))  # ans:
        # crop center square
        h, w = img.shape[:2]
        size = min(h, w)
        start_y = (h - size) // 2
        start_x = (w - size) // 2
        cropped = img[start_y:start_y+size, start_x:start_x+size]  # ans:
      

Exercises 8 · advanced


        # translate with border handling
        M = np.float32([[1, 0, 100],
                        [0, 1, 50]])
        h, w = img.shape[:2]
        translated = cv2.warpAffine(img, M, (w, h),  # ans:
                                    borderMode=cv2.BORDER_CONSTANT,  # ans:
                                    borderValue=(0, 0, 0))  # ans:
      

Exercises 9 · advanced


        # rotate and expand canvas
        angle = 45
        h, w = img.shape[:2]
        center = (w//2, h//2)
        M = cv2.getRotationMatrix2D(center, angle, 1.0)
        cos = np.abs(M[0, 0])
        sin = np.abs(M[0, 1])
        new_w = int(h * sin + w * cos)
        new_h = int(h * cos + w * sin)
        M[0, 2] += (new_w - w) / 2
        M[1, 2] += (new_h - h) / 2
        rotated = cv2.warpAffine(img, M, (new_w, new_h))  # ans:
        # ans: expands the canvas to fit the rotated image