ENH: Add SimpleITK <-> ITK image conversion to the Python interface (supersedes #6021) - #6811
Conversation
|
@greptileai review |
This comment was marked as resolved.
This comment was marked as resolved.
769fa94 to
46afb95
Compare
|
Thank for working on this and moving it forward! Do you have an active need to support the round trip origin that adds those special cases to this conversion code? Maybe this is not a requirement of these methods? [ EDIT: Additionally if the buffered region is not the largest possible region, then in this current form the round trip image has different region information.] I am still mulling over adding the _zyx _zyx keys to the SimpleITK class. The extra specification and verbosity is nice and clarifies things. It is unfortunate that the keys between ITK and SimpleITK are not natively compatible. But for SimpleITK maybe it would be simpler to just have the one consistent representation. I am still mulling over the best corse of action here. Thanks again! |
I do not have an active case because this was unusable previously :). I was trying to be complete and hoped for parity with C++ in the new features being added. I had missed considering the Buffer != Largest case, and I think we should throw a Python exception in that slightly unusual case for now (at least by default). Hans |
|
@blowekamp Filed your buffered-vs-largest observation as #6826, milestoned for ITK 6.0 RC1 so the guard lands before the API is frozen. Why RC1 rather than the backlogBoth functions are new here and unreleased, so adding a The frequency is genuinely low: Your |
|
Can this be merged, or are some further changes needed/desired (e.g. throw when regions are not all equal)? |
|
I don't think this round trip preservation of ITK meta-data and regions are useful and should be removed from the design goals of this feature. No filters copy meta-data from input to output. This preservation feature will not be frequently used because the meta-data will only be preserved in the trivial copy in and out or the limited "in-place" operations available. Keep things simple and remove unnecessary features that complicate behavior and could cause problems. |
I'm going to remove for now to get the minimal needed work in place. I diagree that the ability to preserve round trip meta-data and regions is useful. It was the "criteria for complete success" that I had in mind when first thinking about this. We are not there yet, and we can take that up later when more funding and resources are available. |
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>
46afb95 to
f831d4d
Compare
|
Pushed What was removed, and what deliberately stayedRemoved (−27 lines in
Kept:
The guardPlaced after Verified that it fires on a mismatched image and does not fire on a normally-allocated one. This is what #6826 proposed, so that issue is addressed here. |
Adds
(@blowekamp), which stalled on the axis-order conflict that
has since resolved.
itk.image_from_simpleitk()anditk.simpleitk_from_image(), and teaches the filter decorator to accept a SimpleITK image wherever it accepts a NumPy array. SupersedesNo 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.
Why the bare
spacingkey cannot be usedimage['spacing']means (z, y, x) on anitk.Imageand (x, y, z) on a SimpleITKImage. 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_xyzkeys from #6710, falling back toGetSpacing()/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
GetSpacing()/GetOrigin()/GetDirection(); SimpleITK exposes methods, not dict keys. Vector images treated as scalar, geometry left at ITK defaults_spatial_from_order_explicit()tries the_xyzkey, then the accessor. Components come fromGetNumberOfComponentsPerPixel();dimfromGetDimension(), notarray.ndimITK_original_indexand restored by the inverse. SimpleITK images always start at 0, so it cannot be represented directlyImageRegion.m_Indexas metadataMetadata: 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.
PythonSimpleITKProtocolTest— Passed via ctest against this commit. Runs with SimpleITK present and with it blocked, confirming no hard dependency.extras.py/helpers.py. Causes are a broken VTK@rpathand a wrapping predating002eebce7c4, neither related to this change.pre-commit run --all-filespasses on the branch tip.Not validated on Linux or Windows.