I’m currently using the Python demons registration filters (DemonsRegistrationFilter, DifferomorphicDRF, SymmetricDRF, etc.) from SimpleITK to perform non-rigid image registration on x-rays for my research.
Is there a simple way to set the filters to stop running upon reaching a certain metric value? Right now, the filters run until the maximum number of iterations has been reached regardless of metric value.
I’ve looked through the documentation several times and I can’t seem to find what I’m looking for. I know that one solution would be to run the the filter twice to see what metric value is achieved at each iteration but if registration takes 1000s of iterations I’d prefer not to do it more than once.
Should I be using the ITKv4 registration framework instead to better control optimization?
The Demons family of algorithms has a SetMaximumRMSError which provides you with an image similarity based stopping criterion, the SetNumberOfIterations gives you a known bound on the number of iterations.
Using the observer/callback mechanism you can look at the RMS change GetRMSChange and force early termination by changing the caller’s settings (I believe SetNumberOfIterations(GetElapsedIterations()-1) will work though haven’t tried it).
I experimented with the SetMaximumRMSError function and it definitely works to stop iterations. However, when experimenting with two sets of images the final RMS was higher for the more similar images and lower for images that were more different. So, demons registration stopped for images that needed more registration but kept going for images that were registered very well.
When I added a callback to look at the RMS Change values they were all 0.0. The exact modification I did is shown below.
But, if I understand you what told me, the command_iteration inline function allows me to send callbacks to the demons observable during runtime. I should be able to add a stopping criterion in this inline function based on the metric or RMS error.
I added a stopping criterion based on the current metric value. Here’s my modified function:
def command_iteration(filter):
print(f"{filter.GetElapsedIterations():3} = {filter.GetMetric():10.5f}")
# This is a test to stop the filter in the middle of iterations
if filter.GetMetric() < 10.0:
filter.SetNumberOfIterations(filter.GetElapsedIterations() - 1)
print(f"{filter.GetNumberOfIterations():3}")
I don’t think it stopped iterations. This is an excerpt of the output:
Looks like this trick doesn’t work. It is due to the SimpleITK implementation and the interaction with the underlying ITK code. It should be addressed by this PR which will expose the StopRegistration method, allowing the caller to explicitly stop the registration.
To use the functionality you will have to update your version of SimpleITK to latest, once the PR is merged.
Thank you for the update. I’m glad I was able to contribute to adding more functionality to SimpleITK.
My last questions are, will the documentation be updated to include this new function and will this update also apply to the Anaconda version of SimpleITK?
Although it seems fairly intuitive, I want to make sure I use it properly.
Yes documentation will be added and this will be part of the SimpleITK anaconda distribution.
The next official SimpleITK release, 2.1, is expected in the next couple of weeks so you will be able to install that from the toolkit’s anaconda cloud channel. If you are in a hurry you will be able to use the feature once the pull-request is merged and the latest release is updated on GitHub (the install from GitHub works for anaconda too).