Image Registration Developer Guide

MONAI Physio image registration classes register a moving ITK image to a fixed ITK image.

Basic Pattern

import itk

from monai_physio import RegisterImagesANTS

fixed = itk.imread("fixed.mha")
moving = itk.imread("moving.mha")

registrar = RegisterImagesANTS()
registrar.set_modality("ct")
registrar.set_fixed_image(fixed)

result = registrar.register(moving)
registered = registrar.get_registered_image()

The result dictionary contains fixed_to_moving_transform, moving_to_fixed_transform, and loss. Applying the right one is critical and direction-dependent: fixed_to_moving_transform warps the moving image onto the fixed grid, while moving_to_fixed_transform warps moving points/landmarks into fixed space (image and point warps use opposite transforms). See Transform Direction Conventions for the full rules.

Time Series

import itk

from monai_physio import RegisterImagesGreedy, RegisterTimeSeriesImages

images = [itk.imread(f"phase_{idx:02d}.mha") for idx in range(10)]

registrar = RegisterTimeSeriesImages(registration_method=RegisterImagesGreedy())
registrar.set_fixed_image(images[0])
result = registrar.register_time_series(
    moving_images=images,
    reference_frame=0,
    register_reference=False,
)

Combining Registrars

Workflows that accept a registration_method (e.g. WorkflowConvertImageToUSD, RegisterTimeSeriesImages) take any RegisterImagesBase instance, including a composite chain that runs multiple backends in sequence. RegisterImagesChain runs an ordered list of registrars, each stage refining the previous stage’s fixed_to_moving_transform through register_from() (see Seeding a registration below). RegisterImagesGreedyICON is a named 2-stage convenience class for the common case of a fast Greedy registration followed by ICON refinement:

from monai_physio import RegisterImagesChain, RegisterImagesGreedy, RegisterImagesICON

# Arbitrary N-stage chain
registrar = RegisterImagesChain([RegisterImagesGreedy(), RegisterImagesICON()])

# Or, for the common Greedy-then-ICON case:
from monai_physio import RegisterImagesGreedyICON

registrar = RegisterImagesGreedyICON()
registrar.greedy.set_number_of_iterations([30, 15, 7, 3])
registrar.icon.set_number_of_iterations(20)

Seeding a registration

To start from an alignment you already have, call register_from() instead of register():

result = registrar.register_from(known_fixed_to_moving_transform, moving_image)

It warps the moving image, mask and labelmap onto the fixed grid by that transform, registers the residual, and composes the two, so the returned transforms still map between the original moving image and the fixed image. Every backend goes through this one implementation – no registrar accepts an initial transform of its own, which is what keeps the pre-warp, the composition and the inversion identical for Greedy, ICON and ANTs.

Development Notes

  • Use masks when registration should focus on a specific anatomy.

  • Check transform direction before applying transforms to contours or images.

  • Use ProcessTransforms.transform_image() for resampling images.

  • Use ProcessTransforms.transform_pvcontour() for PyVista contours.

See Also