Skip to content

Commit 6dc64c9

Browse files
committed
RF: get_norm_zooms -> get_zooms(units="canonical")
1 parent de9e71a commit 6dc64c9

File tree

4 files changed

+106
-31
lines changed

4 files changed

+106
-31
lines changed

nibabel/analyze.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -665,13 +665,22 @@ def get_base_affine(self):
665665

666666
get_best_affine = get_base_affine
667667

668-
def get_zooms(self):
669-
''' Get zooms from header
668+
def get_zooms(self, units='canonical', raise_unknown=False):
669+
''' Get zooms (spacing between voxels along each axis) from header
670+
671+
Parameters
672+
----------
673+
units : {'canonical', 'raw'}, optional
674+
Return zooms in "canonical" units of mm/sec for spatial/temporal or
675+
as raw values stored in header.
676+
raise_unkown : bool, optional
677+
If canonical units are requested and the units are ambiguous, raise
678+
a ``ValueError``
670679
671680
Returns
672681
-------
673-
z : tuple
674-
tuple of header zoom values
682+
zooms : tuple
683+
tuple of header zoom values
675684
676685
Examples
677686
--------
@@ -710,10 +719,6 @@ def set_zooms(self, zooms):
710719
pixdims = hdr['pixdim']
711720
pixdims[1:ndim + 1] = zooms[:]
712721

713-
def get_norm_zooms(self, raise_unknown=False):
714-
''' Get zooms in mm/s units '''
715-
return self.get_zooms()
716-
717722
def set_norm_zooms(self, zooms):
718723
''' Set zooms in mm/s units '''
719724
return self.set_zooms(zooms)

