Image Registration Developer Guide
PhysioTwin4D image registration classes register a moving ITK image to a fixed ITK image.
Basic Pattern
import itk
from physiotwin4d 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 forward_transform, inverse_transform,
and loss. Applying the right one is critical and direction-dependent:
forward_transform warps the moving image onto the fixed grid, while
inverse_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 physiotwin4d 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
forward_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 physiotwin4d import RegisterImagesChain, RegisterImagesGreedy, RegisterImagesICON
# Arbitrary N-stage chain
registrar = RegisterImagesChain([RegisterImagesGreedy(), RegisterImagesICON()])
# Or, for the common Greedy-then-ICON case:
from physiotwin4d 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_forward_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
TransformTools.transform_image()for resampling images.Use
TransformTools.transform_pvcontour()for PyVista contours.