Skip to content

Flip

Bases: SpatialTransform

Reverse the order of elements in an image along the given axes.

Parameters:

Name Type Description Default
axes int | str | Sequence[int | str]

Index or tuple of indices of the spatial dimensions along which the image might be flipped. Integers must be in {0, 1, 2}. Anatomical labels may also be used, such as 'Left', 'Right', 'Anterior', 'Posterior', 'Inferior', 'Superior'. Only the first letter of the string is used. Anatomical labels are resolved using the image orientation.

0
flip_probability float

Probability that each axis will be flipped (per-axis coin flip). This is independent of the p parameter, which gates the entire transform.

1.0
**kwargs Any

See Transform for additional keyword arguments.

{}
Tip

Specifying the axes as anatomical labels is useful when the image orientation is not known.

Examples:

>>> import torchio as tio
>>> # Flip along the first spatial axis
>>> transform = tio.Flip(axes=0)
>>> # Flip along the lateral axis (anatomical label)
>>> transform = tio.Flip(axes='LR')
>>> # Random per-axis flip with 50% chance each
>>> transform = tio.Flip(axes=(0, 1, 2), flip_probability=0.5)
Source code in src/torchio/transforms/spatial/flip.py
class Flip(SpatialTransform):
    r"""Reverse the order of elements in an image along the given axes.

    Args:
        axes: Index or tuple of indices of the spatial dimensions along
            which the image might be flipped. Integers must be in
            `{0, 1, 2}`. Anatomical labels may also be used, such as
            `'Left'`, `'Right'`, `'Anterior'`, `'Posterior'`,
            `'Inferior'`, `'Superior'`. Only the first letter of
            the string is used. Anatomical labels are resolved using
            the image orientation.
        flip_probability: Probability that each axis will be flipped
            (per-axis coin flip). This is independent of the `p`
            parameter, which gates the entire transform.
        **kwargs: See [`Transform`][torchio.Transform] for additional
            keyword arguments.

    Tip:
        Specifying the axes as anatomical labels is useful when the
        image orientation is not known.

    Examples:
        >>> import torchio as tio
        >>> # Flip along the first spatial axis
        >>> transform = tio.Flip(axes=0)
        >>> # Flip along the lateral axis (anatomical label)
        >>> transform = tio.Flip(axes='LR')
        >>> # Random per-axis flip with 50% chance each
        >>> transform = tio.Flip(axes=(0, 1, 2), flip_probability=0.5)
    """

    def __init__(
        self,
        *,
        axes: int | str | Sequence[int | str] = 0,
        flip_probability: float = 1.0,
        **kwargs: Any,
    ) -> None:
        super().__init__(**kwargs)
        self.axes = axes
        if not 0 <= flip_probability <= 1:
            msg = f"flip_probability must be in [0, 1], got {flip_probability}"
            raise ValueError(msg)
        self.flip_probability = flip_probability

    def make_params(
        self,
        batch: SubjectsBatch,
    ) -> dict[str, Any]:
        # Resolve string axes using the first image's orientation
        orientation = None
        first_img = next(iter(batch.images.values()))
        if first_img.batch_size > 0:
            img = first_img[0]
            orientation = img.orientation
        resolved = _resolve_axes(self.axes, orientation)

        # Per-axis coin flip
        flip_mask = torch.rand(3) < self.flip_probability
        axes_to_flip = tuple(a for a in resolved if flip_mask[a].item())
        return {"axes": axes_to_flip}

    def apply_transform(
        self,
        batch: SubjectsBatch,
        params: dict[str, Any],
    ) -> SubjectsBatch:
        axes = params["axes"]
        if not axes:
            return batch
        dims = [a - 3 for a in axes]
        for _name, img_batch in self._get_images(batch).items():
            img_batch.data = torch.flip(img_batch.data, dims)
        return batch

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

    def inverse(self, params: dict[str, Any]) -> Flip:
        """Flip is its own inverse."""
        return Flip(axes=params["axes"], copy=False)

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)
    if 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
    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)

Flip is its own inverse.

Source code in src/torchio/transforms/spatial/flip.py
def inverse(self, params: dict[str, Any]) -> Flip:
    """Flip is its own inverse."""
    return Flip(axes=params["axes"], copy=False)