Skip to content

Pad

Pad

Bases: SpatialTransform

Add a border of voxels to each side of the volume.

Parameters:

Name Type Description Default
padding PaddingParam

Tuple \((i_\text{ini}, i_\text{fin}, j_\text{ini}, j_\text{fin}, k_\text{ini}, k_\text{fin})\) defining the number of voxels added to the edges of each axis. If the initial shape of the image is \(I \times J \times K\), the final shape will be \((I + i_\text{ini} + i_\text{fin}) \times (J + j_\text{ini} + j_\text{fin}) \times (K + k_\text{ini} + k_\text{fin})\). If only three values \((i, j, k)\) are provided, then \(i_\text{ini} = i_\text{fin} = i\), etc. If only one value \(n\) is provided, all six values are \(n\).

required
padding_mode str

One of 'constant', 'reflect', 'replicate', or 'circular'. See torch.nn.functional.pad.

'constant'
fill float

Fill value when padding_mode='constant'.

0
**kwargs Any

See Transform for additional keyword arguments.

{}

Examples:

>>> import torchio as tio
>>> transform = tio.Pad(padding=10)
>>> transform = tio.Pad(padding=(5, 10, 0))
>>> transform = tio.Pad(padding=10, padding_mode='reflect')
Source code in src/torchio/transforms/spatial/pad.py
class Pad(SpatialTransform):
    r"""Add a border of voxels to each side of the volume.

    Args:
        padding: Tuple
            $(i_\text{ini}, i_\text{fin}, j_\text{ini}, j_\text{fin},
            k_\text{ini}, k_\text{fin})$
            defining the number of voxels added to the edges of
            each axis. If the initial shape of the image is
            $I \times J \times K$, the final shape will be
            $(I + i_\text{ini} + i_\text{fin}) \times
            (J + j_\text{ini} + j_\text{fin}) \times
            (K + k_\text{ini} + k_\text{fin})$.
            If only three values $(i, j, k)$ are provided, then
            $i_\text{ini} = i_\text{fin} = i$, etc.
            If only one value $n$ is provided, all six values are $n$.
        padding_mode: One of `'constant'`, `'reflect'`,
            `'replicate'`, or `'circular'`. See
            [`torch.nn.functional.pad`](https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html).
        fill: Fill value when `padding_mode='constant'`.
        **kwargs: See [`Transform`][torchio.Transform] for additional
            keyword arguments.

    Examples:
        >>> import torchio as tio
        >>> transform = tio.Pad(padding=10)
        >>> transform = tio.Pad(padding=(5, 10, 0))
        >>> transform = tio.Pad(padding=10, padding_mode='reflect')
    """

    def __init__(
        self,
        *,
        padding: PaddingParam,
        padding_mode: str = "constant",
        fill: float = 0,
        **kwargs: Any,
    ) -> None:
        super().__init__(**kwargs)
        self.padding = _parse_padding(padding)
        self.padding_mode = padding_mode
        self.fill = fill

    def make_params(self, batch: SubjectsBatch) -> dict[str, Any]:
        return {
            "padding": self.padding,
            "padding_mode": self.padding_mode,
            "fill": self.fill,
        }

    def apply_transform(
        self,
        batch: SubjectsBatch,
        params: dict[str, Any],
    ) -> SubjectsBatch:
        i0, i1, j0, j1, k0, k1 = params["padding"]
        mode = params["padding_mode"]
        fill = params["fill"]
        # F.pad expects reversed order: (k0, k1, j0, j1, i0, i1)
        pad_arg = (k0, k1, j0, j1, i0, i1)
        for _name, img_batch in self._get_images(batch).items():
            img_batch.data = torch.nn.functional.pad(
                img_batch.data,
                pad_arg,
                mode=mode,
                value=fill,
            )
            # Update each affine's origin (shift back)
            for affine in img_batch.affines:
                origin_shift = affine.data[:3, :3] @ affine.data.new_tensor(
                    [-float(i0), -float(j0), -float(k0)],
                )
                affine._matrix[:3, 3] += origin_shift
        return batch

    @property
    def invertible(self) -> bool:
        return True

    def inverse(self, params: dict[str, Any]) -> Any:
        """Inverse of Pad is Crop."""
        from .crop import Crop

        return Crop(cropping=params["padding"], copy=False)

