Skip to content

Commit 2222df0

Browse files
authored
Merge pull request #741 from effigies/fix/dim_info_reorientation
FIX: Correctly reorient dim_info when reorienting NIfTI images
2 parents b2f4300 + 7c37276 commit 2222df0

File tree

3 files changed

+57
-7
lines changed

3 files changed

+57
-7
lines changed

nibabel/nifti1.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2016,13 +2016,9 @@ def as_reoriented(self, ornt):
20162016
return img
20172017

20182018
# Also apply the transform to the dim_info fields
2019-
new_dim = list(img.header.get_dim_info())
2020-
for idx, value in enumerate(new_dim):
2021-
# For each value, leave as None if it was that way,
2022-
# otherwise check where we have mapped it to
2023-
if value is None:
2024-
continue
2025-
new_dim[idx] = np.where(ornt[:, 0] == idx)[0]
2019+
new_dim = [
2020+
None if orig_dim is None else int(ornt[orig_dim, 0])
2021+
for orig_dim in img.header.get_dim_info()]
20262022

20272023
img.header.set_dim_info(*new_dim)
20282024

nibabel/tests/test_nifti1.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
from nibabel.spatialimages import HeaderDataError
2929
from nibabel.tmpdirs import InTemporaryDirectory
3030
from ..freesurfer import load as mghload
31+
from ..orientations import aff2axcodes
3132

3233
from .test_arraywriters import rt_err_estimate, IUINT_TYPES
34+
from .test_orientations import ALL_ORNTS
3335
from .test_helpers import bytesio_filemap, bytesio_round_trip
3436
from .nibabel_data import get_nibabel_data, needs_nibabel_data
3537

@@ -1418,6 +1420,36 @@ def test_rt_bias(self):
14181420
bias_thresh = np.max([max_miss / np.sqrt(count), eps])
14191421
assert_true(np.abs(bias) < bias_thresh)
14201422

1423+
def test_reoriented_dim_info(self):
1424+
# Check that dim_info is reoriented correctly
1425+
arr = np.arange(24).reshape((2, 3, 4))
1426+
# Start as RAS
1427+
aff = np.diag([2, 3, 4, 1])
1428+
simg = self.single_class(arr, aff)
1429+
for freq, phas, slic in ((0, 1, 2),
1430+
(0, 2, 1),
1431+
(1, 0, 2),
1432+
(2, 0, 1),
1433+
(None, None, None),
1434+
(0, 2, None),
1435+
(0, None, None),
1436+
(None, 2, 1),
1437+
(None, None, 1),
1438+
):
1439+
simg.header.set_dim_info(freq, phas, slic)
1440+
fdir = 'RAS'[freq] if freq is not None else None
1441+
pdir = 'RAS'[phas] if phas is not None else None
1442+
sdir = 'RAS'[slic] if slic is not None else None
1443+
for ornt in ALL_ORNTS:
1444+
rimg = simg.as_reoriented(np.array(ornt))
1445+
axcode = aff2axcodes(rimg.affine)
1446+
dirs = ''.join(axcode).replace('P', 'A').replace('I', 'S').replace('L', 'R')
1447+
new_freq, new_phas, new_slic = rimg.header.get_dim_info()
1448+
new_fdir = dirs[new_freq] if new_freq is not None else None
1449+
new_pdir = dirs[new_phas] if new_phas is not None else None
1450+
new_sdir = dirs[new_slic] if new_slic is not None else None
1451+
assert_equal((new_fdir, new_pdir, new_sdir), (fdir, pdir, sdir))
1452+
14211453

14221454
@runif_extra_has('slow')
14231455
def test_large_nifti1():

nibabel/tests/test_orientations.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@
8383
OUT_ORNTS = [np.array(ornt) for ornt in OUT_ORNTS]
8484

8585

86+
_LABELS = ['RL', 'AP', 'SI']
87+
ALL_AXCODES = [(_LABELS[i0][j0], _LABELS[i1][j1], _LABELS[i2][j2])
88+
for i0 in range(3) for i1 in range(3) for i2 in range(3)
89+
if i0 != i1 != i2 != i0
90+
for j0 in range(2) for j1 in range(2) for j2 in range(2)]
91+
92+
ALL_ORNTS = [[[i0, j0], [i1, j1], [i2, j2]]
93+
for i0 in range(3) for i1 in range(3) for i2 in range(3)
94+
if i0 != i1 != i2 != i0
95+
for j0 in [1, -1] for j1 in [1, -1] for j2 in [1, -1]]
96+
97+
8698
def same_transform(taff, ornt, shape):
8799
# Applying transformations implied by `ornt` to a made-up array
88100
# ``arr`` of shape `shape`, results in ``t_arr``. When the point
@@ -125,6 +137,10 @@ def test_apply():
125137
apply_orientation,
126138
a,
127139
[[0, 1], [np.nan, np.nan], [2, 1]])
140+
shape = np.array(a.shape)
141+
for ornt in ALL_ORNTS:
142+
t_arr = apply_orientation(a, ornt)
143+
assert_array_equal(a.shape, np.array(t_arr.shape)[np.array(ornt)[:, 0]])
128144

129145

130146
def test_flip_axis():
@@ -282,6 +298,9 @@ def test_ornt2axcodes():
282298
# As do directions not in range
283299
assert_raises(ValueError, ornt2axcodes, [[0, 0]])
284300

301+
for axcodes, ornt in zip(ALL_AXCODES, ALL_ORNTS):
302+
assert_equal(ornt2axcodes(ornt), axcodes)
303+
285304

286305
def test_axcodes2ornt():
287306
# Go from axcodes back to orientations
@@ -340,6 +359,9 @@ def test_axcodes2ornt():
340359
assert_raises(ValueError, axcodes2ornt, 'blD', ('SD', 'BF', 'lD'))
341360
assert_raises(ValueError, axcodes2ornt, 'blD', ('SD', 'SF', 'lD'))
342361

362+
for axcodes, ornt in zip(ALL_AXCODES, ALL_ORNTS):
363+
assert_array_equal(axcodes2ornt(axcodes), ornt)
364+
343365

344366
def test_aff2axcodes():
345367
assert_equal(aff2axcodes(np.eye(4)), tuple('RAS'))

0 commit comments

Comments
 (0)