Comments (13)
Hi Matthew,
Thanks for spending time on this.
It seems like you guys want to have set_sform
and set_qform
be private methods because calling those methods directly causes inconsistencies in the image and header affine.
In [1]: import numpy as np
In [2]: import nibabel as nib
In [3]: aff = np.eye(4)
In [4]: vol = np.zeros((5,5,5))
In [6]: img = nib.Nifti1Image(vol, aff)
In [7]: hdr = img.get_header()
In [8]: hdr.set_sform(-aff, 1)
In [9]: hdr.get_best_affine()
Out[9]:
array([[-1., -0., -0., -0.],
[-0., -1., -0., -0.],
[-0., -0., -1., -0.],
[ 0., 0., 0., 1.]])
In [10]: img.update_header()
In [11]: hdr.get_best_affine()
Out[11]:
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
I personally think any consistency checks should be done when the affine gets modified and not on write because the following seems really unintuitive to me and I think it'll be confusing to users.
In [18]: hdr.set_sform(-aff, 1)
In [19]: hdr.get_sform()
Out[13]:
array([[-1., -0., -0., -0.],
[-0., -1., -0., -0.],
[-0., -0., -1., -0.],
[ 0., 0., 0., 1.]])
In [20]: nib.save(img, 'my_img.nii')
In [21]: hdr.get_sform()
Out[21]:
array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
I'm willing to spend some time on this, but it would help me to know how many ways the affine on an 'image' can get changed.
from nibabel.
Hi Bago,
On Mon, Dec 19, 2011 at 8:02 PM, MrBago
[email protected]
wrote:
Hi Matthew,
Thanks for spending time on this.It seems like you guys want to have
set_sform
andset_qform
be private methods because calling those methods directly causes inconsistencies in the image and header affine.In [1]: import numpy as np In [2]: import nibabel as nib In [3]: aff = np.eye(4) In [4]: vol = np.zeros((5,5,5)) In [6]: img = nib.Nifti1Image(vol, aff) In [7]: hdr = img.get_header() In [8]: hdr.set_sform(-aff, 1) In [9]: hdr.get_best_affine() Out[9]: array([[-1., -0., -0., -0.], [-0., -1., -0., -0.], [-0., -0., -1., -0.], [ 0., 0., 0., 1.]]) In [10]: img.update_header() In [11]: hdr.get_best_affine() Out[11]: array([[ 1., 0., 0., 0.], [ 0., 1., 0., 0.], [ 0., 0., 1., 0.], [ 0., 0., 0., 1.]])
I personally think any consistency checks should be done when the affine gets modified and not on write because the following seems really unintuitive to me and I think it'll be confusing to users.
In [18]: hdr.set_sform(-aff, 1) In [19]: hdr.get_sform() Out[13]: array([[-1., -0., -0., -0.], [-0., -1., -0., -0.], [-0., -0., -1., -0.], [ 0., 0., 0., 1.]]) In [20]: nib.save(img, 'my_img.nii') In [21]: hdr.get_sform() Out[21]: array([[ 1., 0., 0., 0.], [ 0., 1., 0., 0.], [ 0., 0., 1., 0.], [ 0., 0., 0., 1.]])
I'm willing to spend some time on this, but it would help me to know how many ways the affine on an 'image' can
Thanks for thinking about this.
The problems are two-fold:
The affine is separate from the header in general. For example an
Analyze image can contain any affine, but can't store one in the
header. Even for nifti, we can't use the same storage for the image
affine and the sform, because the sform is only 3 x 4.
We can't tell in general when the affine is modified. Consider:
img = load('some_image.nii')
img.get_affine()[0, 0] = 6
See you,
Matthew
from nibabel.
Ok, now I understand the scope of the problem better. I'm sure a more complete and elegant solution is possible, but maybe the simplest thing we can do is to create a keyword for the save function which will turn on/off update_header(). It's not that pretty but it'll allow a user to manually manipulate the header and make sure those values get used durring the save. Let me know what you think.
from nibabel.
On Wed, Dec 21, 2011 at 1:06 AM, MrBago
[email protected]
wrote:
Ok, now I understand the scope of the problem better. I'm sure a more complete and elegant solution is possible, but maybe the simplest thing we can do is to create a keyword for the save function which will turn on/off update_header(). It's not that pretty but it'll allow a user to manually manipulate the header and make sure those values get used durring the save. Let me know what you think.
I'm a bit reluctant to add keywords to 'save' just on the basis that
it could start getting rather cluttered if we carry on down that
track. Not completely against.
It would not be hard as things stand to prevent the affine updating
the header if the affine is the same as it was at image instantiation.
How far would that go towards solving the problem do you think?
from nibabel.
On 12/22/2011 05:43 AM, Matthew Brett wrote:
I'm a bit reluctant to add keywords to 'save' just on the basis that
it could start getting rather cluttered if we carry on down that
track. Not completely against.
I agree
It would not be hard as things stand to prevent the affine updating
the header if the affine is the same as it was at image instantiation.
How far would that go towards solving the problem do you think?I feel like that's unnecessarily complex without addressing the root of
the problem. I think the fix you've proposed already takes care of my
use case, and maybe I'm trying to solve a problem that doesn't exist.
Let me give this some more thought of-line (and give others smarter than
me a chance to think about it too). Also if others run into this issue
it'll give us a better idea of the use cases where this matters.
Bago
from nibabel.
Shouldn't the Nifti1 update_header just harmonize the affine to the sform and not touch the qform or the codes? Let the users set these header specific bits through the header object.
from nibabel.
After thinking about this some more, my above suggestion does not work if the sform_code is 0 (since it would never get updated).
The approach in the master branch (do nothing if the affine matches the header.get_best_affine()) seems like a good solution. I do wonder if the qform should really be getting overwritten when the affines don't match, but at least this can be avoided.
from nibabel.
On Tue, Feb 28, 2012 at 8:03 PM, moloney
[email protected]
wrote:
After thinking about this some more, my above suggestion does not work if the sform_code is 0 (since it would never get updated).
The approach in the master branch (do nothing if the affine matches the header.get_best_affine()) seems like a good solution. I do wonder if the qform should really be getting overwritten when the affines don't match, but at least this can be avoided.
Thanks for thinking about this.
The reason it works as it does is that I imagine some situation like this:
some_affine = np.eye(4)
data = np.zeros((2,3,4))
img = Nifti1Image(data, some_affine)
I'm imagining then that you'd want to set both of sform and qform -
because neither are set at the moment. Then imagine I have done some
registration that result in a new affine for the img:
reg_aff = some_registration(img, another_img)
and I want to set this new affine into the image:
img.get_affine()[:] = reg_aff
Now, I could mean - 'only set the sform to this affine leave the qform
as it is'. But I probably don't mean that, I probably mean 'the
affine for this image has changed, please set all the header fields
accordingly when I save the image'.
You can set just the sform (not the qform) with:
img.get_affine()[:] = reg_aff
img.get_header().set_sform(reg_aff)
because then the update_header check will see that the sform and
affine match. I realize this is rather complicated to keep in mind.
from nibabel.
Unfortunately I'm still running into issues with this qform/sform stuff. Here is the issue:
>>> aff = img.get_affine()
>>> aff[:] = np.diag([1.1, 1.1, 1.1, 1])
>>> hdr.set_qform(aff, 2)
>>> hdr.set_sform(aff, 2)
>>> img.update_header()
>>> hdr['qform_code']
array(0, dtype=int16)
I think it's happening because the affine is float64 and the sform is float32:
>>> aff == hdr.get_best_affine()
array([[False, True, True, True],
[ True, False, True, True],
[ True, True, False, True],
[ True, True, True, True]], dtype=bool)
>>> aff[:] = np.diag([1.1, 1.1, 1.1, 1]).astype('float32')
>>> aff == hdr.get_best_affine()
array([[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True],
[ True, True, True, True]], dtype=bool)
I've resorted to the following in order to be able to set the qform to match (as much as possible) the sform:
aff = img.get_affine()
aff[:] = np.diag([1.1, 1.1, 1.1, 1])
img.update_header()
aff[:] = hdr.get_best_affine()
hdr.set_qform(aff, 2)
from nibabel.
Seems like the code should be using something like numpy.allclose instead of comparing floats directly.
from nibabel.
On Thu, Mar 8, 2012 at 11:47 AM, moloney
[email protected]
wrote:
Seems like the code should be using something like numpy.allclose instead of comparing floats directly.
Sounds reasonable - care to review : #90 ?
Thanks a lot
from nibabel.
See discussion at #90 about how to solve sform / qform problem in a more general way.
from nibabel.
Closed by the pull request above
from nibabel.
Related Issues (20)
- numpy.AxisError: axis 1 is out of bounds for array of dimension 1 HOT 13
- Unresolved attribute reference warning in Pycharm HOT 4
- Nibabel converts nan to zero when saving a floating point image HOT 2
- Type checking issues HOT 9
- How to replace the voxel values based on a csv file and save it as a new nifti file?
- Reading CAT12 geometries HOT 6
- Loss of Data Precision Issue When Saving Nifti1Image HOT 2
- `file` constructor in `doc/source/devel/register_me.py` HOT 6
- Add test runners for non-x86/x64 architectures
- Segfaulting on test_array_interface_with_dtype and numpy 2.0-dev HOT 3
- 1 test fails: test_pkg_info HOT 3
- Request: stop throwing ExpiredDeprecationError HOT 23
- Add M1 runners
- Shape mismatch HOT 1
- Please port to Python3.12 HOT 3
- python-nibabel fails to build with Python 3.13: AttributeError: module 'logging' has no attribute 'warn'; indentation in docstrings mismatch, AssertionError HOT 2
- Is support for memory maps discontinued? HOT 2
- Might lead to MemoryError on i386 HOT 3
- Trying to access dlabel.nii dynamic field HOT 1
- Noisy UserWarning is thrown (`np.longdouble`) when importing `nibabel` with `numpy>=1.25` on WSL1 HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nibabel.