-
Notifications
You must be signed in to change notification settings - Fork 160
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
to_nibabel() produces wrong transforms #52
Comments
very nice find. a pull request would be helpful. it's probably just changing some indexing somewhere in the function |
As for the pull request, I'm not really sure where to fix this issue (prolly somewhere in the itkNiftiImageIO.cxx). As far as I understand, the direction and origin are parsed from the q_form without paying respect to quatern_b, quatern_c and quatern_d. For my current code I wrote a wrapper to replace ants.from_nibabel()
This however assumes 3D data and Nifti1 headers. |
indeed, i am not sure where you would fix this either. when i search: https://github.com/ANTsX/ANTsPy/search?q=get_qform&unscoped_q=get_qform i dont find any code in ANTsPy. thoughts? |
When I understand the code correctly, the direction, origin and spacing is derived from the ITK function itk::ImageIOBase::ReadImageInformation() in ANTsPy/ants/lib/LOCAL_antsImageHeaderInfo.cxx So this has to be an issue in the used ITK version. |
a reproducible / self-contained example of this problem:
|
the problem may be resolvable by alterations to this bit of code: ANTsPy/ants/utils/convert_nibabel.py Lines 18 to 21 in ad7fcd2
|
The problem is, that the metadata already mismatches upon loading the image via ants.image_read().
|
this particular difference may be the difference between LPS vs whatever nibabel uses. |
This issue is not nibabel related, since the qform is saved within the nifti header and should be parsed the same way in all implementations. I checked the values within SPM and MRIcroN and they are the same as the nibabel output, so there has to be an issue by extracting the values via the ReadImageInformation(). As reading and writing through ITK methods results in correct qforms, my guess is that ITK stores the quatern_b, quatern_c and quatern_d values from the header as well to correct the directions. |
can you share the image you are using ( upload to issue ) so we can be on the same page. |
upon further reflection, i think that this is just an image orientation difference - ie a difference in coordinate systems (itk uses LPS). @cookpa - can you briefly comment and / or suggest a relevant link ? |
ITK uses LPS coordinates and NIFTI RAS. This is handled in the I/O, when ITK converts qform into a direction cosine matrix or writes a cosine matrix back out as a qform. See methods According to this page https://nipy.org/nibabel/coordinate_systems.html NiBabel always wants RAS coordinates so I think it should be safe to apply the same conversion steps in the Some more on this: https://itk.org/Doxygen/html/classitk_1_1ImageBase.html#a23ebc76de3b60bb1eeabf66cd4dabc48 This is the base ITK class that handles voxel to physical space conversion. It references this page https://itk.org/Wiki/Proposals:Orientation#Some_notes_on_the_DICOM_convention_and_current_ITK_usage |
more discussion here: https://discourse.itk.org/t/nifti-orientation-issues/431/2 it doesnt "convert images" ... rather, the reference frame is interpreted as LPS. the issue here is, i think, that the ANTsPy "to_nibabel" function is probably wrong. |
To make a long story short: ITK assumes NIFTI images to be in RAS space and simply flips the first two axes upon loading (code). Therefore it is sufficient to do the same upon to_nibabel(). However, I tried to utilize ants.reorient_image2() in order to achieve this and watched again a strange behavior. When loading an NIFTI image in RAS orientation
this results in a direction
as the first axes are flipped. But when applying ants.reorient_image2(orientation='RAS') to it, it results in
where the Z-Axes is flipped, which looks like a bug within itkOrientImageFilter.hxx to me. |
i do not think that is likely. behavior looks correct here:
|
however, your comment: "To make a long story short: ITK assumes NIFTI images to be in RAS space and simply flips the first two axes upon loading (code). Therefore it is sufficient to do the same upon to_nibabel()." is probably right. i guess the question is what happens in 2D and 4D. |
According to nibabel documentation the z-axis value should be positive in RAS, or am I missing a point here? |
let me answer with the code from ITK:
It flips the first 2 dimensions in every case. And every dimension above the third is simply discarded. |
ok - here is a fix:
|
apologies for pushing this to master but it seems to be correct .... agree? |
I dont think the last-ind has to be flipped. But I'll check into this. |
I'll checked into the fix and as far as I see it is not quite correct. ITK changes the signs of the first two elements of all vectors. Fortunately, this simplifies the whole fix to:
UPDATE: The way the affine is created, you fix works nevertheless. When considering using the real transformation in the future, tho above approach is the way to go. |
thx - i am leaving this open until a test is added to help prevent this from coming up in the future. |
consider 1e73b82 |
While using transforms on the MNI152 template I noticed that the output of to_nibabel() was flipped along the vertical plane. While investigating the issue, I noticed, that this is caused by a wrong extraction of the q-form parameters (direction, origin) from ITK.
results in:
Using the ITK internal functions for exporting to nifti file format, everything works as expected:
Although this could be used a a quick work around, like in the from_nibabel() implementation, a Nifti/Nibabel class export, should no rely on using hard-drive exports, when all the necessary information could be retrieved while loading the file initially.
The text was updated successfully, but these errors were encountered: