Skip to content

ENH: Add labelmap support to image registration pipeline#35

Merged
aylward merged 2 commits intoProject-MONAI:mainfrom
aylward:registration_with_labelmap
Mar 31, 2026
Merged

ENH: Add labelmap support to image registration pipeline#35
aylward merged 2 commits intoProject-MONAI:mainfrom
aylward:registration_with_labelmap

Conversation

@aylward
Copy link
Copy Markdown
Collaborator

@aylward aylward commented Mar 31, 2026

Threads optional multi-label segmentation (labelmap) through the base class, ANTs, Greedy, ICON, and time-series registrars. When a labelmap is provided it is used in place of the binary mask; ICON activates dice-loss weighting accordingly.

Summary by CodeRabbit

  • New Features

    • Optional label-map parameters added to registration APIs for multi-label segmentation
    • New API to set a fixed label map for registration
    • Time-series registration now accepts per-frame label maps and forwards them to backends
    • Backends preferentially use label maps (when available) for masked registration
  • Chores

    • Added ignore pattern for *_cache files
  • Documentation

    • Updated public API docs to reflect the new label-map parameters and signatures

Threads optional multi-label segmentation (labelmap) through the base
class, ANTs, Greedy, ICON, and time-series registrars. When a labelmap
is provided it is used in place of the binary mask; ICON activates
dice-loss weighting accordingly.
Copilot AI review requested due to automatic review settings March 31, 2026 15:52
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 08490776-fefc-428f-aa90-8cb6b1d1abab

📥 Commits

Reviewing files that changed from the base of the PR and between 11cfdf3 and 12739d8.

📒 Files selected for processing (2)
  • .gitignore
  • src/physiomotion4d/register_images_icon.py
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/physiomotion4d/register_images_icon.py

Walkthrough

Added optional moving_labelmap parameters across registration_method APIs, introduced fixed_labelmap state with setter, propagated per-frame moving_labelmaps through time-series registration, and refined return type annotations to dict[str, Union[itk.Transform, float]]. ICON backend computes effective masks from labelmaps.

Changes

Cohort / File(s) Summary
Base Registration API
src/physiomotion4d/register_images_base.py
Added self.fixed_labelmap and self.moving_labelmap fields, introduced set_fixed_labelmap(), extended register() and registration_method() with moving_labelmap parameter, and tightened return type annotations to dict[str, Union[itk.Transform, float]].
ANTs & Greedy Backends
src/physiomotion4d/register_images_ants.py, src/physiomotion4d/register_images_greedy.py
Extended registration_method() signatures to accept optional moving_labelmap (signature-only; no behavioral changes shown).
ICON Backend
src/physiomotion4d/register_images_icon.py
Added moving_labelmap parameter, compute fixed_effective_mask/moving_effective_mask preferring labelmaps over binary masks, adjust masked-registration decision, set dice_loss_weight when labelmaps used, and update return type annotation.
Time-Series Registration
src/physiomotion4d/register_time_series_images.py, src/physiomotion4d/register_models_distance_maps.py
Added moving_labelmaps per-frame parameter, validate lengths, forward moving_labelmap per-frame to backend register()/registration_method(), and apply set_fixed_labelmap() to backends where relevant.
Documentation & Misc
docs/API_MAP.md, .gitignore
Updated API docs to document moving_labelmap/moving_labelmaps; added .gitignore pattern *_cache.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through code with eager paws,
Added labelmaps, minding all the laws.
Per-frame guides and ICON's careful mask,
Now registrations wear a clearer task. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding labelmap support to the image registration pipeline, which aligns perfectly with the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds optional multi-label segmentation (labelmap) plumbing through the image registration APIs so callers can pass per-frame labelmaps (time-series) and enable labelmap-aware behavior (notably for ICON).

Changes:

  • Extend base/time-series registration interfaces to accept moving_labelmap(s) and store fixed_labelmap.
  • Thread fixed_labelmap into the ANTs/ICON registrars from the time-series pipeline and pass moving_labelmap through registration calls.
  • Update ICON registrar to prefer labelmaps over binary masks and to enable dice-loss weighting; update docs/API_MAP.md for the new public API signatures.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/physiomotion4d/register_time_series_images.py Adds moving_labelmaps parameter and forwards fixed/moving labelmaps into underlying registrars.
