CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-simpleitk

SimpleITK is a simplified interface to the Insight Toolkit (ITK) for image registration and segmentation

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

registration-workflow.mddocs/guides/

Image Registration Workflow

Complete guide to image registration workflows in SimpleITK.

Overview

Image registration aligns two images (fixed and moving) by finding an optimal geometric transformation. SimpleITK provides flexible registration through the ImageRegistrationMethod framework.

Registration Components

1. Metric

Measures similarity between fixed and moving images:

  • Mattes Mutual Information: Multi-modal registration (CT-MRI)
  • Mean Squares: Mono-modal registration (CT-CT)
  • Correlation: Similar intensity distributions
  • ANTs Neighborhood Correlation: Local similarity

2. Optimizer

Finds optimal transform parameters:

  • Gradient Descent: General purpose, requires learning rate tuning
  • L-BFGS-B: Limited memory, good for many parameters
  • Powell: Derivative-free, slower but robust
  • Amoeba: Simplex method, no derivatives needed

3. Transform

Geometric transformation type:

  • Translation: 2-3 parameters
  • Rigid (Euler): 6 parameters (3D)
  • Similarity: 7 parameters (rigid + uniform scale)
  • Affine: 12 parameters (general linear)
  • B-Spline: Deformable, many parameters

4. Interpolator

Resamples moving image:

  • Linear: Fast, good quality
  • Nearest Neighbor: For label images
  • B-Spline: Higher quality, slower

Basic Rigid Registration

import SimpleITK as sitk

def rigid_registration(fixed_image, moving_image):
    """Perform rigid (6 DOF) registration."""
    
    # Initialize transform at image centers
    initial_transform = sitk.CenteredTransformInitializer(
        fixed_image,
        moving_image,
        sitk.Euler3DTransform(),
        sitk.CenteredTransformInitializerFilter.GEOMETRY
    )
    
    # Setup registration
    registration = sitk.ImageRegistrationMethod()
    
    # Metric
    registration.SetMetricAsMattesMutualInformation(numberOfHistogramBins=50)
    registration.SetMetricSamplingStrategy(registration.RANDOM)
    registration.SetMetricSamplingPercentage(0.01)
    
    # Optimizer
    registration.SetOptimizerAsGradientDescent(
        learningRate=1.0,
        numberOfIterations=100,
        convergenceMinimumValue=1e-6,
        convergenceWindowSize=10
    )
    registration.SetOptimizerScalesFromPhysicalShift()
    
    # Interpolator
    registration.SetInterpolator(sitk.sitkLinear)
    
    # Initial transform
    registration.SetInitialTransform(initial_transform, inPlace=False)
    
    # Execute
    final_transform = registration.Execute(fixed_image, moving_image)
    
    print(f"Optimizer stop condition: {registration.GetOptimizerStopConditionDescription()}")
    print(f"Final metric value: {registration.GetMetricValue()}")
    
    return final_transform

Multi-Resolution Registration

def multiresolution_registration(fixed_image, moving_image):
    """Multi-resolution pyramid registration for better convergence."""
    
    initial_transform = sitk.CenteredTransformInitializer(
        fixed_image,
        moving_image,
        sitk.Euler3DTransform(),
        sitk.CenteredTransformInitializerFilter.GEOMETRY
    )
    
    registration = sitk.ImageRegistrationMethod()
    
    # Metric and optimizer
    registration.SetMetricAsMattesMutualInformation(50)
    registration.SetOptimizerAsGradientDescent(
        learningRate=1.0,
        numberOfIterations=100
    )
    registration.SetOptimizerScalesFromPhysicalShift()
    
    # Multi-resolution pyramid
    registration.SetShrinkFactorsPerLevel([4, 2, 1])
    registration.SetSmoothingSigmasPerLevel([2.0, 1.0, 0.0])
    registration.SetSmoothingSigmasAreSpecifiedInPhysicalUnits(True)
    
    registration.SetInterpolator(sitk.sitkLinear)
    registration.SetInitialTransform(initial_transform)
    
    # Monitor progress
    def iteration_callback():
        print(f"Level {registration.GetCurrentLevel()}, "
              f"Iteration {registration.GetOptimizerIteration()}, "
              f"Metric: {registration.GetMetricValue():.4f}")
    
    registration.AddCommand(sitk.sitkIterationEvent, iteration_callback)
    
    final_transform = registration.Execute(fixed_image, moving_image)
    
    return final_transform