nibabel/freesurfer/mghformat.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -237,25 +237,45 @@ def _ndims(self):
237237
'''
238238
return 3 + (self._structarr['dims'][3] > 1)
239239

240-
def get_zooms(self):
240+
def get_zooms(self, units='canonical', raise_unknown=False):
241241
''' Get zooms from header
242242
243243
Returns the spacing of voxels in the x, y, and z dimensions.
244244
For four-dimensional files, a fourth zoom is included, equal to the
245-
repetition time (TR) in ms (see `The MGH/MGZ Volume Format
246-
<mghformat>`_).
245+
repetition time (TR).
246+
TR is stored in milliseconds (see `The MGH/MGZ Volume Format
247+
<mghformat>`_),
248+
so if ``units == 'raw'``, the fourth zoom will be in ms.
249+
If ``units == 'canonical'`` (default), the fourth zoom will be in
250+
seconds.
247251
248252
To access only the spatial zooms, use `hdr['delta']`.
249253
254+
Parameters
255+
----------
256+
units : {'canonical', 'raw'}, optional
257+
Return zooms in "canonical" units of mm/sec for spatial/temporal or
258+
as raw values stored in header.
259+
raise_unkown : bool, optional
260+
If canonical units are requested and the units are ambiguous, raise
261+
a ``ValueError``
262+
250263
Returns
251264
-------
252-
z : tuple
253-
tuple of header zoom values
265+
zooms : tuple
266+
tuple of header zoom values
254267
255268
.. _mghformat: https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat#line-82
256269
'''
270+
if units == 'canonical':
271+
tfactor = 0.001
272+
elif units == 'raw':
273+
tfactor = 1
274+
else:
275+
raise ValueError("`units` parameter must be 'canonical' or 'raw'")
276+
257277
# Do not return time zoom (TR) if 3D image
258-
tzoom = (self['tr'],) if self._ndims() > 3 else ()
278+
tzoom = (self['tr'] * tfactor,) if self._ndims() > 3 else ()
259279
return tuple(self._structarr['delta']) + tzoom
260280

261281
def set_zooms(self, zooms):
@@ -287,15 +307,6 @@ def set_zooms(self, zooms):
287307
''.format(zooms[3]))
288308
hdr['tr'] = zooms[3]
289309

290-
def get_norm_zooms(self, raise_unknown=False):
291-
''' Get zooms in mm/s units '''
292-
zooms = self.get_zooms()
293-
294-
if len(zooms) == 4:
295-
zooms = zooms[:3] + (zooms[3] / 1000,)
296-
297-
return zooms
298-
299310
def set_norm_zooms(self, zooms):
300311
if len(zooms) == 4:
301312
zooms = zooms[:3] + (zooms[3] * 1000,)

nibabel/nifti1.py

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,9 +1636,56 @@ def set_xyzt_units(self, xyz=None, t=None):
16361636
t_code = unit_codes[t]
16371637
self.structarr['xyzt_units'] = xyz_code + t_code
16381638

1639-
def get_norm_zooms(self, raise_unknown=False):
1640-
''' Get zooms in mm/s units '''
1641-
raw_zooms = self.get_zooms()
1639+
def get_zooms(self, units=None, raise_unknown=False):
1640+
''' Get zooms (spacing between voxels along each axis) from header
1641+
1642+
NIfTI1 headers may specify that zooms are encoded in units other than
1643+
mm and sec (see ``get_xyzt_units``).
1644+
Default behavior has been to return the raw zooms, and leave it to the
1645+
programmer to handle non-standard units.
1646+
However, most files indicate mm/sec units or have unspecified units,
1647+
and it is common practice to neglect specified units and assume all
1648+
files will be in mm/sec.
1649+
1650+
The default behavior for ``get_zooms`` will remain to return the raw
1651+
zooms until version 4.0, when it will change to return zooms in
1652+
canonical mm/sec units.
1653+
Because the default behavior will change, a warning will be given to
1654+
prompt programmers to specify whether they intend to retrieve raw
1655+
values, or values coerced into canonical units.
1656+
1657+
Parameters
1658+
----------
1659+
units : {'canonical', 'raw'}
1660+
Return zooms in "canonical" units of mm/sec for spatial/temporal or
1661+
as raw values stored in header.
1662+
raise_unkown : bool, optional
1663+
If canonical units are requested and the units are ambiguous, raise
1664+
a ``ValueError``
1665+
1666+
Returns
1667+
-------
1668+
zooms : tuple
1669+
tuple of header zoom values
1670+
1671+
'''
1672+
if units is None:
1673+
units = 'raw'
1674+
warnings.warn('Units not specified in `{}.get_zooms`. Returning '
1675+
'raw zooms, but default will change to canonical.\n'
1676+
'Please explicitly specify units parameter.'
1677+
''.format(self.__class__.__name__),
1678+
FutureWarning, stacklevel=2)
1679+
1680+
raw_zooms = super(Nifti1Header, self).get_zooms(units='raw',
1681+
raise_unknown=False)
1682+
1683+
if units == 'raw':
1684+
return raw_zooms
1685+
1686+
elif units != 'canonical':
1687+
raise ValueError("`units` parameter must be 'canonical' or 'raw'")
1688+
16421689
xyz_zooms = raw_zooms[:3]
16431690
t_zoom = raw_zooms[3] if len(raw_zooms) > 3 else None
16441691

nibabel/spatialimages.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,23 @@ def set_data_shape(self, shape):
228228
nzs = min(len(self._zooms), ndim)
229229
self._zooms = self._zooms[:nzs] + (1.0,) * (ndim - nzs)
230230

231-
def get_zooms(self):
231+
def get_zooms(self, units='canonical', raise_unknown=False):
232+
''' Get zooms (spacing between voxels along each axis) from header
233+
234+
Parameters
235+
----------
236+
units : {'canonical', 'raw'}, optional
237+
Return zooms in "canonical" units of mm/sec for spatial/temporal or
238+
as raw values stored in header.
239+
raise_unkown : bool, optional
240+
If canonical units are requested and the units are ambiguous, raise
241+
a ``ValueError``
242+
243+
Returns
244+
-------
245+
zooms : tuple
246+
Spacing between voxels along each axis
247+
'''
232248
return self._zooms
233249

234250
def set_zooms(self, zooms):
@@ -242,10 +258,6 @@ def set_zooms(self, zooms):
242258
raise HeaderDataError('zooms must be positive')
243259
self._zooms = zooms
244260

245-
def get_norm_zooms(self, raise_unknown=False):
246-
''' Get zooms in mm/s units '''
247-
return self.get_zooms()
248-
249261
def set_norm_zooms(self, zooms):
250262
''' Get zooms in mm/s units '''
251263
return self.set_zooms(zooms)

0 commit comments

Comments
 (0)