-
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?
Conversation
f5435f5
to
2bfc8d7
Compare
Codecov ReportBase: 92.40% // Head: 92.18% // Decreases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #567 +/- ##
==========================================
- Coverage 92.40% 92.18% -0.22%
==========================================
Files 98 98
Lines 12248 12326 +78
Branches 2516 2546 +30
==========================================
+ Hits 11318 11363 +45
- Misses 611 630 +19
- Partials 319 333 +14
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
468397b
to
c112e26
Compare
c112e26
to
925d5f9
Compare
925d5f9
to
976eace
Compare
976eace
to
bddf15c
Compare
1da0097
to
dcc71f1
Compare
This is ready for review. All behavior tested. |
Just a bump on this, now the holidays are over. |
dcc71f1
to
ad9fc49
Compare
I hate to say it - but would you mind putting a test into I'm suffering slightly about this one, because we otherwhere make our outputs canonical - for example, we make our affines point to RAS+ space, for DICOM. So it seems kindve odd to let the formats do whatever with the zooms, and fix it with this function. I guess it's too late to switch nifti / freesurfer to (mm, mm, mm, seconds) ? How about |
Or a flag to |
Not too late for MGHHeader, since we haven't released with TR as zooms[3], but yeah, NIFTI uses raw zooms without correcting for units. Unless we want to treat that as a bug, but I think people will be depending on it. We could deprecate get_zooms, or switch to a keyword argument to specify raw or canonical. Finally, I'm okay with get_canonical_zooms, but it is getting long. Does it make sense to move to a canonical zooms property? Or even header.zooms that behaves canonically, combined with a get/set_zooms deprecation that warns of new semantics. And sure, I'll add tests. |
I believe I avoided using a property on the basis that the setter would also modify the header (at least, it does now). So, it would break the property manifesto : https://github.com/nipy/nibabel/wiki/property_manifesto I could imagine another model, where we left the header unmodified from its load state, and stored things like zooms etc inside the image, but that would be an API break. Could you say more about what people are depending on? Do you think that some people currently have meters set in their header, but are using the units as mm (for example)? |
Okay. So no property. I'd be okay with doing the option to And an example of depending on current behavior: zooms = np.array(reoriented.header.get_zooms()[:3])
xyz_unit = img.header.get_xyzt_units()[0]
atol = {'meter': 1e-5, 'mm': 0.01, 'micron': 10}[xyz_unit]
rescale = not np.allclose(zooms, target_zooms, atol=atol) (Adapted from https://github.com/poldracklab/fmriprep/blob/682b507c141254a51316b2367f9834708eb4409e/fmriprep/interfaces/images.py#L236-L256) Here we took into account the fact that the zooms may not be in mm. If the zooms start being mm but |
Right - but I guess the snippet leaves open whether anyone actually has micron etc nifti images ... A flag seems like the right way to go. I think we should also default Freesurfer to using seconds - what do you think? |
Yes, that's true. I've seen someone say they have ms TR images (they ran into issues with an FSL tool that assumed sec), but I don't know if I've ever heard of a meter image in the wild. So how about a For nifti and any others where we are not guaranteed that Do you know MINC units off the top of your head? I think I had a look but couldn't find them. |
Does bring up a question of |
A thing I just thought about: If the zooms are in microns, then the affine is presumably from VOX -> RAS (um), right? Do we need to account for that at all? |
@matthew-brett I have some unpushed changes in the pipeline*, but if you have a minute to give your thoughts on the API issues I brought up in the last three comments, I'd appreciate it.
|
4b53011
to
3cd8618
Compare
- Switch 'canonical' to 'norm' for brevity
3cd8618
to
98e43a0
Compare
Because most NIfTI files are in mm+s units, it's pretty easy to write code that breaks on nonstandard units. This PR adds a
get_norm_zooms
method to spatial image headers that always returns zooms scaled to mm+s, based on metadata when available.The basic API is:
Edit:
With MGHHeader encoding TR in milliseconds (see snippet), being able to access zooms in standard units across image types seems even more like a good idea.
nibabel/nibabel/freesurfer/mghformat.py
Lines 240 to 246 in b8545ef
I've also added a
set_norm_zooms()
that takes zooms in mm/s and applies any necessary transformations to set the headers correctly to ensure a lossless round-trip withget_norm_zooms
.