Remap

Overview

The Remap sample demonstrates GPU-accelerated pixel remapping using CV-CUDA’s remap operator. A coordinate map is built on the CPU with NumPy — a sinusoidal wave-distortion field — then uploaded to the GPU and applied to the source image. The result is a ripple-distorted version of the input that is saved as a viewable JPEG.

Usage

Basic Usage

Apply the default wave distortion to the built-in test image:

python3 remap.py

Custom Input

Remap a custom source image and write to a custom output path:

python3 remap.py -i input.jpg -o cat_remap.jpg

Command-Line Arguments

Argument

Short Form

Default

Description

--input

-i

tabby_tiger_cat.jpg

Input image file path

--output

-o

cvcuda/.cache/cat_remap.jpg

Output image file path

Implementation

Building the Displacement Map

# Build a sinusoidal wave-distortion map in absolute coordinates.
# The map tensor must have shape (H, W, 1) with dtype _2F32 (two float32
# values packed per element: [src_x, src_y]) or shape (H, W, 2) with dtype F32.
# We use shape (H, W, 2) / dtype F32 here so each pixel stores [src_x, src_y].
height, width, _ = input_image.shape

# Create grid of output pixel coordinates
ys = np.arange(height, dtype=np.float32)
xs = np.arange(width, dtype=np.float32)
grid_x, grid_y = np.meshgrid(xs, ys)  # both (H, W)

# Apply a sinusoidal horizontal and vertical wave displacement
amplitude = height * 0.04  # ~4 % of image height
freq_x = 2.0 * np.pi / width * 3  # 3 cycles across width
freq_y = 2.0 * np.pi / height * 3  # 3 cycles across height

# Each output pixel at (y, x) samples the source at a displaced position,
# creating a ripple effect that is visually distinctive without clipping content.
src_x = grid_x + amplitude * np.sin(freq_y * grid_y)
src_y = grid_y + amplitude * np.sin(freq_x * grid_x)

# Stack into (H, W, 2) array — channel 0 = src_x, channel 1 = src_y
map_np = np.stack([src_x, src_y], axis=2).astype(np.float32)
map_np = np.ascontiguousarray(map_np)

# Allocate a GPU tensor for the map and upload it from the host.
# Layout "HWC" matches the (H, W, 2) shape; the operator sees 2 channels of F32.
map_tensor = cvcuda.Tensor(map_np.shape, cvcuda.Type.F32, "HWC")
upload_tensor(map_np, map_tensor)

Applying the Remap Operator

# Build a sinusoidal wave-distortion map in absolute coordinates.
# The map tensor must have shape (H, W, 1) with dtype _2F32 (two float32
# values packed per element: [src_x, src_y]) or shape (H, W, 2) with dtype F32.
# We use shape (H, W, 2) / dtype F32 here so each pixel stores [src_x, src_y].
height, width, _ = input_image.shape

# Create grid of output pixel coordinates
ys = np.arange(height, dtype=np.float32)
xs = np.arange(width, dtype=np.float32)
grid_x, grid_y = np.meshgrid(xs, ys)  # both (H, W)

# Apply a sinusoidal horizontal and vertical wave displacement
amplitude = height * 0.04  # ~4 % of image height
freq_x = 2.0 * np.pi / width * 3  # 3 cycles across width
freq_y = 2.0 * np.pi / height * 3  # 3 cycles across height

# Each output pixel at (y, x) samples the source at a displaced position,
# creating a ripple effect that is visually distinctive without clipping content.
src_x = grid_x + amplitude * np.sin(freq_y * grid_y)
src_y = grid_y + amplitude * np.sin(freq_x * grid_x)

# Stack into (H, W, 2) array — channel 0 = src_x, channel 1 = src_y
map_np = np.stack([src_x, src_y], axis=2).astype(np.float32)
map_np = np.ascontiguousarray(map_np)

# Allocate a GPU tensor for the map and upload it from the host.
# Layout "HWC" matches the (H, W, 2) shape; the operator sees 2 channels of F32.
map_tensor = cvcuda.Tensor(map_np.shape, cvcuda.Type.F32, "HWC")
upload_tensor(map_np, map_tensor)

Key points:

  1. Map tensor shape: The coordinate map uses shape (H, W, 2) with dtype F32 — two float channels storing [src_x, src_y] absolute source coordinates per output pixel.

  2. Map type — ABSOLUTE: cvcuda.Remap.ABSOLUTE means each map value is an un-normalized (x, y) pixel coordinate in the source image, giving full control over the displacement.

  3. Source interpolation: src_interp=LINEAR smooths the sampled source values for a continuous displacement field; NEAREST is faster when sub-pixel accuracy is not needed.

  4. Border policy: border=REPLICATE avoids black edges at the image boundary by repeating the nearest border pixel, keeping the output perceptually clean.

  5. Host-to-device upload: The NumPy map array is transferred to a pre-allocated cvcuda.Tensor via cuda_memcpy_h2d — the same pattern used by other samples that synthesize GPU inputs.

Expected Output

The output shows the image with a sinusoidal wave distortion applied:

../../_images/tabby_tiger_cat.jpg

Original Input Image

../../_images/cat_remap.jpg

Output: Wave-Distorted Image

CV-CUDA Operators Used

Operator

Purpose

cvcuda.remap()

Warp an image using an arbitrary (H, W, 2) coordinate map

Common Utilities Used

  • read_image() - Load image as CV-CUDA tensor

  • write_image() - Save remapped image

  • cuda_memcpy_h2d - Upload the NumPy coordinate map to the GPU tensor

See Also