Bspline Free form deformable registration

Once you have points, they are points. It does not matter that they came from an image. You need to treat them as points, e.g. use point-set registration instead of image registration. That is currently not exposed in Python interface, which might be causing confusion for you.

Oh I see what you mean . I have a follow up question as well .
So for this second half of the B-spline registration

# Select the fixed and moving images, valid entries are in [0,9].
fixed_image_index = 0
moving_image_index = 7


tx = bspline_intra_modal_registration(fixed_image = images[fixed_image_index], 
                                      moving_image = images[moving_image_index],
                                      fixed_image_mask = (masks[fixed_image_index] == lung_label),
                                      fixed_points = points[fixed_image_index], 
                                      moving_points = points[moving_image_index]
                                     )
initial_errors_mean, initial_errors_std, _, initial_errors_max, initial_errors = ru.registration_errors(sitk.Euler3DTransform(), points[fixed_image_index], points[moving_image_index])
final_errors_mean, final_errors_std, _, final_errors_max, final_errors = ru.registration_errors(tx, points[fixed_image_index], points[moving_image_index])

plt.hist(initial_errors, bins=20, alpha=0.5, label='before registration', color='blue')
plt.hist(final_errors, bins=20, alpha=0.5, label='after registration', color='green')
plt.legend()
plt.title('TRE histogram');
print('Initial alignment errors in millimeters, mean(std): {:.2f}({:.2f}), max: {:.2f}'.format(initial_errors_mean, initial_errors_std, initial_errors_max))
print('Final alignment errors in millimeters, mean(std): {:.2f}({:.2f}), max: {:.2f}'.format(final_errors_mean, final_errors_std, final_errors_max)) 

There are fixed_points = points[fixed_image_index], and moving_points = points[moving_image_index] . So what exactly do these points corresponds do .

Thank you :slight_smile:

Hello @VeerBal,

Those points are not used for registration. They are corresponding points (same points over the respiratory cycle) which were manually localized and are used in the code for evaluating the quality of the intensity based registration.

That makes sense . Thanks a lot . :slight_smile:

Is there a way to implement this approach for my data set .

Here is an updated PR:

1 Like

That’s awesome . Can you tell me a bit more how to use this PR for my code .

Thanks a lot .

You could build from source. Or wait until this is integrated into master and makes its way into a release, so you can pip install it.

You should be able to instantiate the registration method and metric as below:

registration_metric = itk.PointSetToPointSetMetric.PSF3.New()
registration_method = itk.PointSetToPointSetRegistrationMethod.REGF3F3.New()
1 Like

Alternatively, registration_metric = itk.PointSetToPointSetMetric[PointSetType].New()

1 Like

Thank you so much @Pranjal_Sahu and @dzenanz . I will try this approach .

Just for clarification . In my Bspline registration function , I should replace
registration_method = sitk.ImageRegistrationMethod()
and
registration_method.SetMetricAsMeanSquares()
with
registration_metric = itk.PointSetToPointSetMetric[PointSetType].New()
and
registration_method = itk.PointSetToPointSetRegistrationMethod.REGF3F3.New()

Thank you

Yes. But now you will need an extra call, something like registration_method.SetMetric(registration_metric).

Perfect . Thanks for the clarification . Will keep you posted with the results :slight_smile:

Hello
So I was working on my code with the Bspline FFD and my code was similar to the one used in the POPI model . Previously I was getting an error [ virtual sampled points must have one or more points ]

This is the part of the code:

registration_method.SetInitialTransformAsBSpline(initial_transform,
                                                 inPlace=False,
                                                 scaleFactors=[1,2,4])

registration_method.SetMetricAsMeanSquares()
 registration_method.SetMetricAsJointHistogramMutualInformation()
registration_method.SetMetricSamplingStrategy(registration_method.RANDOM)
registration_method.SetMetricSamplingPercentage(0.01)
#registration_method.SetMetricFixedMask(Fixed_image_sitk_ffd_mask)
    
registration_method.SetShrinkFactorsPerLevel(shrinkFactors = [4,2,1])
registration_method.SetSmoothingSigmasPerLevel(smoothingSigmas=[2,1,0])
registration_method.SmoothingSigmasAreSpecifiedInPhysicalUnitsOn()

registration_method.SetInterpolator(sitk.sitkLinear)
registration_method.SetOptimizerAsLBFGS2(solutionAccuracy=1e-2, numberOfIterations=100, deltaConvergenceTolerance=0.01)

registration_method.AddCommand(sitk.sitkIterationEvent, lambda: iteration_callback(registration_method))

final_transformation = registration_method.Execute(Fixed_image_sitk_ffd, Moving_image_sitk_ffd)
print('\nOptimizer\'s stopping condition, {0}'.format(registration_method.GetOptimizerStopConditionDescription())) 

so when I run this code without commenting the line registration_method.SetMetricFixedMask(Fixed_image_sitk_ffd_mask) I still get the same error as above . But when I comment this line the code runs and gives me an output of
-0.64
Optimizer’s stopping condition, Already minimized

my moving and fixed images for now are the lung dicom images that have been saved as .mha files , but I haven’t used any mask files in this code .

Can you provide some insights about what might be causing that error in the place .

The optimizer cannot improve registration metric. Try setting tighter tolerances (e.g. solutionAccuracy=1e-4).

Please repeat the error message, as this thread is already long and it is not clear to which “above error” you are referring. Also consider starting a new discussion thread.

1 Like

Sorry for not being clear in the first place .
So by error I meant
final_transformation = registration_method.Execute(Fixed_image_sitk_ffd, Moving_image_sitk_ffd)

File “C:\Users\singhgau\Anaconda3\lib\site-packages\SimpleITK\SimpleITK.py”, line 10387, in Execute
return _SimpleITK.ImageRegistrationMethod_Execute(self, fixed, moving)

RuntimeError: Exception thrown in SimpleITK ImageRegistrationMethod_Execute: d:\a\1\sitk-build\itk-prefix\include\itk-5.2\itkImageToImageMetricv4.hxx:270:
ITK ERROR: MeanSquaresImageToImageMetricv4(000001ABEF49DE90): VirtualSampledPointSet must have 1 or more points.

This is when I have registration_method.SetMetricFixedMask(Fixed_image_sitk_ffd_mask) .

1 Like

This probably means there is no overlap of your mask and your image. Potentially there is a small overlap, but none of the randomly chosen 1% of points do not fall there.

So is there a way to fix the error, or just not use this line at all .
Thanks

Try increasing sampling percentage (registration_method.SetMetricSamplingPercentage(0.01) and make sure that your fixed mask is in the same physical space as your fixed image.

1 Like