Add Image.new_like() for custom subclass support#1445
Open
fepegar wants to merge 2 commits into
Open
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
fepegar
force-pushed
the
1391-image-new-like
branch
from
April 1, 2026 23:07
6f365b0 to
c98633d
Compare
Add a new_like(tensor, affine) factory method to Image so that transforms creating new image instances work with custom subclasses that have different __init__ signatures. Extra dict keys (metadata like age, site, etc.) are automatically propagated. Only the two actual reconstruction call sites are changed: - Crop._crop_image: type(image)(...) → image.new_like(...) - build_image_from_reference: class_(...) → reference.new_like(...) Image.__copy__() now delegates to new_like() for loaded images. Fixes #1391 Co-authored-by: tcollins-hub <245905921+tcollins-hub@users.noreply.github.com> Co-authored-by: siddharth10ss <143159776+siddharth10ss@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
fepegar
force-pushed
the
1391-image-new-like
branch
from
April 1, 2026 23:08
c98633d to
23b30cf
Compare
Contributor
📖 Docs PreviewPreview of the documentation for this PR: 🔗 https://smokeshow.helpmanual.io/1z5n220n2y5x2r3o6x2f/ Built from eda78a5 |
Member
Author
|
@tcollins-hub, @siddharth10ss, would this work for you? |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds an Image.new_like() factory method as an extension point so transforms that need to create a new image instance can preserve custom Image subclasses whose __init__ signatures differ from TorchIO’s built-ins.
Changes:
- Add
Image.new_like(tensor, affine=None)and updateImage.__copy__()to use it for loaded images. - Update
Crop(copy_patch=True) andToReferenceSpace.from_tensorto construct images vianew_like()instead of calling constructors directly. - Add a dedicated test suite covering custom subclasses and the #1391 reproduction.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/torchio/data/image.py |
Introduces new_like() and updates copy semantics to support subclassing. |
src/torchio/transforms/preprocessing/spatial/crop.py |
Uses image.new_like(...) when creating cropped copies. |
src/torchio/transforms/preprocessing/spatial/to_reference_space.py |
Uses reference.new_like(...) when building an image from a tensor + reference. |
tests/transforms/test_custom_image_subclass.py |
Adds regression + behavior tests for custom subclasses and new_like(). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| type=image.type, | ||
| path=image.path, | ||
| ) | ||
| new_image.path = image.path |
| check_nans=self.check_nans, | ||
| reader=self.reader, | ||
| ) | ||
| new_image.path = self.path |
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 #1391
Problem
Transforms that create new image instances — specifically
Crop(withcopy_patch=True) andToReferenceSpace.from_tensor— reconstruct images by calling the constructor directly:This breaks for any
Imagesubclass whose__init__has a different signature (e.g., a requiredhistoryparameter):Solution
Add a
new_like(tensor, affine=None)factory method toImage. Transforms call this instead of the constructor directly. The base implementation works for all built-in types (Image,ScalarImage,LabelMap). Subclasses with custom__init__signatures override it:Scope
Only 2 call sites in the codebase actually reconstruct images via
type(image)(...):Crop._crop_image— whencopy_patch=Truebuild_image_from_reference— used byToReferenceSpace.from_tensorThese are the only places that needed fixing. Other spatial transforms (Pad, Resample, ToOrientation, Transpose) use in-place mutation (
image.set_data()+image.affine = ...), which already preserves the original object's type. Those are left untouched.Image.__copy__()was also updated to usenew_like()for loaded images, socopy.copy()now works for custom subclasses too.Changes
src/torchio/data/image.pynew_like(), rewrite__copy__()src/torchio/transforms/preprocessing/spatial/crop.pytype(image)(...)→image.new_like(...)src/torchio/transforms/preprocessing/spatial/to_reference_space.pyclass_(...)→reference.new_like(...)tests/transforms/test_custom_image_subclass.py