Skip to content

Preserve channels_first through resample_image, smooth_image, and indexing - #957

Open
SID-6921 wants to merge 1 commit into
ANTsX:mainfrom
SID-6921:fix/channels-first-resample-smooth-indexing
Open

SID-6921 wants to merge 1 commit into
ANTsX:mainfrom
SID-6921:fix/channels-first-resample-smooth-indexing

Conversation

@SID-6921

Copy link
Copy Markdown

Description

Follow-up to #938, whose description explicitly reserves "independent channels_first propagation defects in resample_image, smooth_image, and multicomponent indexing" for later work.

ants.resample_image's multi-component branch reassigns its own image parameter inside the per-channel loop (for image in images:). By the time channels_first=image.channels_first runs after the loop, image refers to the last split-channel component, which split_channels() always constructs with channels_first=False (the ANTsImage.__init__ default). The explicit propagation code looks correct but is always a no-op.

ants.smooth_image's multi-component branch has the exact same loop-variable shadowing (for image in imagelist:), and on top of that didn't even attempt to pass channels_first to merge_channels at all.

ANTsImage.__getitem__'s has_components branch had the same omission as smooth_image — no channels_first passed through.

Fix

  • resample_image: capture channels_first = image.channels_first before the loop, and rename the loop variable so it can no longer shadow the function's own image parameter.
  • smooth_image: same pattern — capture before the loop, rename the loop variable, and pass channels_first through to merge_channels (previously missing entirely).
  • ANTsImage.__getitem__: pass channels_first=self.channels_first through to merge_channels.

Testing

Verified live against the real compiled ants package (pip install antspyx, patching in the fixed pure-Python files):

import ants
img1 = ants.image_read(ants.get_ants_data('r16'))
img2 = ants.image_read(ants.get_ants_data('r16'))
vecimg = ants.merge_channels([img1, img2], channels_first=True)

resampled = ants.resample_image(vecimg, (100, 100), True)
print(resampled.channels_first)  # True (was False before the fix)

smoothed = ants.smooth_image(vecimg, 1.0)
print(smoothed.channels_first)  # True (was False before the fix)

Worth noting: my first attempt at the smooth_image fix (just adding channels_first=image.channels_first to the existing merge_channels call, matching the pattern suggested when this was scoped out in #938's review) was still broken by the same loop-shadowing bug — caught by this live check, which is why the fix renames the loop variable there too rather than only adding the keyword argument.

I did not have a way to exercise ANTsImage.__getitem__'s has_components branch through the pip-installed wheel in the time available, but the change there is the same pattern (no loop-variable shadowing risk, since it's a list comprehension using self.channels_first directly, not a loop variable).

AI Usage Disclosure

This PR was put together with AI assistance (Claude Code). Every change was traced against the real source, verified live against the installed package as shown above, and reviewed by me before pushing.

resample_image's multi-component branch reassigned its own `image`
parameter inside the per-channel loop, so by the time
channels_first=image.channels_first ran after the loop, `image` was the
last split-channel component, which split_channels() always constructs
with channels_first=False. The explicit propagation looked correct but
was always a no-op. smooth_image's multi-component branch had the same
loop-variable shadowing, plus didn't even attempt to pass
channels_first to merge_channels. ANTsImage.__getitem__'s
has_components branch had the same omission.

Fixed by capturing channels_first before the loop (resample_image,
smooth_image) and renaming the loop variable so it can no longer
shadow the function's own `image` parameter, and by passing
channels_first=self.channels_first through in __getitem__.

Verified live: merging two images into a channels_first=True vector
image, then round-tripping through resample_image and smooth_image,
now preserves channels_first=True on the output (previously silently
flipped to False in both).

This is a follow-up to ANTsX#938, whose description explicitly reserves
"independent channels_first propagation defects in resample_image,
smooth_image, and multicomponent indexing" for later work.

Signed-off-by: Siddhardha Nanda <99672439+SID-6921@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings November 10, 2026 16:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

This branch has not been deployed

No deployments
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