Affine Registration

def affine_registration(fixed_image, moving_image):
    """Affine registration (12 DOF) with initialization from rigid."""
    
    # Start with rigid registration
    rigid_transform = rigid_registration(fixed_image, moving_image)
    
    # Convert to affine
    affine_transform = sitk.AffineTransform(3)
    affine_transform.SetMatrix(rigid_transform.GetMatrix())
    affine_transform.SetTranslation(rigid_transform.GetTranslation())
    affine_transform.SetCenter(rigid_transform.GetCenter())
    
    # Affine registration
    registration = sitk.ImageRegistrationMethod()
    registration.SetMetricAsMattesMutualInformation(50)
    registration.SetOptimizerAsGradientDescent(
        learningRate=1.0,
        numberOfIterations=100
    )
    registration.SetOptimizerScalesFromPhysicalShift()
    registration.SetInterpolator(sitk.sitkLinear)
    registration.SetInitialTransform(affine_transform, inPlace=True)
    
    # Multi-resolution
    registration.SetShrinkFactorsPerLevel([4, 2, 1])
    registration.SetSmoothingSigmasPerLevel([2.0, 1.0, 0.0])
    registration.SetSmoothingSigmasAreSpecifiedInPhysicalUnits(True)
    
    final_transform = registration.Execute(fixed_image, moving_image)
    
    return final_transform

Deformable Registration

Demons Algorithm

def demons_registration(fixed_image, moving_image, initial_transform=None):
    """Deformable registration using demons algorithm."""
    
    # Apply initial transform if provided
    if initial_transform:
        moving_image = sitk.Resample(
            moving_image,
            fixed_image,
            initial_transform,
            sitk.sitkLinear,
            0.0,
            moving_image.GetPixelID()
        )
    
    # Demons registration
    demons = sitk.DemonsRegistrationFilter()
    demons.SetNumberOfIterations(50)
    demons.SetStandardDeviations(1.0)
    
    displacement_field = demons.Execute(fixed_image, moving_image)
    
    # Create displacement field transform
    transform = sitk.DisplacementFieldTransform(3)
    transform.SetDisplacementField(displacement_field)
    
    return transform

B-Spline Registration

def bspline_registration(fixed_image, moving_image, initial_transform=None):
    """B-spline deformable registration."""
    
    # Apply initial transform if provided
    if initial_transform:
        moving_image = sitk.Resample(
            moving_image,
            fixed_image,
            initial_transform,
            sitk.sitkLinear,
            0.0,
            moving_image.GetPixelID()
        )
    
    # Create B-spline transform
    transform_domain = fixed_image
    bspline = sitk.BSplineTransform(transform_domain, 3)
    bspline.SetTransformDomainMeshSize((8, 8, 8))
    
    # Initialize with no deformation
    params = [0.0] * bspline.GetNumberOfParameters()
    bspline.SetParameters(params)
    
    # Registration
    registration = sitk.ImageRegistrationMethod()
    registration.SetMetricAsMattesMutualInformation(50)
    registration.SetOptimizerAsLBFGSB(
        gradientConvergenceTolerance=1e-5,
        numberOfIterations=100
    )
    registration.SetInterpolator(sitk.sitkLinear)
    registration.SetInitialTransform(bspline, inPlace=True)
    
    final_transform = registration.Execute(fixed_image, moving_image)
    
    return final_transform

Complete Registration Pipeline

def complete_registration_pipeline(fixed_path, moving_path, output_path):
    """Complete registration pipeline: rigid -> affine -> deformable."""
    
    # Read images
    fixed = sitk.ReadImage(fixed_path, sitk.sitkFloat32)
    moving = sitk.ReadImage(moving_path, sitk.sitkFloat32)
    
    print("1. Rigid registration...")
    rigid_transform = rigid_registration(fixed, moving)
    
    print("2. Affine registration...")
    affine_transform = affine_registration(fixed, moving)
    
    print("3. Deformable registration...")
    deformable_transform = demons_registration(fixed, moving, affine_transform)
    
    # Apply final transform
    print("4. Applying final transform...")
    registered = sitk.Resample(
        moving,
        fixed,
        deformable_transform,
        sitk.sitkLinear,
        0.0,
        moving.GetPixelID()
    )
    
    # Save result
    sitk.WriteImage(registered, output_path)
    print(f"Saved registered image to {output_path}")
    
    return registered, deformable_transform

