Skip to content

randaugment_multispectral

anomaly_match.datasets.augmentation.randaugment_multispectral

Multispectral-compatible augmentations for arbitrary channel counts.

This module provides augmentation operations that work with images having any number of channels (not just RGB). It excludes PIL-dependent operations like AutoContrast, Brightness, Color, and Contrast that assume RGB images.

Based on the approach from DistMSMatch/MSMatch.

MultispectralRandAugment(n, m, num_channels=4)

Random augmentation pipeline for multispectral images.

Randomly applies a series of channel-agnostic image transformations that work with arbitrary channel counts.

Parameters:

Name Type Description Default
n int

Number of augmentation operations to apply

required
m int

Magnitude parameter (unused, kept for API compatibility)

required
num_channels int

Number of channels in the images

4

Attributes:

Name Type Description
n

Number of augmentation operations to apply

m

Magnitude parameter (unused, kept for API compatibility)

num_channels

Number of image channels

augment_list

List of available augmentation operations

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def __init__(self, n: int, m: int, num_channels: int = 4) -> None:
    self.n = n
    self.m = m
    self.num_channels = num_channels
    self.augment_list = multispectral_augment_list()

__call__(img)

Apply random augmentations to the input image.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be augmented. Will be converted to uint8 if necessary, as operations like Posterize and Solarize use bit-shift arithmetic that assumes 0-255 integer values.

required

Returns:

Type Description
ndarray

Augmented numpy array (uint8)

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def __call__(self, img: np.ndarray) -> np.ndarray:
    """Apply random augmentations to the input image.

    Args:
        img: numpy array (H, W, C) to be augmented. Will be converted to
            uint8 if necessary, as operations like Posterize and Solarize
            use bit-shift arithmetic that assumes 0-255 integer values.

    Returns:
        Augmented numpy array (uint8)
    """
    # Ensure input is numpy array
    if not isinstance(img, np.ndarray):
        img = np.array(img)

    # Convert to uint8 — operations like Posterize and Solarize use
    # bit-shift arithmetic that requires integer 0-255 values.
    if img.dtype != np.uint8:
        img = np.clip(img, 0, 255).astype(np.uint8)

    # Apply n random augmentations
    ops = random.choices(self.augment_list, k=self.n)
    for op, min_val, max_val in ops:
        val = min_val + float(max_val - min_val) * random.random()
        img = op(img, val)

    # Apply cutout (for FixMatch)
    cutout_val = random.random() * 0.5
    img = Cutout(img, cutout_val, num_channels=self.num_channels)

    return img

Identity(img, v)

Return the image unchanged.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Unused parameter

required

Returns:

Type Description
ndarray

The original image

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def Identity(img: np.ndarray, v: float) -> np.ndarray:
    """Return the image unchanged.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Unused parameter

    Returns:
        The original image
    """
    return img

Posterize(img, v)

Reduce the number of bits for each channel.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Number of bits to keep for each channel (range [4, 8])

required

Returns:

Type Description
ndarray

numpy array with reduced color depth

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def Posterize(img: np.ndarray, v: float) -> np.ndarray:
    """Reduce the number of bits for each channel.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Number of bits to keep for each channel (range [4, 8])

    Returns:
        numpy array with reduced color depth
    """
    v = int(v)
    v = max(1, min(8, v))
    shift = 8 - v
    return ((img >> shift) << shift).astype(np.uint8)

Rotate(img, v)

Rotate the image by v degrees.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Rotation angle in degrees (range [-30, 30])

required

Returns:

Type Description
ndarray

Rotated numpy array

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def Rotate(img: np.ndarray, v: float) -> np.ndarray:
    """Rotate the image by v degrees.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Rotation angle in degrees (range [-30, 30])

    Returns:
        Rotated numpy array
    """
    transform = A.Rotate(limit=(v, v), border_mode=0, p=1.0)
    return transform(image=img)["image"]

Sharpness(img, v)

Adjust the sharpness of the image using unsharp masking.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Sharpness factor (range [0.05, 0.95])

required

Returns:

Type Description
ndarray

numpy array with adjusted sharpness

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def Sharpness(img: np.ndarray, v: float) -> np.ndarray:
    """Adjust the sharpness of the image using unsharp masking.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Sharpness factor (range [0.05, 0.95])

    Returns:
        numpy array with adjusted sharpness
    """
    # Apply per-channel sharpening using unsharp mask
    blurred = uniform_filter(img.astype(np.float32), size=(3, 3, 1))
    sharpened = img.astype(np.float32) + v * (img.astype(np.float32) - blurred)
    return np.clip(sharpened, 0, 255).astype(np.uint8)

ShearX(img, v)

Apply horizontal shear to the image.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Shear factor (range [-0.3, 0.3])

required

Returns:

Type Description
ndarray

numpy array with horizontal shear applied

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def ShearX(img: np.ndarray, v: float) -> np.ndarray:
    """Apply horizontal shear to the image.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Shear factor (range [-0.3, 0.3])

    Returns:
        numpy array with horizontal shear applied
    """
    transform = A.Affine(shear={"x": (v * 45, v * 45), "y": (0, 0)}, border_mode=0, p=1.0)
    return transform(image=img)["image"]

