Bspline Free form deformable registration

So after iterating my bspline FFD my output looks like this where I’m getting a rounding error .
14408.027
Optimizer’s stopping condition, A rounding error occurred or line-search steps have an insufficient reduction
Iteration: 50
Metric value: 14402.493636195337

My optimizer conditions are as follows
registration_method.SetOptimizerAsLBFGS2(solutionAccuracy=1e-4, numberOfIterations=100, deltaConvergenceTolerance=0.01)

Can you provide some insights of what might be causing this .

This code is equivalent to the POPI model . I tried adjusting the solution accuracy but I’m still getting this optimizer stop condition .

This might very well mean convergence has been reached.

1 Like

So I was performing the Bspline FFD registration same as the POPI model . My fixed and moving images are the two CT lung ct scans at different timepoint . And I generated 100 random fixed and moving points from the Ct images for TRE . The optimizer that I used was registration_method.SetOptimizerAsLBFGS2(solutionAccuracy=1e-2, numberOfIterations=100,deltaConvergenceTolerance=0.01) . And for metric sampling I did not used any mask as it was giving me an error of VirtualSampledPointSet must have 1 or more points.

These were the results I got which does not seem to be significant .

image

image

So my question is … Is there a way I could improve these results and is there a better way to use fixed and moving points from the images for TRE .

If you are tired of tuning the registration yourself, it is worth trying ITKElastix. I don’t know whether it is available in SimpleITK, you would need to use ITK Python wrapping. Examples are available.

1 Like

Hi.
I have a quick question about the composite transformation .

So I did a bslpline FFD transformation on the lung CT scans pre and post for the same subject and my fixed and moving points are the airway bifurcation points ( x, y ,z) , but my fixed mask is set to NONE

So for the TRE for Bspline I have
Initial alignment errors for subjects 20 and 21 in millimeters, mean(std): 133.73(38.81), max: 259.89
and
Final alignment errors in millimeters, mean(std): 65.73(42.72), max: 166.35

But I also did an affine registration on the lung mask prior to this Bspline FFD and therefore did a composite transformation using
Composite_tx = sitk.CompositeTransform([Affine_transform,tx])

and then I looked at the TRE which is larger than , when I only performed Bspline FFD

Final alignment errors for composite for subjects 20 and 21 in millimeters, mean(std): 73.66(44.36), max: 183.80

Can you provide some insights if I’m doing something wrong because from my understanding a composition of affine (rigid) and bspline (non rigid) is a better registration and hence the errors should be lower than when I did just the Bspline FFD .

Thank you

Steps should be:

  1. do affine registration using lung masks
  2. create a composite transform of affine from step 1 and default-initialized BSpline
  3. do free-form registration using the above composite transform making sure you are optimizing only the last transform (BSpline)

If you are optimizing BSpline separately from affine, it is no wonder that their combination is worse than BSpline alone.

1 Like

Thank you so much. Is there a code that I could refer to . I’m working in python .

Thank you

I don’t think there is a Python example. It should not be hard to translate DeformableRegistration15, or relevant parts of it, into Python.

1 Like

So if I correctly understood
First do a composite of the affine transform that has been generated as tfm and default-initialized bspline

registration_method = sitk.ImageRegistrationMethod()
#code for grid physical_spacing , initial_physical size, mesh_size

initialized_bspline = sitk.BSplineTransformInitializer(image1 = fixed_image,
transformDomainMeshSize = mesh_size, order=3)
composite_tx = sitk.CompositeTransform([Affine_transform, initialized bspline ])

and then use this as an initial b-spline
R.SetInitialTransform(composite_tx)
and then for optimizing the last transform
use
R.SetOnlyMostRecentTransformToOptimizeOn();
R.SetOptimizerAsLBFGS2(solutionAccuracy=1e-2, numberOfIterations=100, deltaConvergenceTolerance=0.01)

Thank you once again

Sounds about right.

1 Like

I am getting an attribute error using ‘SetOnlyMostRecentTransformToOptimizeOn’
Error Message

composite.SetOnlyMostRecentTransformToOptimizeOn()

AttributeError: ‘CompositeTransform’ object has no attribute ‘SetOnlyMostRecentTransformToOptimizeOn’

Sample code

registration_method = sitk.ImageRegistrationMethod()
#code for grid physical_spacing , initial_physical size, mesh_size

initial_transform = sitk.BSplineTransformInitializer(
    image1=fixed_image, transformDomainMeshSize=mesh_size, order=3
)

# initialize the composite transform by affine and initital B-spline transform
# initializer 
composite = sitk.CompositeTransform([Affine_transform,initial_transform])

# optimize the most recent transform ( B-spline) but still using the previous affine 
composite.SetOnlyMostRecentTransformToOptimizeOn()
# set the initial transform as the composite of affine and iniital transform
registration_method.SetInitialTransform(composite)

So it looks like this composite transformation doesn’t have the attribute to optimize the only last transform , is there another way to do the optimization for only the last transform.

Can you provide some insights on what might be causing this issue . Thank you

Maybe composite.OnlyMostRecentTransformToOptimizeOn() or composite.SetOnlyMostRecentTransformToOptimize(True)?

1 Like

Using both of these approaches are yielding me same error
of composite transform doesn’t have the attribute to optimize the last transform.
AttributeError: ‘CompositeTransform’ object has no attribute ‘OnlyMostRecentTransformToOptimizeOn’

Is there another approach to optimizing the most recent transform .

Thank you :slight_smile:

@blowekamp or @zivy might be able to help with syntax.

1 Like

Hello @VeerBal,

In SimpleITK “The only parameters of the transform at the back of the queue are exposed and optimizable for registration.” (see CompositeTransform doxygen), so nothing needs to be set and hence this method doesn’t exist.

1 Like

Thank you
So this means I can carry out my deformable registration simply by initializing it with composite of my affine transformation and initial B-spline and then carrying out the free form deformation on it without using the function SetOnlyMostRecentTransformToOptimizeOn() .

1 Like

Correct.

1 Like

So I performed the deformable registration . But when I overlay the fixed and the registered image , registration works great for the axial view . But for the coronal and sagittal view , its not that great .
image
image
image

Can you provide some insights of why this might be happening .

Thank you once again .

Could you be mixing up laterality (left/right) in coronal and sagittal overlay?

I double checked and the overlay doesn’t look mixed up . Could there be any other issue going on.