src/physiomotion4d/register_images_icon.py Adds moving_labelmap support, labelmap-as-mask behavior, and dice-loss weighting toggle.
src/physiomotion4d/register_images_greedy.py Extends API signature with moving_labelmap (currently not used in implementation).
src/physiomotion4d/register_images_base.py Adds stored fixed_labelmap / moving_labelmap and setter, and threads labelmap into register()/registration_method() calls.
src/physiomotion4d/register_images_ants.py Extends API signature with moving_labelmap (currently not used in implementation).
docs/API_MAP.md Regenerated API map to reflect the updated public method signatures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/physiomotion4d/register_images_greedy.py (1)

260-267: moving_labelmap parameter added but unused in Greedy backend.

Same as ANTs, the parameter is added for API consistency but is not utilized. The Greedy registration continues to use only moving_mask for -gm/-mm options. Consider adding a docstring note about this for clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/physiomotion4d/register_images_greedy.py` around lines 260 - 267, In
registration_method, the new parameter moving_labelmap is currently unused by
the Greedy backend; update the docstring for the method (registration_method) to
note that moving_labelmap is accepted for API consistency with the ANTs backend
but is ignored by the Greedy implementation and that Greedy only uses
moving_mask for its -gm/-mm options; reference the parameter name
moving_labelmap and the function registration_method so reviewers can find and
read the added clarification.
src/physiomotion4d/register_images_ants.py (1)

510-517: moving_labelmap parameter added but unused.

The parameter is added for API consistency with the base class, but it's not utilized in the ANTs registration. This is acceptable since ANTs doesn't natively support dice-loss weighting like ICON. However, consider:

  1. Adding a brief note in the docstring mentioning the parameter is accepted for API compatibility but not currently used by ANTs.
  2. Alternatively, logging a debug message when a labelmap is provided but ignored.
📝 Suggested docstring addition (around line 526-528)
         Args:
             moving_image (itk.image): The 3D image to be registered/aligned.
             moving_mask (itk.image, optional): Binary mask defining the
                 region of interest in the moving image
+            moving_labelmap (itk.image, optional): Multi-label segmentation for
+                the moving image. Note: Currently not used by ANTs registration;
+                accepted for API compatibility with other backends.
             moving_image_pre (ants.core.ANTsImage, optional): Pre-processed moving image
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/physiomotion4d/register_images_ants.py` around lines 510 - 517, The
registration_method currently accepts moving_labelmap but never uses it; update
the registration_method's docstring to note that moving_labelmap is accepted for
API compatibility with the base class but is ignored by the ANTs implementation,
and/or add a debug log in registration_method (using the existing logger) to
emit a message when moving_labelmap is provided and will be ignored; reference
the registration_method function and the moving_labelmap parameter so reviewers
can find where to add the docstring note and the optional logger.debug call.
src/physiomotion4d/register_images_base.py (1)

194-205: Consider validating fixed_image before setting fixed_labelmap.

The set_fixed_mask method validates that fixed_image is set before allowing a mask (line 180-181). For consistency and to catch user errors early, set_fixed_labelmap should likely have the same guard. Additionally, consider whether setting a labelmap should clear the fixed_mask (or vice versa) to prevent inconsistent state.

💡 Suggested validation
     def set_fixed_labelmap(self, fixed_labelmap: Optional[itk.Image]) -> None:
         """Set the fixed image labelmap (multi-label segmentation).

         Args:
             fixed_labelmap (itk.Image, optional): Multi-label segmentation
                 co-registered with the fixed image, or None to clear.
         """
