Skip to content

Commit 22f4286

Browse files
committed
RF: Derive affine in SpatialImage.transpose
Return original image if no transform is to be made
1 parent 69a5089 commit 22f4286

File tree

3 files changed

+38
-28
lines changed

3 files changed

+38
-28
lines changed

nibabel/funcs.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010
''' Processor functions for images '''
1111
import numpy as np
1212

13-
from .orientations import (io_orientation, inv_ornt_aff,
14-
OrientationError)
13+
from .orientations import io_orientation, OrientationError
1514
from .loadsave import load
1615

1716

@@ -206,24 +205,14 @@ def as_closest_canonical(img, enforce_diag=False):
206205
already has the correct data ordering, we just return `img`
207206
unmodified.
208207
'''
209-
aff = img.affine
210-
ornt = io_orientation(aff)
211-
if np.all(ornt == [[0, 1],
212-
[1, 1],
213-
[2, 1]]): # canonical already
214-
# however, the affine may not be diagonal
215-
if enforce_diag and not _aff_is_diag(aff):
216-
raise OrientationError('Transformed affine is not diagonal')
217-
return img
218-
shape = img.shape
219-
t_aff = inv_ornt_aff(ornt, shape)
220-
out_aff = np.dot(aff, t_aff)
221-
# check if we are going to end up with something diagonal
222-
if enforce_diag and not _aff_is_diag(aff):
208+
# Get the image class to transform the data for us
209+
img = img.transpose(io_orientation(img.affine))
210+
211+
# however, the affine may not be diagonal
212+
if enforce_diag and not _aff_is_diag(img.affine):
223213
raise OrientationError('Transformed affine is not diagonal')
224214

225-
# Get the image class to transform the data for us
226-
return img.transpose(ornt, out_aff)
215+
return img
227216

228217

229218
def _aff_is_diag(aff):

nibabel/nifti1.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
from .spm99analyze import SpmAnalyzeHeader
2828
from .casting import have_binary128
2929
from .pydicom_compat import have_dicom, pydicom as pdcm
30-
from .orientations import apply_orientation
3130

3231
# nifti1 flat header definition for Analyze-like first 348 bytes
3332
# first number in comments indicates offset in file header in bytes
@@ -1970,23 +1969,39 @@ def set_sform(self, affine, code=None, **kwargs):
19701969
else:
19711970
self._affine[:] = self._header.get_best_affine()
19721971

1973-
def transpose(self, ornt, new_aff):
1974-
# Override the default SpatialImage method so that we update dim_info
1975-
t_arr = apply_orientation(self.get_data(), ornt)
1972+
def transpose(self, ornt):
1973+
"""Apply an orientation change and return a new image
1974+
1975+
If image already has orientation, return the original image, unchanged
1976+
1977+
Parameters
1978+
----------
1979+
ornt : (n,2) orientation array
1980+
orientation transform. ``ornt[N,1]` is flip of axis N of the
1981+
array implied by `shape`, where 1 means no flip and -1 means
1982+
flip. For example, if ``N==0`` and ``ornt[0,1] == -1``, and
1983+
there's an array ``arr`` of shape `shape`, the flip would
1984+
correspond to the effect of ``np.flipud(arr)``. ``ornt[:,0]`` is
1985+
the transpose that needs to be done to the implied array, as in
1986+
``arr.transpose(ornt[:,0])``
1987+
"""
1988+
img = super(Nifti1Pair, self).transpose(ornt)
1989+
1990+
if img is self:
1991+
return img
19761992

19771993
# Also apply the transform to the dim_info fields
1978-
new_hdr = self.header.copy()
1979-
new_dim = list(new_hdr.get_dim_info())
1994+
new_dim = list(img.header.get_dim_info())
19801995
for idx, value in enumerate(new_dim):
19811996
# For each value, leave as None if it was that way,
19821997
# otherwise check where we have mapped it to
19831998
if value is None:
19841999
continue
19852000
new_dim[idx] = np.where(ornt[:, 0] == idx)[0]
19862001

1987-
new_hdr.set_dim_info(*new_dim)
2002+
img.header.set_dim_info(*new_dim)
19882003

1989-
return self.__class__(t_arr, new_aff, new_hdr)
2004+
return img
19902005

19912006

19922007
class Nifti1Image(Nifti1Pair):

nibabel/spatialimages.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@
141141
from .viewers import OrthoSlicer3D
142142
from .volumeutils import shape_zoom_affine
143143
from .deprecated import deprecate_with_version
144-
from .orientations import apply_orientation
144+
from .orientations import apply_orientation, inv_ornt_aff
145145

146146

147147
class HeaderDataError(Exception):
@@ -486,9 +486,11 @@ def orthoview(self):
486486
title=self.get_filename())
487487

488488

489-
def transpose(self, ornt, new_aff):
489+
def transpose(self, ornt):
490490
"""Apply an orientation change and return a new image
491491
492+
If image already has orientation, return the original image, unchanged
493+
492494
Parameters
493495
----------
494496
ornt : (n,2) orientation array
@@ -506,6 +508,10 @@ def transpose(self, ornt, new_aff):
506508
when re-orienting an image.
507509
"""
508510

511+
if np.array_equal(ornt, [[0, 1], [1, 1], [2, 1]]):
512+
return self
513+
509514
t_arr = apply_orientation(self.get_data(), ornt)
515+
new_aff = self.affine.dot(inv_ornt_aff(ornt, self.shape))
510516

511517
return self.__class__(t_arr, new_aff, self.header)

0 commit comments

Comments
 (0)