ENH: Add SimpleITK Image to ITK Image conversion support#6021
Conversation
|
@blowekamp I made a note this morning that this was going to be needed :)! You must have heard my thoughts! |
|
@dzenanz Raised this issue here: SimpleITK/SimpleITK#2531 |
hjmjohnson
left a comment
There was a problem hiding this comment.
Can you comment on the missing "Image buffer start index" that is missing?
- Implement image_from_simpleitk() function for converting SimpleITK images to ITK images - Support 2D, 3D, and multi-component (vector) images - Preserve spacing, origin, and direction metadata - Preserve MetaData dictionary entries - Integrate SimpleITK support into filter auto-conversion decorator - Add comprehensive tests for conversion functionality
f3b51ac to
98916f9
Compare
|
This feature ran into a issue/block with the ITK dictionary keys unexpectedly return attributes in numpy order and not ITK order. |
|
I replicated the ordering blocker with released wheels (itk 5.4.6 + SimpleITK 2.5.5): ITK's Standalone replication script (needs only Replication results3-D image, spacing (1, 2, 3), origin (5, 10, 15) in x,y,z:
So ITK is also internally inconsistent: The Feeding this PR's generic-reader pattern (read Separate finding: against released SimpleITK 2.5.5, Possible paths forward
|
|
| Filename | Overview |
|---|---|
| Wrapping/Generators/Python/Tests/extras.py | Adds SimpleITK conversion coverage for scalar, vector, metadata, and filter auto-conversion paths. |
| Wrapping/Generators/Python/itk/support/extras.py | Adds image_from_simpleitk, but real SimpleITK spatial metadata is not read through the implemented generic key fallback. |
| Wrapping/Generators/Python/itk/support/helpers.py | Extends the array-like conversion decorator to accept SimpleITK images and return ITK outputs without reconversion. |
Sequence Diagram
%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Caller
participant Decorator as accept_array_like_xarray_torch
participant Converter as itk.image_from_simpleitk
participant Filter as ITK filter
Caller->>Decorator: filter(SimpleITK.Image)
Decorator->>Converter: convert input image
Converter-->>Decorator: itk.Image / itk.VectorImage
Decorator->>Filter: invoke with ITK image
Filter-->>Decorator: ITK output
Decorator-->>Caller: ITK output
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Caller
participant Decorator as accept_array_like_xarray_torch
participant Converter as itk.image_from_simpleitk
participant Filter as ITK filter
Caller->>Decorator: filter(SimpleITK.Image)
Decorator->>Converter: convert input image
Converter-->>Decorator: itk.Image / itk.VectorImage
Decorator->>Filter: invoke with ITK image
Filter-->>Decorator: ITK output
Decorator-->>Caller: ITK output
Comments Outside Diff (1)
-
General comment
image_from_simpleitk does not obtain pixel arrays from real SimpleITK images
- Bug
- The generated PR test-plan harness used a real
SimpleITK.Image([12, 8], sitk.sitkFloat32)and executed the changed repo implementation ofimage_from_simpleitk(). It failed immediately duringitk.image_view_from_array(array), before metadata or filter auto-conversion could be validated. The stack trace shows ITK attempteditk.Image[itk.D, 1], which is consistent withnp.array(sitk_image)not returning the expected 2D float pixel buffer for SimpleITK images.
- The generated PR test-plan harness used a real
- Cause
image_from_simpleitk()reads pixels witharray = np.array(sitk_image). Real SimpleITK images do not expose their pixel buffer through NumPy's generic array protocol in the required shape/dtype; SimpleITK's supported API isSimpleITK.GetArrayFromImage()/GetArrayViewFromImage(). As a result, scalar 2D images are misinterpreted as a 1D double/object-like array and conversion fails.
- Fix
- Use SimpleITK's image array API when the input is a SimpleITK image, e.g.
sitk.GetArrayFromImage(sitk_image), while preserving the intended vector-image channel layout. Keep the generic path only for objects that actually provide a valid ndarray via__array__, and add a runtime test that checks the array shape/dtype before callingitk.image_view_from_array().
- Use SimpleITK's image array API when the input is a SimpleITK image, e.g.
- Bug
Reviews (1): Last reviewed commit: "ENH: Add SimpleITK Image to ITK Image co..." | Re-trigger Greptile
| else: | ||
| # Probe spatial keys directly (e.g. SimpleITK 3.x supports [] but not keys()) | ||
| keys = [] | ||
| for k in spatial_keys: | ||
| try: | ||
| sitk_image[k] | ||
| keys.append(k) | ||
| except (KeyError, TypeError, AttributeError): | ||
| pass | ||
| # Collect MetaData keys via dedicated accessor if available | ||
| if hasattr(sitk_image, "GetMetaDataKeys"): | ||
| keys.extend(sitk_image.GetMetaDataKeys()) | ||
|
|
||
| if "spacing" in keys: | ||
| spacing = sitk_image["spacing"] | ||
| dim = len(spacing) |
There was a problem hiding this comment.
Use SimpleITK getters
The fallback path never reads GetSpacing(), GetOrigin(), or GetDirection() from real SimpleITK.Image objects, because SimpleITK exposes those as methods rather than image['spacing'] / keys(). With only GetMetaDataKeys() added to keys, spacing is absent, so dim stays as array.ndim, vector images are treated as scalar 3D images, and spatial metadata is left at ITK defaults; the new spacing/origin/direction tests fail against current SimpleITK.
Context Used: AGENTS.md (source)
Artifacts
- Contains supporting evidence from the run (text/x-python; charset=utf-8).
- Keeps the command output available without making the summary code-heavy.
This PR introduces a "generic" interface for an "itk-like" python image object. The itk-like object can be converted to a numpy array and contains "spacing", "direction", and "origin" keys. This should be an interface both ITK and SimpleITK images provide.
Any thoughts on this type of interface?
PR Checklist
Refer to the ITK Software Guide for
further development details if necessary.