fepegar / torchio

Medical imaging toolkit for deep learning
https://torchio.org
Apache License 2.0
2.06k stars 241 forks source link

choosing sform or qform when adding an image to subject #567

Closed romainVala closed 3 years ago

romainVala commented 3 years ago

🚀 Feature

I appologies to still using SPM coregister function. They made the "bad" (but pratical in some case) choice to modify the nifti sform, leaving me with volume having to different affine in the nifti header (note that all other software, ants fsl niftireg, to write the affine transformation in a separate txt file, and so the leave the initial volume with 2 identical sform and qform

Pitch

for now It seems that torchio affine, comes from the nifti qform

Alternatives

Could we add an attribute to force the affine sform instead ?

Additional context The 2 affines in the nifti, are just the worst choice they have made for nifti, since there are no commun handeling of those 2 affine definition between software so this is the reason of silent bug, when playing with different software ...

fepegar commented 3 years ago

Hi, Romain. I agree this could be useful for some people. What is the sform_code of your images? If it's != 0, you can use the NiBabel reader to read your images and the sform will be used as affine:

In [1]: import nibabel as nib

In [2]: nii = nib.load('t1.nii.gz')

In [3]: nii.get_qform()
Out[3]: 
array([[  0.        ,   0.        ,   1.        , -82.6807251 ],
       [ -1.        ,   0.        ,   0.        , 132.33735657],
       [  0.        ,  -1.        ,   0.        , 102.21686554],
       [  0.        ,   0.        ,   0.        ,   1.        ]])

In [4]: nii.get_sform()
Out[4]: 
array([[ -0.        ,   0.        ,   1.        , -82.6807251 ],
       [ -1.        ,  -0.        ,  -0.        , 132.33735657],
       [  0.        ,  -1.        ,   0.        , 102.21686554],
       [  0.        ,   0.        ,   0.        ,   1.        ]])

In [5]: new_sform = nii.get_sform() * 2

In [6]: new_sform[3, 3] = 1

In [7]: nii.set_sform(new_sform)

In [8]: nib.save(nii, 't1_different_sform.nii.gz')

In [9]: import torchio as tio

In [10]: image = tio.ScalarImage('t1_different_sform.nii.gz', reader=tio.io._read_nibabel)

In [11]: image.affine
Out[11]: 
array([[  -0.        ,    0.        ,    2.        , -165.3614502 ],
       [  -2.        ,   -0.        ,   -0.        ,  264.67471313],
       [   0.        ,   -2.        ,    0.        ,  204.43373108],
       [   0.        ,    0.        ,    0.        ,    1.        ]])

In [12]: nii.header['sform_code']
Out[12]: array(1, dtype=int16)

Would this work for you?

romainVala commented 3 years ago

Hi fernando

Yes usually when both sform ans qform are set, then sform_code and qform_code are 1 (at least in my case)

Yes it does make the job, (I did not know you can ask to specifically use nibabel,)

But it works because nibable make opposit default choice than itk. (nibabel use the sform and itk the qform ! that is an example of soft inconsistency regarding the nifti affine ...)

It would be much more clear for the user, if the choice could be explicit, with something like

image tio.ScalarImage('T1.nii"; default_affine='sform')

If the reader is nibabel, it should be easy to add, I do not know itk, but I guess too

fepegar commented 3 years ago

Yes it does make the job, (I did not know you can ask to specifically use nibabel,)

Good! I added the kwarg in #454, the docs are at https://torchio.readthedocs.io/data/image.html#torchio.Image. It's not used in the tutorials, though.

If the reader is nibabel, it should be easy to add, I do not know itk, but I guess too

I don't think so. ITK is less flexible, and their implementation of NIfTI might be incomplete (maybe I'm wrong). Here are some discussions that you might find interesting:

romainVala commented 3 years ago

thanks for the links, I see other reason to complain about nifti

but we still have to live with it ...

About those 2 possible reader, this is something a bit confusing, ... Do you know if both are really equivalent for torchio uses ?

fepegar commented 3 years ago

About those 2 possible reader, this is something a bit confusing, ... Do you know if both are really equivalent for torchio uses ?

Do you mean NiBabel vs SimpleITK? They are not totally equivalent because

  1. SimpleITK uses qform always (I think), NiBabel looks at the codes in the NIfTI header
  2. The set of formats that the libraries can read has a lot overlap, but it's no the same. ITK is more generic. NiBabel can read some neuroimaging formats that ITK doesn't understand.
romainVala commented 3 years ago

ok, thanks, I close the issue, since the use of nibabel reader makes the job (but in an implicit way) but It is worth to recall this affine difference between the 2 reader in the doc.

fepegar commented 3 years ago

That's a good point. Thanks, Romain!