+        if fixed_labelmap is not None and self.fixed_image is None:
+            raise ValueError("Fixed image must be set before setting a fixed labelmap.")
         self.fixed_labelmap = fixed_labelmap
         self.forward_transform = None
         self.inverse_transform = None
         self.loss = None
         self.moving_image_registered = None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/physiomotion4d/register_images_base.py` around lines 194 - 205, The
set_fixed_labelmap method currently sets fixed_labelmap without validating that
fixed_image exists; update set_fixed_labelmap to mirror set_fixed_mask by
raising an error (or ValueError) if self.fixed_image is None, and then set
self.fixed_labelmap; also clear any conflicting state by resetting
self.fixed_mask to None (or vice versa per project convention) along with
forward_transform, inverse_transform, loss, and moving_image_registered so the
object cannot be left in an inconsistent state; reference method names
set_fixed_labelmap and set_fixed_mask and attributes fixed_image,
fixed_labelmap, fixed_mask, forward_transform, inverse_transform, loss,
moving_image_registered when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/physiomotion4d/register_images_icon.py`:
- Around line 232-248: The network is cached in self.net but dice_loss_weight is
computed per call from moving_labelmap, so subsequent calls may use the wrong
loss configuration; update register() to detect when the desired
dice_loss_weight (computed from moving_labelmap) differs from the network's
current setting and reinitialize the network if so. Concretely, store the
current dice weight on the instance (e.g., self._dice_loss_weight) when creating
the network via get_multigradicon/get_unigradicon, and on each register() call
compute dice_loss_weight from moving_labelmap and if self.net is None or
dice_loss_weight != self._dice_loss_weight then recreate the net with the new
dice_loss_weight; ensure both branches that call get_multigradicon and
get_unigradicon set self._dice_loss_weight accordingly.
- Around line 224-230: The current logic sets fixed_effective_mask based on
moving_labelmap presence which can produce mismatched masks; change the
selection so fixed_effective_mask uses self.fixed_labelmap when it exists (i.e.,
fixed_effective_mask = self.fixed_labelmap if self.fixed_labelmap is not None
else self.fixed_mask) and add a consistency check in the surrounding code (in
the same block where moving_effective_mask and fixed_effective_mask are
computed) to either raise an error or handle the case when one side has a
labelmap and the other does not so registration does not silently fall back to
unmasked behavior; reference variables: moving_effective_mask,
fixed_effective_mask, moving_labelmap, self.fixed_labelmap, moving_mask,
self.fixed_mask.

---

Nitpick comments:
In `@src/physiomotion4d/register_images_ants.py`:
- Around line 510-517: The registration_method currently accepts moving_labelmap
but never uses it; update the registration_method's docstring to note that
moving_labelmap is accepted for API compatibility with the base class but is
ignored by the ANTs implementation, and/or add a debug log in
registration_method (using the existing logger) to emit a message when
moving_labelmap is provided and will be ignored; reference the
registration_method function and the moving_labelmap parameter so reviewers can
find where to add the docstring note and the optional logger.debug call.

In `@src/physiomotion4d/register_images_base.py`:
- Around line 194-205: The set_fixed_labelmap method currently sets
fixed_labelmap without validating that fixed_image exists; update
set_fixed_labelmap to mirror set_fixed_mask by raising an error (or ValueError)
if self.fixed_image is None, and then set self.fixed_labelmap; also clear any
conflicting state by resetting self.fixed_mask to None (or vice versa per
project convention) along with forward_transform, inverse_transform, loss, and
moving_image_registered so the object cannot be left in an inconsistent state;
reference method names set_fixed_labelmap and set_fixed_mask and attributes
fixed_image, fixed_labelmap, fixed_mask, forward_transform, inverse_transform,
loss, moving_image_registered when making the change.

In `@src/physiomotion4d/register_images_greedy.py`:
- Around line 260-267: In registration_method, the new parameter moving_labelmap
is currently unused by the Greedy backend; update the docstring for the method
(registration_method) to note that moving_labelmap is accepted for API
consistency with the ANTs backend but is ignored by the Greedy implementation
and that Greedy only uses moving_mask for its -gm/-mm options; reference the
parameter name moving_labelmap and the function registration_method so reviewers
can find and read the added clarification.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8cc2bdb2-809d-4c4b-9ce9-7208d5da01de

📥 Commits

Reviewing files that changed from the base of the PR and between eac1c56 and 11cfdf3.

📒 Files selected for processing (6)
  • docs/API_MAP.md
  • src/physiomotion4d/register_images_ants.py
  • src/physiomotion4d/register_images_base.py
  • src/physiomotion4d/register_images_greedy.py
  • src/physiomotion4d/register_images_icon.py
  • src/physiomotion4d/register_time_series_images.py

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 31, 2026

Codecov Report

❌ Patch coverage is 12.50000% with 21 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@eac1c56). Learn more about missing BASE report.

Files with missing lines Patch % Lines
src/physiomotion4d/register_images_base.py 20.00% 8 Missing ⚠️
src/physiomotion4d/register_time_series_images.py 0.00% 8 Missing ⚠️
src/physiomotion4d/register_images_icon.py 16.66% 5 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main      #35   +/-   ##
=======================================
  Coverage        ?   13.67%           
=======================================
  Files           ?       49           
  Lines           ?     6596           
  Branches        ?        0           
=======================================
  Hits            ?      902           
  Misses          ?     5694           
  Partials        ?        0           
Flag Coverage Δ
integration-tests 13.67% <12.50%> (?)
unittests 13.67% <12.50%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@aylward aylward merged commit 666146f into Project-MONAI:main Mar 31, 2026
14 checks passed
@aylward aylward deleted the registration_with_labelmap branch March 31, 2026 16:28
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