ShearY(img, v)

Apply vertical shear to the image.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Shear factor (range [-0.3, 0.3])

required

Returns:

Type Description
ndarray

numpy array with vertical shear applied

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def ShearY(img: np.ndarray, v: float) -> np.ndarray:
    """Apply vertical shear to the image.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Shear factor (range [-0.3, 0.3])

    Returns:
        numpy array with vertical shear applied
    """
    transform = A.Affine(shear={"x": (0, 0), "y": (v * 45, v * 45)}, border_mode=0, p=1.0)
    return transform(image=img)["image"]

TranslateX(img, v)

Translate the image horizontally by a percentage of its width.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Translation factor as a percentage of image width (range [-0.3, 0.3])

required

Returns:

Type Description
ndarray

numpy array with horizontal translation applied

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def TranslateX(img: np.ndarray, v: float) -> np.ndarray:
    """Translate the image horizontally by a percentage of its width.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Translation factor as a percentage of image width (range [-0.3, 0.3])

    Returns:
        numpy array with horizontal translation applied
    """
    transform = A.Affine(translate_percent={"x": (v, v), "y": (0, 0)}, border_mode=0, p=1.0)
    return transform(image=img)["image"]

TranslateY(img, v)

Translate the image vertically by a percentage of its height.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Translation factor as a percentage of image height (range [-0.3, 0.3])

required

Returns:

Type Description
ndarray

numpy array with vertical translation applied

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def TranslateY(img: np.ndarray, v: float) -> np.ndarray:
    """Translate the image vertically by a percentage of its height.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Translation factor as a percentage of image height (range [-0.3, 0.3])

    Returns:
        numpy array with vertical translation applied
    """
    transform = A.Affine(translate_percent={"x": (0, 0), "y": (v, v)}, border_mode=0, p=1.0)
    return transform(image=img)["image"]

Solarize(img, v)

Invert all pixel values above a threshold.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Threshold for solarization (range [0, 256])

required

Returns:

Type Description
ndarray

Solarized numpy array

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def Solarize(img: np.ndarray, v: float) -> np.ndarray:
    """Invert all pixel values above a threshold.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Threshold for solarization (range [0, 256])

    Returns:
        Solarized numpy array
    """
    v = int(v)
    return np.where(img >= v, 255 - img, img).astype(np.uint8)

Cutout(img, v, num_channels=None)

Apply cutout augmentation to the image.

Creates a square mask at a random location in the image.

Parameters:

Name Type Description Default
img ndarray

numpy array (H, W, C) to be processed

required
v float

Size of the cutout as a percentage of image size (range [0.0, 0.5])

required
num_channels int | None

Number of channels (inferred from img if not provided)

None

Returns:

Type Description
ndarray

numpy array with cutout applied

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def Cutout(img: np.ndarray, v: float, num_channels: int | None = None) -> np.ndarray:
    """Apply cutout augmentation to the image.

    Creates a square mask at a random location in the image.

    Args:
        img: numpy array (H, W, C) to be processed
        v: Size of the cutout as a percentage of image size (range [0.0, 0.5])
        num_channels: Number of channels (inferred from img if not provided)

    Returns:
        numpy array with cutout applied
    """
    if v <= 0.0:
        return img

    h, w = img.shape[:2]
    if num_channels is None:
        num_channels = img.shape[2] if len(img.shape) > 2 else 1

    cutout_size = int(v * min(h, w))
    if cutout_size <= 0:
        return img

    # Random position for cutout
    x0 = np.random.randint(0, max(1, w - cutout_size + 1))
    y0 = np.random.randint(0, max(1, h - cutout_size + 1))

    # Apply cutout with gray fill (128 for all channels)
    img_out = img.copy()
    img_out[y0 : y0 + cutout_size, x0 : x0 + cutout_size, :] = 128

    return img_out

multispectral_augment_list()

Return a list of available augmentation operations with their value ranges.

These operations work with arbitrary channel counts, excluding PIL-dependent operations (AutoContrast, Brightness, Color, Contrast, Equalize) that assume RGB.

Returns:

Type Description
list[tuple]

List of tuples (operation, min_value, max_value) for each augmentation

Source code in anomaly_match/datasets/augmentation/randaugment_multispectral.py
def multispectral_augment_list() -> list[tuple]:
    """Return a list of available augmentation operations with their value ranges.

    These operations work with arbitrary channel counts, excluding PIL-dependent
    operations (AutoContrast, Brightness, Color, Contrast, Equalize) that assume RGB.

    Returns:
        List of tuples (operation, min_value, max_value) for each augmentation
    """
    return [
        (Identity, 0, 1),
        (Posterize, 4, 8),
        (Rotate, -30, 30),
        (Sharpness, 0.05, 0.95),
        (ShearX, -0.3, 0.3),
        (ShearY, -0.3, 0.3),
        (Solarize, 0, 256),
        (TranslateX, -0.3, 0.3),
        (TranslateY, -0.3, 0.3),
    ]