Monitoring and Debugging

Progress Tracking

def register_with_monitoring(fixed_image, moving_image):
    """Registration with detailed progress monitoring."""
    
    initial_transform = sitk.CenteredTransformInitializer(
        fixed_image,
        moving_image,
        sitk.Euler3DTransform(),
        sitk.CenteredTransformInitializerFilter.GEOMETRY
    )
    
    registration = sitk.ImageRegistrationMethod()
    registration.SetMetricAsMattesMutualInformation(50)
    registration.SetOptimizerAsGradientDescent(
        learningRate=1.0,
        numberOfIterations=100
    )
    registration.SetInterpolator(sitk.sitkLinear)
    registration.SetInitialTransform(initial_transform)
    
    # Callbacks for monitoring
    def start_callback():
        print("Registration started")
    
    def iteration_callback():
        print(f"Iteration {registration.GetOptimizerIteration()}: "
              f"Metric = {registration.GetMetricValue():.6f}, "
              f"Position = {registration.GetOptimizerPosition()}")
    
    def end_callback():
        print(f"Registration completed: {registration.GetOptimizerStopConditionDescription()}")
    
    registration.AddCommand(sitk.sitkStartEvent, start_callback)
    registration.AddCommand(sitk.sitkIterationEvent, iteration_callback)
    registration.AddCommand(sitk.sitkEndEvent, end_callback)
    
    final_transform = registration.Execute(fixed_image, moving_image)
    
    return final_transform

Saving and Loading Transforms

# Save transform
sitk.WriteTransform(final_transform, 'transform.tfm')

# Load transform
loaded_transform = sitk.ReadTransform('transform.tfm')

# Apply loaded transform
registered = sitk.Resample(moving, fixed, loaded_transform)

Quality Assessment

def assess_registration_quality(fixed, moving, transform):
    """Assess registration quality using multiple metrics."""
    
    # Apply transform
    registered = sitk.Resample(
        moving,
        fixed,
        transform,
        sitk.sitkLinear,
        0.0,
        moving.GetPixelID()
    )
    
    # Compute difference images
    difference_before = fixed - moving
    difference_after = fixed - registered
    
    # Statistics
    stats_before = sitk.StatisticsImageFilter()
    stats_before.Execute(sitk.Abs(difference_before))
    
    stats_after = sitk.StatisticsImageFilter()
    stats_after.Execute(sitk.Abs(difference_after))
    
    print(f"Mean absolute difference before: {stats_before.GetMean():.4f}")
    print(f"Mean absolute difference after: {stats_after.GetMean():.4f}")
    print(f"Improvement: {(1 - stats_after.GetMean()/stats_before.GetMean())*100:.2f}%")
    
    return registered

Common Issues and Solutions

Issue: Registration Diverges

Solution: Reduce learning rate or use multi-resolution

registration.SetOptimizerAsGradientDescent(
    learningRate=0.1,  # Reduced from 1.0
    numberOfIterations=200
)

Issue: Slow Convergence

Solution: Use sampling and multi-resolution

registration.SetMetricSamplingPercentage(0.01)  # Sample 1% of pixels
registration.SetShrinkFactorsPerLevel([8, 4, 2, 1])  # More levels

Issue: Poor Initial Alignment

Solution: Use geometric initialization

initial_transform = sitk.CenteredTransformInitializer(
    fixed_image,
    moving_image,
    sitk.Euler3DTransform(),
    sitk.CenteredTransformInitializerFilter.MOMENTS  # Use moments instead of geometry
)

See Also

  • Transform API Reference - Complete transform documentation
  • Registration Filter Reference - Registration filter details
  • Real-World Examples - Complete registration examples

Install with Tessl CLI

npx tessl i tessl/pypi-simpleitk

docs

index.md

tile.json