Multiresolution Registration with 2D Affine Transformation on pairs of 2D images

Hello @ScottP,

Welcome to SimpleITK/Python/registration, tackling all at once is not going to be easy. We’ll try to make it manageable.

First, to debug a registration you need to visualize the images after each step. This will give you an idea if you have a bug. Second the Too many samples map outside moving image buffer exception is indeed indicating that the images no longer overlap, as you suspected the initial alignment is off. In your code this is a combination of two transforms (initial_transform, optimized_transform) you also need to combine the two after the registration, your code doesn’t do that (see Version 1.1 in this notebook).

Let’s simplify, start with a basic 2D/2D affine registration example. To run the following code as is you will need to obtain the two images photo.dcm and cxr.dcm.

Once you understand how this code works, you should be able to generalize it for your case, or ask a specific question (one question at a time please :wink:):

import SimpleITK as sitk

def multires_registration(fixed_image, moving_image, initial_transform):    
    registration_method = sitk.ImageRegistrationMethod()
    registration_method.SetInterpolator(sitk.sitkLinear)
    registration_method.SetMetricAsMattesMutualInformation(numberOfHistogramBins=50)
    registration_method.SetMetricSamplingStrategy(registration_method.RANDOM)
    registration_method.SetMetricSamplingPercentage(0.01)
    registration_method.SetOptimizerAsGradientDescent(learningRate=1.0, numberOfIterations=100, convergenceMinimumValue=1e-6, convergenceWindowSize=10)
    registration_method.SetOptimizerScalesFromPhysicalShift() 
    registration_method.SetInitialTransform(initial_transform, inPlace=True)
    registration_method.SetShrinkFactorsPerLevel(shrinkFactors = [4,2,1])
    registration_method.SetSmoothingSigmasPerLevel(smoothingSigmas = [2,1,0])
    registration_method.SmoothingSigmasAreSpecifiedInPhysicalUnitsOn()

    registration_method.Execute(fixed_image, moving_image)
    
    print('Final metric value: {0}'.format(registration_method.GetMetricValue()))
    print('Optimizer\'s stopping condition, {0}'.format(registration_method.GetOptimizerStopConditionDescription()))
    
# Read the images and modify so that they are 2D, the original size is [x,y,1] and we want [x,y].
fixed_image = sitk.ReadImage('cxr.dcm', sitk.sitkFloat32)[:,:,0]
moving_image = sitk.ReadImage('photo.dcm', sitk.sitkFloat32)[:,:,0]

# Display the original images and resamples moving_image (onto the
# fixed_image grid using the identity transformation)
sitk.Show(fixed_image, 'fixed')
sitk.Show(moving_image, 'moving')
sitk.Show(sitk.Resample(moving_image, fixed_image, sitk.Transform()), 'identity transform')

# Centered 2D affine transform and show the resampled moving_image using this transform.
registration_transform = sitk.CenteredTransformInitializer(fixed_image, 
                                                      moving_image, 
                                                      sitk.AffineTransform(2), 
                                                      sitk.CenteredTransformInitializerFilter.GEOMETRY)
sitk.Show(sitk.Resample(moving_image, fixed_image, registration_transform), 'initial affine transform')


# Register using 2D affine initial transform that is overwritten
# and show the resampled moving_image using this transform.
multires_registration(fixed_image, moving_image, registration_transform)
sitk.Show(sitk.Resample(moving_image, fixed_image, registration_transform), 'final affine transform')
2 Likes