Time-Series Registration
RegisterTimeSeriesImages registers ordered 3D image phases to a reference
frame using ANTs, ICON, or the combined ants_icon method.
Class Reference
- class physiomotion4d.RegisterTimeSeriesImages(registration_method='ants', log_level=20)[source]
Bases:
RegisterImagesBaseRegister a time series of images to a fixed image.
This class extends RegisterImagesBase to provide sequential registration of multiple images (time series) to a fixed image. It supports both ANTs and ICON registration methods and can propagate information from prior registrations to initialize subsequent ones.
The registration proceeds in two passes from a reference frame: 1. Forward pass: from reference_frame to the end of the series 2. Backward pass: from reference_frame-1 to the beginning
This bidirectional approach helps maintain temporal coherence in the registration results.
Key features: - Sequential registration of ordered image lists - Support for both ANTs and ICON registration backends - Optional use of prior transforms to initialize next registration - Configurable starting point in the time series - Returns all transforms and loss values for the entire series
- registrar
Internal registration object (ANTs or ICON)
- Type:
- transform_tools
Utility for transform operations
- Type:
Example
>>> # Register a cardiac CT time series >>> registrar = RegisterTimeSeriesImages(registration_method='ants') >>> registrar.set_modality('ct') >>> registrar.set_fixed_image(fixed_image) >>> registrar.set_number_of_iterations_ants([40, 20, 10]) >>> >>> # Register all time points to fixed image >>> result = registrar.register_time_series( ... moving_images=time_series_images, ... reference_frame=5, # Start from middle of cardiac cycle ... register_reference=True, ... prior_weight=0.5, ... ) >>> >>> forward_tfms = result['forward_transforms'] # Moving → Fixed >>> inverse_tfms = result['inverse_transforms'] # Fixed → Moving >>> losses = result['losses'] >>> >>> # Reconstruct time series with optional upsampling >>> reconstructed = registrar.reconstruct_time_series( ... moving_images=time_series_images, ... inverse_transforms=inverse_tfms, ... upsample_to_fixed_resolution=True, ... )
- __init__(registration_method='ants', log_level=20)[source]
Initialize the time series image registration class.
- Parameters:
- Raises:
ValueError – If registration_method is not ‘ants’ or ‘icon’
- set_number_of_iterations_ants(number_of_iterations_ants)[source]
Set the number of iterations for ANTs registration.
- set_number_of_iterations_icon(number_of_iterations_icon)[source]
Set the number of iterations for ICON registration.
- set_smooth_prior_transform_sigma(smooth_prior_transform_sigma)[source]
Set the sigma for smoothing the prior transform.
- set_mask_dilation(mask_dilation_mm)[source]
Set the dilation of the fixed and moving image masks.
This passes through to the underlying registration method.
- set_modality(modality)[source]
Set the imaging modality for registration optimization.
This passes through to the underlying registration method.
- set_fixed_image(fixed_image)[source]
Set the fixed image for registration.
All moving images in the time series will be registered to this fixed image.
- Parameters:
fixed_image (itk.Image) – The 3D fixed image
- Return type:
- set_fixed_mask(fixed_mask)[source]
Set a binary mask for the fixed image region of interest.
This passes through to the underlying registration method.
- Parameters:
fixed_mask (itk.Image) – Binary mask defining ROI
- Return type:
- register_time_series(moving_images, moving_masks=None, moving_labelmaps=None, reference_frame=0, register_reference=True, prior_weight=0.0)[source]
Register a time series of images to the fixed image.
This method registers an ordered sequence of images to a common fixed frame. Registration proceeds bidirectionally from a reference frame: forward to the end and backward to the beginning.
For each image after the reference image, the method can optionally use the transform from the previous image to initialize the registration, which can improve convergence and temporal coherence.
- Parameters:
moving_images (list[itk.Image]) – List of 3D images to register
moving_masks (list[itk.Image], optional) – List of binary masks, one for each moving image. If None, no masks are used. If provided, must have the same length as moving_images. Default: None
moving_labelmaps (list[itk.Image], optional) – Per-frame multi-label segmentations, one for each moving image. If None, no labelmaps are used. If provided, must have the same length as moving_images. Default: None
reference_frame (int, optional) – Index of the reference image to register first. Registration proceeds forward from this index to the end, then backward from this index to the beginning. Default: 0
register_reference (bool, optional) – If True, register the reference image to the fixed image. If False, use identity transform for the reference image. Default: True
prior_weight (float, optional) – Weight (0.0 to 1.0) for using the prior image’s transform to initialize the next registration. 0.0 means no prior information is used (each registration starts from identity). Higher values provide more temporal smoothness but may propagate errors. Default: 0.0
- Returns:
- Dictionary containing results:
”forward_transforms” (list[itk.Transform]): Transforms from moving to fixed space for each image (warps moving → fixed)
”inverse_transforms” (list[itk.Transform]): Transforms from fixed to moving space for each image (warps fixed → moving)
”losses” (list[float]): Registration loss value for each image
- Return type:
- Raises:
ValueError – If fixed_image is not set
ValueError – If reference_frame is out of range
ValueError – If prior_weight not in [0, 1]
ValueError – If moving_masks length doesn’t match moving_images length
Note
The method compares registration with identity initialization versus prior transform initialization and selects the result with lower loss. This helps prevent error propagation in the temporal sequence.
The fixed image mask can be set using set_fixed_mask() before calling this method.
Example
>>> registrar = RegisterTimeSeriesImages(registration_method='ants') >>> registrar.set_fixed_image(fixed_image) >>> registrar.set_fixed_mask(fixed_mask) # Optional >>> registrar.set_number_of_iterations_ants([30, 15, 5]) >>> >>> # Use new intuitive parameter names >>> result = registrar.register_time_series( ... moving_images=image_list, ... moving_masks=mask_list, # Optional ... reference_frame=5, ... register_reference=True, ... prior_weight=0.5, ... ) >>> >>> # Access results using new intuitive names >>> for i, (forward_tfm, loss) in enumerate( ... zip(result['forward_transforms'], result['losses']) ... ): ... # Apply forward transform to align moving image i to fixed ... registered = transform_tools.transform_image( ... moving_images[i], forward_tfm, fixed_image ... )
- reconstruct_time_series(moving_images, inverse_transforms, upsample_to_fixed_resolution=False)[source]
Reconstruct time series images using inverse transforms.
This method applies the inverse transforms to reconstruct each moving image in the fixed image space. If upsample_to_fixed_resolution is enabled, the reconstructed images will use isotropic spacing (mean of fixed image’s X and Y spacing) while maintaining each moving image’s original origin and direction.
- Parameters:
moving_images (list[itk.Image]) – List of moving images to reconstruct
inverse_transforms (list[itk.Transform]) – List of inverse transforms (one per moving image) from fixed space to moving space
upsample_to_fixed_resolution (bool, optional) – If True, reconstructed images will be upsampled to isotropic resolution (mean of fixed image’s X and Y spacing) while maintaining their original origin and direction. Default: False
- Returns:
List of reconstructed images in fixed image space
- Return type:
list[itk.Image]
- Raises:
ValueError – If fixed_image is not set
ValueError – If lengths of moving_images and inverse_transforms don’t match
Example
>>> registrar = RegisterTimeSeriesImages(registration_method='ants') >>> registrar.set_fixed_image(fixed_image) >>> >>> result = registrar.register_time_series( ... moving_images=time_series_images, ... reference_frame=0, ... ) >>> >>> reconstructed_images = registrar.reconstruct_time_series( ... moving_images=time_series_images, ... inverse_transforms=result['inverse_transforms'], ... upsample_to_fixed_resolution=True, ... )
Basic Usage
import itk
from physiomotion4d import RegisterTimeSeriesImages
images = [itk.imread(f"phase_{idx:02d}.mha") for idx in range(10)]
registrar = RegisterTimeSeriesImages(registration_method="ants")
registrar.set_fixed_image(images[0])
result = registrar.register_time_series(
moving_images=images,
reference_frame=0,
register_reference=False,
)
forward_transforms = result["forward_transforms"]
inverse_transforms = result["inverse_transforms"]