-
Notifications
You must be signed in to change notification settings - Fork 258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: Add get/set_zooms(units='norm') to manipulate zooms in mm/s units #567
base: master
Are you sure you want to change the base?
Changes from all commits
3f3b450
d26acfb
de9323c
5c30366
4b86d3e
eb1d8ff
6ba8b66
1357a3b
096da88
798fc4e
f31aba5
27234c3
8899bc7
da54665
1620f31
5d96f5c
233f7f0
4babf08
6cd83f7
94cbd0d
cfc5abe
3562921
d9199ca
98e43a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -578,8 +578,10 @@ def get_frame_affine(self, frame=0): | |
z_off]) | ||
return aff | ||
|
||
def get_zooms(self, frame=0): | ||
def get_zooms(self, frame=0, units='norm', raise_unknown=False): | ||
"""returns zooms ...pixdims""" | ||
if units not in ('norm', 'raw'): | ||
raise ValueError("`units` parameter must be 'norm' or 'raw'") | ||
subhdr = self.subheaders[frame] | ||
x_zoom = subhdr['x_pixel_size'] * 10 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wasn't sure whether to make |
||
y_zoom = subhdr['y_pixel_size'] * 10 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -237,40 +237,75 @@ def _ndims(self): | |
""" | ||
return 3 + (self._structarr['dims'][3] > 1) | ||
|
||
def get_zooms(self): | ||
def get_zooms(self, units='norm', raise_unknown=False): | ||
""" Get zooms from header | ||
|
||
Returns the spacing of voxels in the x, y, and z dimensions. | ||
For four-dimensional files, a fourth zoom is included, equal to the | ||
repetition time (TR) in ms (see `The MGH/MGZ Volume Format | ||
<mghformat>`_). | ||
repetition time (TR). | ||
TR is stored in milliseconds (see `The MGH/MGZ Volume Format | ||
<mghformat>`_), | ||
so if ``units == 'raw'``, the fourth zoom will be in ms. | ||
If ``units == 'norm'`` (default), the fourth zoom will be in | ||
seconds. | ||
|
||
To access only the spatial zooms, use `hdr['delta']`. | ||
|
||
Parameters | ||
---------- | ||
units : {'norm', 'raw'}, optional | ||
Return zooms in normalized units of mm/sec for spatial/temporal or | ||
as raw values stored in header. | ||
raise_unkown : bool, optional | ||
If normalized units are requested and the units are ambiguous, raise | ||
a ``ValueError`` | ||
|
||
Returns | ||
------- | ||
z : tuple | ||
tuple of header zoom values | ||
zooms : tuple | ||
tuple of header zoom values | ||
|
||
.. _mghformat: https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat#line-82 | ||
""" | ||
if units == 'norm': | ||
tfactor = 0.001 | ||
elif units == 'raw': | ||
tfactor = 1 | ||
else: | ||
raise ValueError("`units` parameter must be 'norm' or 'raw'") | ||
|
||
# Do not return time zoom (TR) if 3D image | ||
tzoom = (self['tr'],) if self._ndims() > 3 else () | ||
tzoom = (self['tr'] * tfactor,) if self._ndims() > 3 else () | ||
return tuple(self._structarr['delta']) + tzoom | ||
|
||
def set_zooms(self, zooms): | ||
def set_zooms(self, zooms, units='norm'): | ||
""" Set zooms into header fields | ||
|
||
Sets the spacing of voxels in the x, y, and z dimensions. | ||
For four-dimensional files, a temporal zoom (repetition time, or TR, in | ||
ms) may be provided as a fourth sequence element. | ||
For four-dimensional files, a temporal zoom (repetition time, or TR) | ||
may be provided as a fourth sequence element. | ||
|
||
TR is stored in milliseconds (see `The MGH/MGZ Volume Format | ||
<mghformat>`_), | ||
so if ``units == 'raw'``, the fourth zoom will be interpreted as ms | ||
and stored unmodified. | ||
If ``units == 'norm'`` (default), the fourth zoom will be interpreted | ||
as seconds, and converted to ms before storing in the header. | ||
|
||
Parameters | ||
---------- | ||
zooms : sequence | ||
sequence of floats specifying spatial and (optionally) temporal | ||
zooms | ||
units : {'norm', 'raw'}, optional | ||
Zooms are specified in normalized units of mm/sec for | ||
spatial/temporal dimensions or as raw values to be stored in | ||
header. | ||
|
||
.. _mghformat: https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat#line-82 | ||
""" | ||
if units not in ('norm', 'raw'): | ||
raise ValueError("`units` parameter must be 'norm' or 'raw'") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. too frequent of a code pattern. In current design I guess the only way to mitigate is to come up with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could do something like that. |
||
hdr = self._structarr | ||
zooms = np.asarray(zooms) | ||
ndims = self._ndims() | ||
|
@@ -283,7 +318,13 @@ def set_zooms(self, zooms): | |
if len(zooms) == 4: | ||
if zooms[3] < 0: | ||
raise HeaderDataError(f'TR must be non-negative; got {zooms[3]}') | ||
hdr['tr'] = zooms[3] | ||
if units == 'norm': | ||
tfactor = 1000 | ||
elif units == 'raw': | ||
tfactor = 1 | ||
else: | ||
raise ValueError("`units` parameter must be 'norm' or 'raw'") | ||
hdr['tr'] = zooms[3] * tfactor | ||
|
||
def get_data_shape(self): | ||
""" Get shape of data | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps using
units='norm'
in both cases would be better, as it would also entail setting sensible units for NIfTI. But that may be making a bad assumption if you're in a non-temporal 4th dimension case (ppm, rads, hz).