Skip to content

Commit c604a16

Browse files
committed
RF: get_norm_zooms -> get_zooms(units="canonical")
1 parent dcd9843 commit c604a16

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
@@ -664,13 +664,22 @@ def get_base_affine(self):
664664

665665
get_best_affine = get_base_affine
666666

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

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

nibabel/freesurfer/mghformat.py

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

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

262282
def set_zooms(self, zooms):
@@ -288,15 +308,6 @@ def set_zooms(self, zooms):
288308
''.format(zooms[3]))
289309
hdr['tr'] = zooms[3]
290310

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

nibabel/nifti1.py

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

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

nibabel/spatialimages.py

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

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

235251
def set_zooms(self, zooms):
@@ -243,10 +259,6 @@ def set_zooms(self, zooms):
243259
raise HeaderDataError('zooms must be positive')
244260
self._zooms = zooms
245261

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

0 commit comments

Comments
 (0)