supports_per_instance_params property

Whether this transform can sample parameters per batch element.

Defaults to False. Transforms that implement per-instance parameter sampling override this to return True. When False, the transform always uses batch-shared parameters regardless of the per_instance flag, preserving the legacy behavior.

supports_per_instance_p property

Whether this transform can gate each batch element independently.

Defaults to False. Shape-preserving transforms that implement per-element probability override this to return True. Shape-changing transforms must leave it False because masked and unmasked elements would have incompatible shapes.

forward(data)

forward(data: Subject) -> Subject
forward(data: Image) -> Image
forward(data: Tensor) -> Tensor
forward(data: np.ndarray) -> np.ndarray
forward(data: sitk.Image) -> sitk.Image
forward(data: nib.Nifti1Image) -> nib.Nifti1Image
forward(data: dict) -> dict
forward(data: ImagesBatch) -> ImagesBatch
forward(data: SubjectsBatch) -> SubjectsBatch

Apply the transform.

The output type always matches the input type.

Parameters:

Name Type Description Default
data Any

Input data to transform.

required
Source code in src/torchio/transforms/transform.py
def forward(self, data: Any) -> Any:
    """Apply the transform.

    The output type always matches the input type.

    Args:
        data: Input data to transform.
    """
    if self.copy:
        data = _copy.deepcopy(data)
    batch, unwrap = self._wrap(data)
    # When per-element gating is active, the transform handles the
    # probability itself (masked-out elements get identity params),
    # so skip the batch-wide coin flip here. Apply iff rand < p, so
    # p=0 is always a no-op and p=1 always applies.
    if not self._per_instance_p_active(batch) and torch.rand(1).item() >= self.p:
        return unwrap(batch)
    params = self.make_params(batch)
    batch = self.apply_transform(batch, params)
    # Record history on the batch, unless every element was gated out by
    # per-element probability: that is an exact no-op, and recording it
    # would let history replay (e.g. an invertible spatial transform)
    # trigger an unnecessary identity resample.
    if not _all_elements_gated_out(params):
        trace = AppliedTransform(name=type(self).__name__, params=params)
        if not hasattr(batch, "applied_transforms"):
            batch.applied_transforms = []
        batch.applied_transforms.append(trace)
    result = unwrap(batch)
    # Propagate history to outputs that can carry it
    if (
        hasattr(batch, "applied_transforms")
        and not isinstance(result, (SubjectsBatch, Tensor, np.ndarray))
        and not isinstance(result, dict)
    ):
        with contextlib.suppress(AttributeError):
            result.applied_transforms = list(batch.applied_transforms)
    return result

to_hydra()

Export as a Hydra-compatible config dict.

Returns a dict with _target_ set to the fully qualified class name and only non-default field values included.

Returns:

Type Description
dict[str, Any]

Dict suitable for hydra.utils.instantiate().

Source code in src/torchio/transforms/transform.py
def to_hydra(self) -> dict[str, Any]:
    """Export as a Hydra-compatible config dict.

    Returns a dict with `_target_` set to the fully qualified
    class name and only non-default field values included.

    Returns:
        Dict suitable for `hydra.utils.instantiate()`.
    """
    from .parameter_range import _ParameterRange

    cls = type(self)
    target = f"torchio.{cls.__qualname__}"
    cfg: dict[str, Any] = {"_target_": target}

    for name, default in _collect_init_params(cls).items():
        value = getattr(self, name, default)
        if isinstance(value, _ParameterRange):
            if value._original == default:
                continue
            value = _hydra_value(value._original)
        elif value == default:
            continue
        else:
            value = _hydra_value(value)
        cfg[name] = value
    return cfg

inverse(params)

Inverse of Pad is Crop.

Source code in src/torchio/transforms/spatial/pad.py
def inverse(self, params: dict[str, Any]) -> Any:
    """Inverse of Pad is Crop."""
    from .crop import Crop

    return Crop(cropping=params["padding"], copy=False)