cvcuda.tv

These runnable samples demonstrate augmentation, color, geometry, and preprocessing pipelines using the cvcuda.tv functional API and cvcuda.tv.Compose. They use the repository’s default image and accept the standard sample --input and --output options. Run any script from the repository root, for example:

python3 samples/operators/cvcuda_tv_color.py

Augmentation

args: argparse.Namespace = parse_image_args(output_name="cat_cvcuda_tv_augment.jpg")
input_image: cvcuda.Tensor = read_image(args.input)
height, width, _ = input_image.shape

fill_host = np.array([[[32]], [[96]], [[224]]], dtype=np.uint8)
fill = cvcuda.Tensor(fill_host.shape, dtype=np.uint8, layout="CHW")
upload_tensor(fill_host, fill)

erase_height = max(1, height // 4)
erase_width = max(1, width // 4)
erased = cvcuda.tv.erase(
    input_image,
    (height - erase_height) // 2,
    (width - erase_width) // 2,
    erase_height,
    erase_width,
    fill,
)
output_image = cvcuda.tv.jpeg(erased, quality=65)

assert (output_image.shape, output_image.layout, output_image.dtype) == (
    input_image.shape,
    input_image.layout,
    input_image.dtype,
)
write_image(output_image, args.output)
assert args.output.is_file()

Color

args: argparse.Namespace = parse_image_args(output_name="cat_cvcuda_tv_color.jpg")
input_image: cvcuda.Tensor = read_image(args.input)

output_image = cvcuda.tv.adjust_brightness(input_image, 1.15)
output_image = cvcuda.tv.adjust_contrast(output_image, 1.2)
output_image = cvcuda.tv.adjust_saturation(output_image, 0.8)

assert (output_image.shape, output_image.layout, output_image.dtype) == (
    input_image.shape,
    input_image.layout,
    input_image.dtype,
)
write_image(output_image, args.output)
assert args.output.is_file()

Geometry

args: argparse.Namespace = parse_image_args(
    output_name="cat_cvcuda_tv_geometry.jpg"
)
input_image: cvcuda.Tensor = read_image(args.input)

resized = cvcuda.tv.resize(input_image, [args.height, args.width])
output_image = cvcuda.tv.rotate(resized, angle=15.0)

assert (output_image.shape, output_image.layout, output_image.dtype) == (
    (args.height, args.width, input_image.shape[-1]),
    input_image.layout,
    input_image.dtype,
)
write_image(output_image, args.output)
assert args.output.is_file()

Miscellaneous Preprocessing

args: argparse.Namespace = parse_image_args(output_name="cat_cvcuda_tv_misc.jpg")
input_image: cvcuda.Tensor = read_image(args.input)
stream = cvcuda.Stream()

float_image = cvcuda.tv.to_dtype(input_image, np.float32, scale=True, stream=stream)
preprocessed = cvcuda.tv.normalize(
    float_image,
    mean=[0.485, 0.456, 0.406],
    std=[0.229, 0.224, 0.225],
    stream=stream,
)

blurred = cvcuda.tv.gaussian_blur(input_image, kernel_size=[5, 5], stream=stream)
output_image = cvcuda.tv.gaussian_noise(blurred, sigma=0.03, seed=42, stream=stream)
stream.sync()

assert (preprocessed.shape, preprocessed.layout, preprocessed.dtype) == (
    input_image.shape,
    input_image.layout,
    cvcuda.Type.F32,
)
assert (output_image.shape, output_image.layout, output_image.dtype) == (
    input_image.shape,
    input_image.layout,
    input_image.dtype,
)
write_image(output_image, args.output)
assert args.output.is_file()

TorchVision Pipelines

args: argparse.Namespace = parse_image_args(output_name="cat_cvcuda_tv_compose.jpg")
input_image: cvcuda.Tensor = read_image(args.input)
# Convert HWC to CHW to demonstrate Torch output; Compose also accepts HWC.
image = torch.as_tensor(input_image.cuda()).permute(2, 0, 1).contiguous()

pipeline = cvcuda.tv.Compose(
    [
        v2.RandomResizedCrop(224, scale=(0.5, 1.0)),
        v2.RandomHorizontalFlip(),
        v2.ColorJitter(brightness=0.3, contrast=0.3, saturation=0.3),
        v2.ToDtype(torch.float32, scale=True),
        v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ]
)

torch.manual_seed(0)
augmented = pipeline(image)
torch.manual_seed(0)
repeated = pipeline(image)
assert (augmented.shape, augmented.dtype) == ((3, 224, 224), torch.float32)
assert torch.equal(augmented, repeated)

preview = cvcuda.tv.Compose(
    [v2.RandomResizedCrop(224, scale=(0.5, 1.0)), v2.RandomHorizontalFlip()]
)
torch.manual_seed(0)
output_image = preview(image).permute(1, 2, 0).contiguous()
write_image(cvcuda.as_tensor(output_image, "HWC"), args.output)
assert args.output.is_file()

See Also