Inpaint

Overview

The Inpaint sample demonstrates image inpainting using CV-CUDA’s GPU-accelerated inpaint operator. Inpainting reconstructs the pixel values inside a user-supplied mask region by propagating colour information from the surrounding unmasked pixels. The sample simulates salt-and-pepper sensor noise by randomly zeroing ~15 % of pixels, then uses inpainting to remove the noise and restore the image.

Usage

Basic Usage

Inpaint the default tabby-cat image:

python3 inpaint.py -i input.jpg

Custom Input and Output

Specify a custom input image and output path:

python3 inpaint.py -i image.jpg -o cat_inpaint.jpg

Command-Line Arguments

Argument

Short Form

Default

Description

--input

-i

tabby_tiger_cat.jpg

Input image file path

--output

-o

cvcuda/.cache/cat_inpaint.jpg

Output image file path

Implementation

Inpainting and Outside-Mask Restoration

# Reshape to NHWC and download so we can synthesise the damage on the CPU.
# We keep a clean copy of the original to restore non-masked pixels later.
nhwc_image: cvcuda.Tensor = input_image.reshape((1, height, width, 3), "NHWC")
orig_np = download_tensor(input_image)  # (H, W, 3)
damaged_np = orig_np.copy()[np.newaxis]  # (1,H,W,3)

# Simulate salt-and-pepper sensor noise by randomly zeroing ~15% of pixels.
# Each masked pixel is surrounded by unmasked neighbours so the inpaint
# operator fills every corrupted pixel cleanly from its immediate context.
rng = np.random.default_rng(42)
noise_mask = rng.random((height, width)) < 0.15  # bool (H, W)
mask_np = np.zeros((1, height, width, 1), dtype=np.uint8)
mask_np[0, :, :, 0] = noise_mask.astype(np.uint8) * 255
damaged_np[0, noise_mask, :] = 0

# Save the noisy image for the before/after comparison in the docs.
damaged_output = args.output.parent / (
    args.output.stem + "_damaged" + args.output.suffix
)
upload_tensor(np.ascontiguousarray(damaged_np), nhwc_image)
write_image(nhwc_image.reshape((height, width, 3), "HWC"), damaged_output)

# Re-upload damaged (write_image may have altered the tensor content)
upload_tensor(np.ascontiguousarray(damaged_np), nhwc_image)

mask_tensor: cvcuda.Tensor = cvcuda.Tensor(
    (1, height, width, 1), cvcuda.Type.U8, "NHWC"
)
upload_tensor(mask_np, mask_tensor)

Key points:

  1. Mask format: The mask must be a single-channel (NHWC with C=1) U8 tensor. Non-zero pixels mark the region to be reconstructed; zero pixels are left unchanged.

  2. Batched input: cvcuda.inpaint requires an NHWC (batched) source tensor. A plain HWC image is reshaped to (1, H, W, C) before the call.

  3. inpaintRadius: Controls the neighbourhood radius examined when reconstructing each masked pixel. Larger values smooth over wider damaged areas at the cost of more computation.

  4. Outside-mask restoration: The operator may alter pixels just outside the mask boundary, so the result is downloaded and the original content is restored everywhere outside the mask (via np.where) before the final image is uploaded and saved.

  5. Synthetic mask via upload_tensor: The mask is built as a NumPy array on the CPU and then uploaded to a pre-allocated GPU tensor with upload_tensor, matching the pattern used whenever host-side parameter data must be passed as a tensor.

Expected Output

The output shows the image with salt-and-pepper noise removed by inpainting:

../../_images/cat_inpaint_damaged.jpg

Input: Image with simulated salt-and-pepper sensor noise (~15 % pixels zeroed)

../../_images/cat_inpaint.jpg

Output: Noise removed by inpainting

CV-CUDA Operators Used

Operator

Purpose

cvcuda.inpaint()

Reconstruct masked pixel regions using surrounding colour information

Common Utilities Used

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

  • write_image() - Save inpainted image

  • upload_tensor - Upload the CPU-built mask and result arrays to GPU tensors

  • download_tensor - Download tensors to the CPU for damage synthesis and restoration

See Also