Fast 2D-2D image registration

Hello, I am using simpleitk to register chest x rays of size 512x512. An affine registration produces a decent result and takes about 2 min on my machine. A further free-form deformation based non rigid registration takes another minute. I am looking to register a larger population which will require 15k pair-wise registrations. Are there any GPU/parallel implementations available via simpleitk that I can use to speed up the registrations, even if only using affine transforms? Any suggestions will be helpful.
Thanks

Hello @tanres,

2min for 2D affine registration sounds a bit long, can you share the code?

With respect to parallelism, that is not specific to simpleitk, you can use the standard Python multiprocessing to run multiple registrations at the same time.

1 Like

Thanks for your reply Yaniv. The code below is based on the examples:

fixed_image = sitk.GetImageFromArray(fixed_arr)
moving_image = sitk.GetImageFromArray(moving_arr)
transform = sitk.AffineTransform(2) if use_affine else sitk.ScaleTransform(2)
initial_transform = sitk.CenteredTransformInitializer(sitk.Cast(fixed_image, moving_image.GetPixelID()),
                                                      moving_image,
                                                      transform,
                                                      sitk.CenteredTransformInitializerFilter.GEOMETRY)
ff_img = sitk.Cast(fixed_image, sitk.sitkFloat32)
mv_img = sitk.Cast(moving_image, sitk.sitkFloat32)
registration_method = sitk.ImageRegistrationMethod()

registration_method.SetMetricAsMeanSquares()

sample_per_axis = 12
registration_method.SetOptimizerAsExhaustive([sample_per_axis // 2, 0, 0])
registration_method.SetOptimizerScales([2.0 * 3.14 / sample_per_axis, 1.0, 1.0])

registration_method.SetInterpolator(sitk.sitkLinear)

registration_method.SetOptimizerAsGradientDescent(learningRate=1.0,
                                                  numberOfIterations=200,
                                                  convergenceMinimumValue=1e-6,
                                                  convergenceWindowSize=10)

registration_method.SetOptimizerScalesFromPhysicalShift()

registration_method.SetInitialTransform(initial_transform, inPlace=False)
final_transform_v1 = registration_method.Execute(ff_img,
                                                 mv_img)

resample = sitk.ResampleImageFilter()
resample.SetReferenceImage(fixed_image)

resample.SetInterpolator(sitk.sitkBSpline)
resample.SetTransform(final_transform_v1)
resample.Execute(moving_image)

Hello @tanres,

Thanks for sharing your code. There seems to be some issue here, as there are several rows that don’t actually contribute to the work:

sample_per_axis = 12
registration_method.SetOptimizerAsExhaustive([sample_per_axis // 2, 0, 0])
registration_method.SetOptimizerScales([2.0 * 3.14 / sample_per_axis, 1.0, 1.0])

These settings are then overridden with new settings:

registration_method.SetOptimizerAsGradientDescent(learningRate=1.0,
                                                  numberOfIterations=200,
                                                  convergenceMinimumValue=1e-6,
                                                  convergenceWindowSize=10)

registration_method.SetOptimizerScalesFromPhysicalShift()

So in practice the optimizer is gradient descent and scales are automatically estimated. The setup for the exhaustive optimizer is not used. Not sure what is your intent, but given that it works you can just remove the lines that don’t do anything.

With respect to runtime, I looked at the size of a couple of x-rays and these are pretty large 5Kx4K. You did not call the registration_method.SetMetricSamplingPercentage() so likely you are using the default sampling which results in slower runtimes than necessary. You can tune this parameter to your data so that you find the smallest sampling rate that converges for your data. You can also try the multi-resolution framework.

For the reduced sampling rate, just add:

registration_method.SetMetricSamplingPercentage(0.001)
registration_method.SetMetricSamplingStrategy(registration_method.RANDOM)
1 Like