Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 6, 2026

Description

itk.image_from_array() incorrectly preserved the original array shape when given F-contiguous inputs (e.g., array.T), while itk.image_view_from_array() correctly used the transposed shape. This inconsistency broke user expectations and made the two functions behave differently for the same input.

Root cause: Double reversal in shape handling

  • Python code unconditionally reversed shape: ndarr.shape[::-1]
  • C++ code reversed again for F-contiguous buffers
  • Net effect: original shape preserved instead of transposed

Fix: Conditional shape reversal based on contiguity

  • C-contiguous: reverse in Python (C++ expects ITK order)
  • F-contiguous: pass as-is (C++ handles reversal)

This matches the existing vector image logic and aligns both functions.

Changes

  • Modules/Bridge/NumPy/wrapping/PyBuffer.i.in: Added contiguity check before shape reversal in GetImageViewFromArray()
  • Wrapping/Generators/Python/Tests/extras.py: Added tests for transposed array handling with black-compliant formatting

Example

import itk
import numpy as np

array = np.empty((1, 2, 3))

# Before fix:
itk.image_from_array(array.T).shape    # (1, 2, 3) - WRONG
itk.image_view_from_array(array.T).shape  # (3, 2, 1) - correct

# After fix:
itk.image_from_array(array.T).shape    # (3, 2, 1) - correct
itk.image_view_from_array(array.T).shape  # (3, 2, 1) - correct

PR Checklist

  • No API changes were made (or the changes have been approved)
  • No major design changes were made (or the changes have been approved)
  • Added test (or behavior not changed)
  • Updated API documentation (or API not changed)
  • Added license to new files (if any)
  • Added Python wrapping to new files (if any) as described in ITK Software Guide Section 9.5
  • Added ITK examples for all new major features (if any)
Original prompt

This section details on the original issue you should resolve

<issue_title>Unexpected behavior of itk.image_from_array when passing array.T</issue_title>
<issue_description>

Hi, and thanks again for making ITK!

Description

The shape of an image created with itk.image_from_array is unexpected when the input is not a contiguous array. I discovered this when passing array.T and was surprised when the shape was the same as for array. The issue doesn't happen with itk. image_view_from_array.

Steps to Reproduce

import itk
import numpy as np

array = np.empty((1, 2, 3))

print(f"{array.shape = }")
print()
print(f"{itk.image_from_array(array).shape = }")
print(f"{itk.image_from_array(array.T).shape = }")
print(f"{itk.image_from_array(array.T.copy()).shape = }")
print()
print(f"{itk.image_view_from_array(array).shape = }")
print(f"{itk.image_view_from_array(array.T).shape = }")
print(f"{itk.image_view_from_array(array.T.copy()).shape = }")
print()
print(f"{array.flags['C_CONTIGUOUS'] = }")
print(f"{array.T.flags['C_CONTIGUOUS'] = }")
print(f"{array.T.copy().flags['C_CONTIGUOUS'] = }")
print()
print(f"{array.flags['F_CONTIGUOUS'] = }")
print(f"{array.T.flags['F_CONTIGUOUS'] = }")
print(f"{array.T.copy().flags['F_CONTIGUOUS'] = }")

Expected behavior

I expected reversed shapes for itk.image_from_array(array) and itk.image_from_array(array.T).

Actual behavior (output of script above)

array.shape = (1, 2, 3)

itk.image_from_array(array).shape = (1, 2, 3)
itk.image_from_array(array.T).shape = (1, 2, 3)  # I expected (3, 2, 1) here!
itk.image_from_array(array.T.copy()).shape = (3, 2, 1)

itk.image_view_from_array(array).shape = (1, 2, 3)
itk.image_view_from_array(array.T).shape = (3, 2, 1)
itk.image_view_from_array(array.T.copy()).shape = (3, 2, 1)

array.flags['C_CONTIGUOUS'] = True
array.T.flags['C_CONTIGUOUS'] = False
array.T.copy().flags['C_CONTIGUOUS'] = True

array.flags['F_CONTIGUOUS'] = False
array.T.flags['F_CONTIGUOUS'] = True
array.T.copy().flags['F_CONTIGUOUS'] = False

Reproducibility

Always.

Versions

$ python -c "import numpy; print(numpy.__version__)"
1.26.2

$ python -c "import itk; print(itk.Version.GetITKVersion())"
5.3.0

Environment

$ python <(curl -s https://raw.githubusercontent.com/fepegar/torchio/main/print_system.py)
Platform:   macOS-14.0-arm64-arm-64bit
[...]
Python:     3.11.5 (main, Sep 11 2023, 08:31:25) [Clang 14.0.6 ]

</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Fix unexpected behavior of itk.image_from_array with array.T BUG: Fix image_from_array shape handling for F-contiguous arrays Feb 6, 2026
Copilot AI requested a review from thewtex February 6, 2026 21:50
@hjmjohnson hjmjohnson force-pushed the copilot/fix-itk-image-from-array-issue branch from eb57af4 to 71ba10c Compare February 9, 2026 14:48
@github-actions github-actions bot added type:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances 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 area:Bridge Issues affecting the Bridge module labels Feb 9, 2026
The issue was that GetImageViewFromArray always reversed the shape for
non-vector images, regardless of whether the array was C-contiguous or
F-contiguous. However, the C++ code reverses the shape again for F-contiguous
arrays, resulting in a double reversal.

The fix: Only reverse the shape in Python for C-contiguous arrays. For
F-contiguous arrays, pass the shape as-is to C++, which will handle the
reversal there.

Added comprehensive test cases for both image_from_array and
image_view_from_array with transposed arrays.

Co-authored-by: Matthew McCormick <[email protected]>
@hjmjohnson hjmjohnson force-pushed the copilot/fix-itk-image-from-array-issue branch from 71ba10c to 5167f98 Compare February 9, 2026 14:51
@thewtex
Copy link
Member

thewtex commented Feb 10, 2026

@copilot address failing ci tests

Apply black code formatter's preferred style for multi-line assertions
with continuation. This addresses the pre-commit CI failure.

Co-authored-by: thewtex <[email protected]>
Copy link
Contributor Author

Copilot AI commented Feb 10, 2026

@copilot address failing ci tests

Fixed in 7c49c8a. The pre-commit failure was due to black formatting - the test assertions now use black's preferred multi-line style. The macOS CI failures appear to be transient GitHub API errors (500/503) during git fetch, not related to the code changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Bridge Issues affecting the Bridge module area:Python wrapping Python bindings for a class type:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances 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.

Unexpected behavior of itk.image_from_array when passing array.T

2 participants