Skip to content

Add elastic image registration for 4D CT scenarios#918

Open
acsevillam wants to merge 1 commit into
e0404:devfrom
acsevillam:pr/elastic-image-registration
Open

Add elastic image registration for 4D CT scenarios#918
acsevillam wants to merge 1 commit into
e0404:devfrom
acsevillam:pr/elastic-image-registration

Conversation

@acsevillam
Copy link
Copy Markdown

Feature description

This PR adds elastic image registration support for 4D CT scenarios. It introduces a common image registration interface and a demons-based elastic registration implementation that computes deformation vector fields between a reference CT scenario and the remaining CT scenarios. The implementation can also use push deformation fields to propagate contours from the reference scenario.

Approach

  • Adds matRad_ImageRegistration as an abstract interface for 4D image registration classes.
  • Adds matRad_ElasticImageRegistration, which computes deformation vector fields using MATLAB's imregdemons.
  • Supports pull and push deformation fields through metadata.dvfType.
  • Supports deformation vector fields in voxel or millimeter units through metadata.dvfUnits.
  • Adds contour propagation for push deformation fields using imwarp.
  • Stores deformation metadata in the ct struct, including reference scenario and DVF settings.
  • Adds MOxUnit tests for constructor defaults, struct serialization, input validation, dependency handling, DVF metadata, and contour propagation behavior.

New metadata fields and defaults:

  • metadata.dvfType = 'pull'
  • metadata.dvfUnits = 'voxel'
  • metadata.numIterations = 100
  • metadata.pyramidLevels = 1
  • metadata.accumulatedFieldSmoothing = 1

External dependencies:

  • This feature requires MATLAB with Image Processing Toolbox for imregdemons.
  • Contour propagation additionally requires imwarp.
  • The implementation checks for these dependencies and reports matRad errors when they are unavailable.
  • Tests that require the toolbox are skipped when the dependency is not available.

Open Questions and/or Concerns

  • Reviewers should confirm that the DVF metadata fields are appropriate for future 4D dose accumulation workflows.

References

@read-the-docs-community
Copy link
Copy Markdown

Documentation build overview

📚 matRad | 🛠️ Build #32912487 | 📁 Comparing 5fd45c7 against latest (5a43850)

  🔍 Preview build  

19 files changed · + 1 added · ± 18 modified

+ Added

± Modified

@codecov
Copy link
Copy Markdown

codecov Bot commented May 30, 2026

Codecov Report

❌ Patch coverage is 74.01130% with 46 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.12%. Comparing base (174e756) to head (5fd45c7).

Files with missing lines Patch % Lines
...mageRegistration/matRad_ElasticImageRegistration.m 76.54% 38 Missing ⚠️
matRad/4D/matRad_ImageRegistration.m 46.66% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #918      +/-   ##
==========================================
+ Coverage   54.96%   55.12%   +0.16%     
==========================================
  Files         322      324       +2     
  Lines       20618    20795     +177     
==========================================
+ Hits        11333    11464     +131     
- Misses       9285     9331      +46     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@github-actions
Copy link
Copy Markdown

Test Results

    3 files  ± 0      3 suites  ±0   33m 35s ⏱️ + 1m 23s
  376 tests + 9    370 ✅ + 3   0 💤 ±0  6 ❌ +6 
1 224 runs  +27  1 207 ✅ +15  11 💤 +6  6 ❌ +6 

For more details on these failures, see this check.

Results for commit 5fd45c7. ± Comparison against base commit 174e756.

Copy link
Copy Markdown
Contributor

@wahln wahln left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also a nice addition, have some comments regarding the metadata struct and naming though.

ct
cst
refScen
metadata
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need the metadata object?
I think it should also be possible to just have the corresponding properties on the class. This makes it easier to have default values and understand which properties are necessary. E.g. you could instantiate the class and directly see the corresponding properties in the property explorer of matRad.

@@ -0,0 +1,70 @@
classdef (Abstract) matRad_ImageRegistration
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use a class name that shows this is an Abstract class. This is not entirely consistent in the code base, which uses *Abstract and *Base, but matRad_ImageRegistrationBase would be preferable to the top-level Base class.

Comment on lines +191 to +219
function metadata = normalizeMetadata(metadata)
matRadCfg = MatRad_Config.instance();

if ~isstruct(metadata)
matRadCfg.dispError('metadata must be a struct.');
end

metadata = matRad_ElasticImageRegistration.setDefaultMetadataField(metadata, 'dvfType', 'pull');
metadata = matRad_ElasticImageRegistration.setDefaultMetadataField(metadata, 'dvfUnits', 'voxel');
metadata = matRad_ElasticImageRegistration.setDefaultMetadataField(metadata, 'numIterations', 100);
metadata = matRad_ElasticImageRegistration.setDefaultMetadataField(metadata, 'pyramidLevels', 1);
metadata = matRad_ElasticImageRegistration.setDefaultMetadataField(metadata, 'accumulatedFieldSmoothing', 1);

metadata.dvfType = char(metadata.dvfType);
metadata.dvfUnits = char(metadata.dvfUnits);

if ~any(strcmp(metadata.dvfType, {'pull', 'push'}))
matRadCfg.dispError('metadata.dvfType must be ''pull'' or ''push''.');
end

if ~any(strcmp(metadata.dvfUnits, {'voxel', 'mm'}))
matRadCfg.dispError('metadata.dvfUnits must be ''voxel'' or ''mm''.');
end

matRad_ElasticImageRegistration.validatePositiveInteger(metadata.numIterations, 'metadata.numIterations', matRadCfg);
matRad_ElasticImageRegistration.validatePositiveInteger(metadata.pyramidLevels, 'metadata.pyramidLevels', matRadCfg);
matRad_ElasticImageRegistration.validateNonnegativeScalar(metadata.accumulatedFieldSmoothing, ...
'metadata.accumulatedFieldSmoothing', matRadCfg);
end
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably this can be simplified if you drop the "metadata" field and just use properties on the class. Then you can use property set/get functions from Matlab to check the values.

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

properties (Constant)
name = 'Elastic Registration'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we specify this class uses imregdemons in the name? Because someone could implement another Elastic Registration.

If you want to be extremely flexible for the future, you could have matRad_ElasticImageRegistrationAbstract as an intermediate Abstract class specifying the common properties, and then have matRad_ElasticImageRegistrationImregdemons as the final implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants