Registration Initialization Robustness - #2643
Merged
Merged
Conversation
…hapes The similarity metric averages over only the samples that land inside the moving image, so pulling the two images apart improves the score until nothing but background is being compared against background. The linear stages walked into that dead zone and came back mapping every particle far outside the target, which surfaced much later as an unplaceable particle from inside the sampler. A level now stops as soon as a step throws most of the fixed image off the moving one, and the affine stage is seeded with the size difference between the two shapes, which the rigid stage before it has no freedom to take up. Particles that still land where a domain cannot be sampled are walked back onto the shape rather than aborting the run, and the error names the domain and says whether the point was outside the image or merely outside the narrow band, which call for different answers. Registration initialization moves out of Optimize into RegistrationInitializer, and the transform cache key now carries the registration's own account of its settings, so that changing the algorithm cannot leave a stale description behind in the caller.
The list was built with selection and keyboard focus disabled, so the only way to get the text of an error out of Studio was to retype it from the screen. Messages can now be selected and copied with the usual shortcut or from a context menu, and an arriving message scrolls into view without clearing a selection that is part way through being made.
The rescue walks a stray particle towards one that landed, so a shape with no placed particle at all left every stray where it was and then threw from inside the sampler, which is the failure the rescue exists to prevent; that state now reports itself as a band too narrow to hold the registration. ITK throws rather than returning a zero mass for an empty image, so the scale seed's guard against one was unreachable and cost the pair its affine stage. A transform file is written after its displacement field rather than before, so that a run interrupted between the two leaves no entry instead of one that reads back as a deformable registration quietly reduced to a linear one. The narrow band is quoted in the voxels the parameter is set in rather than the world units the domain keeps it in, the affine seed no longer sets a centre that ImageRegistrationMethodv4 overrides, and the transfer summary counts registrations rather than shapes now that it can hold more than one per shape.
A particle is clamped into the domain's bounding box before it is sampled, but it was being judged where the registration left it, so one a fraction of a voxel outside a shape tight against its image counted against the threshold that abandons the run, for a registration that clamping would have made usable. The walk that moves a stray back now asks the same question, since a target that only clamping makes good is one it could otherwise never reach. The check for particles the displacement field did not cover is gone. It tested transferred and reference points for exact equality, which the rigid stage in the composite makes impossible, and the field is defined over the fixed image, which the reference particles are always well inside; so it guarded a state that cannot arise with a test that could not detect it.
The guard read the number of samples the metric last found usable, but with a line search that count belongs to whichever trial the golden section search evaluated last rather than to the step actually taken, so it could condemn a good step and, worse, pass a bad one. It now maps a few hundred points of its own through the transform and counts how many land on the moving image, which measures the step that was taken and stays comparable across levels of the pyramid rather than growing with them. Two tests cover what the registration gained: that the affine stage recovers a size difference too large for it to find unaided, which fails without the seed that hands it one, and that every setting able to change a transform also changes the description a caller keeps transforms against.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2642
The similarity metric drops samples that fall outside the moving image rather than penalizing them, so the linear stages could improve their score by pulling the two shapes apart until only background was left to compare. A level now stops as soon as a step throws most of the fixed image off the moving one, and the affine stage is seeded with the size difference that the rigid stage before it has no freedom to take up.
Alongside that: strays are walked back onto the shape instead of aborting the run, the narrow band error names the domain and separates the two causes it can have, and the transform cache key now comes from the registration's own account of its settings. Registration initialization moves out of
OptimizeintoRegistrationInitializer. Existing transform caches are invalidated by design, so the first run on any project re-registers.