SimpleITK Image registration 4.13 vs 5.1

Hi message board,

I’ve got some code running in SimpleITK v4.13.1 that I would like to make compatible with SimpleITK 5.1.1. (This is old code that I’m updating to run with Ubuntu 20.0 and the default SimpleITK version that comes from the package repositories). The code is registering a 2D image (fixed) to a 3D volume (moving) with the multilevel algorithm. The size of the images is: fixed - (178, 164, 1), moving - (147, 133, 138)

Here’s the snippet:
#Create a registration method, fixed and moving are the eventual input images
registration_method = sitk.ImageRegistrationMethod()

# Set the initial transform
initial_transform = sitk.VersorRigid3DTransform()
moving_sitkTmp = fixed
initial_transform = sitk.CenteredTransformInitializer(
            fixed,
            moving_sitkTmp,
            initial_transform,
            sitk.CenteredTransformInitializerFilter.GEOMETRY
        )
registration_method.SetInitialTransform( initial_transform, inPlace=True)

#Set masks
# Recasting avoids problems which can occur for some images
registration_method.SetMetricMovingMask( sitk.Cast(moving_mask,  fixed_mask.GetPixelIDValue()) )
registration_method.SetMetricFixedMask(fixed_mask)

# Settings 
registration_method.SetInterpolator(sitk.sitkLinear)
registration_method.SetMetricAsCorrelation()
registration_method.SetOptimizerAsConjugateGradientLineSearch( learningRate = 1, numberOfIterations = 100, lineSearchUpperLimit= 2)
registration_method.SetOptimizerScalesFromJacobian()
registration_method.SetShrinkFactorsPerLevel(shrinkFactors=np.array([3,2,1]))
registration_method.SetSmoothingSigmasPerLevel( smoothingSigmas=np.array([1.5,1.0,0.0]))
registration_method.SmoothingSigmasAreSpecifiedInPhysicalUnitsOn()


registration_transform_sitk = registration_method.Execute( fixed, moving)

The relevant error message when I call the execute method is:
RuntimeError: Exception thrown in SimpleITK ImageRegistrationMethod_Execute: /tmp/SimpleITK-build/ITK-prefix/include/ITK-5.1/itkSmoothingRecursiveGaussianImageFilter.hxx:217:
itk::ERROR: itk::ERROR: SmoothingRecursiveGaussianImageFilter(0x6411d750): The number of pixels along dimension 2 is less than 4. This filter requires a minimum of four pixels along the dimension to be processed.

I think in 4.13 there was no attempt to smooth along dimension 2 but in 5.1 there is now an attempt at smoothing along dimension 2 but not enough pixels in my fixed image.

The reason is that registration framework now uses recursive gaussian instead of discrete gaussian filter. I don’t remember whether that can be overridden. The problem comes from you using a 2D image as a 3D one. Maybe @blowekamp or @zivy have some suggestions?

Hello,

That is an interesting use case, with the z-dimension being just 1. I was unaware that was functional.

I have not had a chance to test, but two possible work arounds include using the Expand filter to duplicate slice to be of sufficient size, or to smooth the images outside the registration framework.

To test if either of these work, just start with 1 level in the framework.

Would there be a recommended or preferred way to perform 2D to 3D registration in the ITK framework? It would be nice to replicate the behavior I saw with 4.13 but if there is a better way to do 2D to 3D registration within ITK it would be great to know about it.

Hello,

I tested your code with trivially constructed images with your specified size and reproduced your error:

fixed = sitk.Image([178, 164, 1], sitk.sitkFloat32)
moving = sitk.Image([147, 133, 138], sitk.sitkFloat32)

I confirmed that by using the expand filter, the report error did not occur:

fixed = sitk.Expand(fixed, expandFactors=[1,1,4])

Or by setting the smoothing sigmas to 0, the reported error did not occur either:

registration_method.SetSmoothingSigmasPerLevel(smoothingSigmas=[0.0, 0.0, 0.0])

While the above sets the framework’s smoothing sigma’s to 0, smoothing can be done outside the framework before registration.

Either of those can be used as a work around to this change of behavior. The change will need to be tested and the results may be different. If the previous results would satisfactory then I would expect these solutions would work too.

1 Like

Does setting only the 3rd sigma to zero work?

With the expand approach, depending on the thickness of slices, it might be helpful to change thickness inversely proportional to expand factor, e.g. reduce spacing 4x along Z.

This sigmas are per registration level not per dimension. The itk::ImageRegistrationMethodv4’s interface only support isotropic scaling.

As ITK filters are aware of the geometry meta-data, this filter preserves the extent of the image by changing the spacing and the origin:

In [3]: fixed = sitk.Image([178, 164, 1], sitk.sitkFloat32)

In [4]: exp_fixed = sitk.Expand(fixed, [1, 1, 4])

In [5]: print(exp_fixed.GetSpacing()[2], exp_fixed.GetOrigin()[2])
0.25 -0.375
1 Like

Is there any way to switch off the smoothing and downsampling and just run a single registration level so the recursiveGaussianFilter never gets called?

If you look at the code:

You can see if the sigmas are 0 then the filter should not be run.

1 Like