Warp Perspective

Overview

The Warp Perspective sample demonstrates GPU-accelerated perspective transform using CV-CUDA’s warp_perspective operator. A 3×3 homography matrix maps every destination pixel back to its source location, enabling keystone correction, bird’s-eye-view synthesis, and other projective geometry tasks.

Usage

Basic Usage

Apply a default mild-keystone perspective transform:

python3 warp_perspective.py -i input.jpg

Custom Output Path

Save the warped result to a specific file:

python3 warp_perspective.py -i input.jpg -o cat_warp_perspective.jpg

Command-Line Arguments

Argument

Short Form

Default

Description

--input

-i

tabby_tiger_cat.jpg

Input image file path

--output

-o

cvcuda/.cache/cat_warp_perspective.jpg

Output image file path

Implementation

Perspective Matrix Setup

# Build a perspective matrix that applies a mild keystone / tilt effect.
# The matrix maps destination pixel (x, y) to source pixel via homogeneous
# coordinates: [x_src, y_src, w] = M @ [x_dst, y_dst, 1].
# We nudge the top-right and bottom-left corners inward so the image
# appears to recede into the distance without leaving empty regions.
src_pts = np.array(
    [[0, 0], [w, 0], [w, h], [0, h]],
    dtype=np.float32,
)
dst_pts = np.array(
    [
        [w * 0.1, h * 0.05],
        [w * 0.9, h * 0.1],
        [w * 0.85, h * 0.95],
        [w * 0.15, h * 0.9],
    ],
    dtype=np.float32,
)

# Use OpenCV-compatible 3x3 float32 perspective matrix expected by cvcuda.warp_perspective.
# We compute it manually via the 4-point DLT (Direct Linear Transform).
def _get_perspective_transform(src: np.ndarray, dst: np.ndarray) -> np.ndarray:
    """Compute 3x3 perspective matrix from 4 point correspondences (DLT)."""
    A = []
    for (sx, sy), (dx, dy) in zip(src, dst, strict=True):
        A.append([-sx, -sy, -1, 0, 0, 0, dx * sx, dx * sy, dx])
        A.append([0, 0, 0, -sx, -sy, -1, dy * sx, dy * sy, dy])
    A_mat = np.array(A, dtype=np.float64)
    _, _, Vt = np.linalg.svd(A_mat)
    H = Vt[-1].reshape(3, 3)
    return (H / H[2, 2]).astype(np.float32)

xform = _get_perspective_transform(dst_pts, src_pts)

Warp Perspective Call

# Build a perspective matrix that applies a mild keystone / tilt effect.
# The matrix maps destination pixel (x, y) to source pixel via homogeneous
# coordinates: [x_src, y_src, w] = M @ [x_dst, y_dst, 1].
# We nudge the top-right and bottom-left corners inward so the image
# appears to recede into the distance without leaving empty regions.
src_pts = np.array(
    [[0, 0], [w, 0], [w, h], [0, h]],
    dtype=np.float32,
)
dst_pts = np.array(
    [
        [w * 0.1, h * 0.05],
        [w * 0.9, h * 0.1],
        [w * 0.85, h * 0.95],
        [w * 0.15, h * 0.9],
    ],
    dtype=np.float32,
)

# Use OpenCV-compatible 3x3 float32 perspective matrix expected by cvcuda.warp_perspective.
# We compute it manually via the 4-point DLT (Direct Linear Transform).
def _get_perspective_transform(src: np.ndarray, dst: np.ndarray) -> np.ndarray:
    """Compute 3x3 perspective matrix from 4 point correspondences (DLT)."""
    A = []
    for (sx, sy), (dx, dy) in zip(src, dst, strict=True):
        A.append([-sx, -sy, -1, 0, 0, 0, dx * sx, dx * sy, dx])
        A.append([0, 0, 0, -sx, -sy, -1, dy * sx, dy * sy, dy])
    A_mat = np.array(A, dtype=np.float64)
    _, _, Vt = np.linalg.svd(A_mat)
    H = Vt[-1].reshape(3, 3)
    return (H / H[2, 2]).astype(np.float32)

xform = _get_perspective_transform(dst_pts, src_pts)

Key points:

  1. 3×3 float32 matrix: warp_perspective expects a 3×3 homography matrix, either as a nested Python list or a float32 NumPy array. The matrix relates homogeneous destination coordinates to homogeneous source coordinates.

  2. WARP_INVERSE_MAP flag: When this flag is combined with the interpolation mode the matrix is interpreted as a destination→source mapping, which is how the standard DLT construction works. Without the flag the operator inverts the matrix internally.

  3. Border mode: cvcuda.Border.CONSTANT fills pixels that map outside the source image with the border_value; REPLICATE and WRAP are also supported.

  4. Batch support: Pass an ImageBatch and a (N, 9) float32 transform tensor to apply per-image perspective matrices in a single call.

Expected Output

../../_images/tabby_tiger_cat.jpg

Original Input Image

../../_images/cat_warp_perspective.jpg

Output: Perspective-warped image

CV-CUDA Operators Used

Operator

Purpose

cvcuda.warp_perspective()

Apply a 3×3 homography perspective transform to an image

Common Utilities Used

See Also