Skip to content

ENH: Add SimpleITK <-> ITK image conversion to the Python interface (supersedes #6021) - #6811

Open
hjmjohnson wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:enh-image-from-simpleitk
Open

ENH: Add SimpleITK <-> ITK image conversion to the Python interface (supersedes #6021)#6811
hjmjohnson wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
hjmjohnson:enh-image-from-simpleitk

Conversation

@hjmjohnson

Copy link
Copy Markdown
Member

Adds itk.image_from_simpleitk() and itk.simpleitk_from_image(), and teaches the filter decorator to accept a SimpleITK image wherever it accepts a NumPy array. Supersedes #6021 (@blowekamp), which stalled on the axis-order conflict that #6710 has since resolved.

No new dependency. SimpleITK is imported lazily inside the functions, so ITK builds and imports without it. The in-tree test uses a duck-typed stub and never imports SimpleITK — SimpleITK's superbuild builds ITK, so a test requiring it would close a cycle in the build graph, and SimpleITK is not present in ITK CI.

Related Status
Original PR this supersedes #6021
Axis-order conflict #6706
Order-explicit keys this builds on #6710
SimpleITK-side dual (open question) SimpleITK#2531
Why the bare spacing key cannot be used

image['spacing'] means (z, y, x) on an itk.Image and (x, y, z) on a SimpleITK Image. A converter reading it from one and writing it to the other silently reverses the spacing — the conflict reported in #6706, and what blocked #6021.

Geometry is therefore read through the order-explicit spacing_xyz / origin_xyz / direction_xyz keys from #6710, falling back to GetSpacing() / GetOrigin() / GetDirection(). Both are unambiguous.

Note that SimpleITK exposes no order-explicit keys today, so the accessor fallback carries every conversion; the key path is forward-looking, and starts working by itself if SimpleITK#2531 lands. A test asserts the two bare-key conventions still disagree, so this fails loudly rather than drifting if either toolkit changes.

Concerns from #6021, and how each is resolved
Concern Raised by Resolution
P1 — fallback never read GetSpacing()/GetOrigin()/GetDirection(); SimpleITK exposes methods, not dict keys. Vector images treated as scalar, geometry left at ITK defaults greptile _spatial_from_order_explicit() tries the _xyz key, then the accessor. Components come from GetNumberOfComponentsPerPixel(); dim from GetDimension(), not array.ndim
Missing image buffer start index @hjmjohnson (CHANGES_REQUESTED) A non-zero buffered-region index is carried as ITK_original_index and restored by the inverse. SimpleITK images always start at 0, so it cannot be represented directly
Store ImageRegion.m_Index as metadata @hjmjohnson / @blowekamp Implemented as above. The earlier "not needed" applied to sitk→itk, where SimpleITK enforces a zero index; this PR adds the itk→sitk direction, where it is needed

Metadata: every key is copied in both directions, and ITK_-prefixed entries are guaranteed to survive — a conversion failure on one of those raises rather than being silently dropped.

Testing

macOS 15 arm64, Release.

  • PythonSimpleITKProtocolTestPassed via ctest against this commit. Runs with SimpleITK present and with it blocked, confirming no hard dependency.
  • Full ITK Python suite — 167/176. The 9 failures are pre-existing: the identical 9 test numbers fail with pristine upstream extras.py/helpers.py. Causes are a broken VTK @rpath and a wrapping predating 002eebce7c4, neither related to this change.
  • Cross-toolkit round trip — 16/16 with ITK 6.0.0 and SimpleITK 3.0.0b1 built against that same ITK, in one interpreter. Covers geometry, vector, 2-D, pixels, metadata, index round trip, and physical-point agreement between the toolkits (which catches a transposed direction matrix that element-wise comparison misses). That suite lives outside both projects so neither gains a dependency.
  • pre-commit run --all-files passes on the branch tip.

Not validated on Linux or Windows.

@github-actions github-actions Bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Enhancement Improvement of existing methods or implementation area:Python wrapping Python bindings for a class type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct labels Aug 27, 2026
@hjmjohnson

Copy link
Copy Markdown
Member Author

@greptileai review

@greptile-apps

This comment was marked as resolved.

Comment thread Wrapping/Generators/Python/itk/support/extras.py Outdated
Comment thread Wrapping/Generators/Python/itk/support/extras.py
itk.image_from_simpleitk() and itk.simpleitk_from_image() convert between the
two toolkits, and the filter decorator accepts a SimpleITK image wherever it
accepts a NumPy array.

Geometry uses the order-explicit spatial keys from InsightSoftwareConsortium#6710, falling back to the
Get*() accessors. The bare 'spacing' key means (z,y,x) on an itk.Image and
(x,y,z) on a SimpleITK Image, so reading it would reverse the spacing (InsightSoftwareConsortium#6706).

SimpleITK images start at index 0, so the origin moves to the first stored
voxel and the index is carried as ITK_original_index; the inverse restores
both, keeping the pixels in the same physical location.

Supersedes InsightSoftwareConsortium#6021.

Co-Authored-By: Bradley Lowekamp <321061+blowekamp@users.noreply.github.com>
Co-Authored-By: Matt McCormick <25432+thewtex@users.noreply.github.com>
Co-Authored-By: Dzenan Zukic <1792121+dzenanz@users.noreply.github.com>
@hjmjohnson
hjmjohnson force-pushed the enh-image-from-simpleitk branch from 769fa94 to 46afb95 Compare August 28, 2026 00:52
@hjmjohnson
hjmjohnson marked this pull request as ready for review August 28, 2026 00:57

@thewtex thewtex left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM!

@thewtex
thewtex requested a review from blowekamp August 28, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Python wrapping Python bindings for a class type:Enhancement Improvement of existing methods or implementation type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants