[Neuroimaging] [nibabel] sform/qform flipping left - right in the affine and (possibly) fsl
Samuel St-Jean
stjeansam at gmail.com
Mon Jul 11 02:48:31 EDT 2016
So, if nibabel reads and write everything correctly, must be something
down the fsl path doing non cool stuff. Question now is if I should
bother fixing it and risk breaking stuff for other people as unseen side
effects.
At least I learned stuff, had no idea qform can not store all possible
transformations, so that explains why it differs slightly from the sform
after saving back.
---------
And one week later (this above was an earlier draft) I got around to
actually fix it, but I cannot explain why. If I save back the header
with it, I do not experience the flip. If I tell nibabel to create an
header because I did not pass anything, it seems to put back my data in
RAS (think I saw this on the website, but I though it was only for
internal representation).
So, saving back header + I change the dtype manually (since the dtype
from the header is used, which is almost always int16 to float32 for me)
does not flip anything. Although I still can't figure out why the
created header gives me flipped data, here is a small excerpt of said
header.
Nibabel saved back original header
qform_name Scanner Anat
qform_code 1
qto_xyz:1 -1.796652 0.000000 -0.000000 112.420448
qto_xyz:2 0.000000 1.795833 -0.054337 -90.885376
qto_xyz:3 0.000000 0.054236 1.799180 54.572971
qto_xyz:4 0.000000 0.000000 0.000000 1.000000
qform_xorient Right-to-Left
qform_yorient Posterior-to-Anterior
qform_zorient Inferior-to-Superior
sform_name Scanner Anat
sform_code 1
sto_xyz:1 -1.796652 0.000000 0.000000 112.420448
sto_xyz:2 0.000000 1.795833 -0.054337 -90.885376
sto_xyz:3 0.000000 0.054236 1.799180 54.572971
sto_xyz:4 0.000000 0.000000 0.000000 1.000000
sform_xorient Right-to-Left
sform_yorient Posterior-to-Anterior
sform_zorient Inferior-to-Superior
Nibabel recreated header
qform_name Unknown
qform_code 0
qto_xyz:1 1.796652 0.000000 0.000000 0.000000
qto_xyz:2 0.000000 1.796652 0.000000 0.000000
qto_xyz:3 0.000000 0.000000 1.800000 0.000000
qto_xyz:4 0.000000 0.000000 0.000000 1.000000
qform_xorient Left-to-Right
qform_yorient Posterior-to-Anterior
qform_zorient Inferior-to-Superior
sform_name Aligned Anat
sform_code 2
sto_xyz:1 -1.796652 0.000000 0.000000 112.420448
sto_xyz:2 0.000000 1.795833 -0.054337 -90.885376
sto_xyz:3 0.000000 0.054236 1.799180 54.572971
sto_xyz:4 0.000000 0.000000 0.000000 1.000000
sform_xorient Right-to-Left
sform_yorient Posterior-to-Anterior
sform_zorient Inferior-to-Superior
Notice how the qform has shearing in the first case (and original also),
while it has flipped orientation and no shearing in the recreated header
case.
So, two questions :
- Is there any adverse effect to using original headers if I know for
certain nothing changed except dtype?
- Well, I still can't figure out the flipping (is it the same when
transformation would be applied in world space? So it still is flipped
for all software in image space in this case then)
or is that some nibabel RAS convention? I am still confused as to what
happened to the orientation for the recreated header.
Samuel
P.S. Quick snippet to reproduce flipping with fslorient, adapt filename
of course but any random nifti should work, this was diffusion data.
Check header with fslhd afterwards.
fslorient -swaporient 'out.nii.gz'
In [1]: import nibabel as nib
In [3]: vol=nib.load('out.nii.gz')
In [4]: data=vol.get_data()
In [5]: aff=vol.get_affine()
In [6]: hdr=vol.get_header()
In [7]: nib.save(nib.Nifti1Image(data,aff,hdr),'out2.nii.gz')
In [8]: nib.save(nib.Nifti1Image(data,aff),'out3.nii.gz')
2016-06-28 15:13 GMT+02:00 Matthew Brett <matthew.brett at gmail.com
<mailto:matthew.brett at gmail.com>>:
Hi,
On Mon, Jun 27, 2016 at 11:50 PM, Samuel St-Jean
<stjeansam at gmail.com <mailto:stjeansam at gmail.com>> wrote:
> I'll need to play a bit with it today and ask some guy about the
flipping, I
> am reporting for someone else actually. So, it seems to be
harmless to put
> back the header in the case of unchanged affine (as it is in my
situation),
> could be that other software downstream does not really like
something else.
> I did not reuse it because of dtypes, voxelsize and other things
which may
> wildly change on processed data.
>
>
> Anyway, this example is using your case number 1, no header,
affine is
> gotten from get_affine. Of course it was not modified during the
processing,
> and I end up with a different sform/qform. Accoridng to your
first point, I
> expected them to be identical, but I end up with a sligthly
different (and
> diagonal) qform. They also have different names, so ifthey were
set to the
> same thing I would expect them to be pristine copies.
>
> That's a bit troublesome now as JC pointed out, since we all use
the same
> set of scripts for the heavy processing, which don't reuse
headers as I can
> remember. Does not seem to cause any problem for us, don't want
to receive
> hate mail by other people using some of our stuff and saying we
broke their
> data though.
>
> Are sform and qform set to match the affine in exactly the same
way, or does
> some transformation is applied and then they are identical? I
went through
> the info on the nibabel website about headers and affine, so
maybe I just
> missed it also if anyone has other info to add.
Well - remember that the qform is stored differently from the sform.
In particular, the qform cannot store shears, because it's the
composition of the translations on a pure rotation on the zooms,
whereas the sform can, because it stores a full 3 x 4 affine matrix.
The sform and the qform will have different so-called "transform
codes", if the sform and qform both get set (rules as described in my
last email). This is because the default transform codes are
different for the sform and qform, and we use the defaults.
The flip should always be the same though, when the sform and qform
get set together - at least if the external software is reading the
header correctly.
Cheers,
Matthew
_______________________________________________
Neuroimaging mailing list
Neuroimaging at python.org <mailto:Neuroimaging at python.org>
https://mail.python.org/mailman/listinfo/neuroimaging
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/neuroimaging/attachments/20160711/6b930a8a/attachment.html>
More information about the Neuroimaging
mailing list