<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div dir="ltr">
<div>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.<br>
</div>
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.<br>
<br>
---------<br>
<br>
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).<br>
<br>
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.<br>
<br>
Nibabel saved back original header<br>
<br>
qform_name Scanner Anat<br>
qform_code 1<br>
qto_xyz:1 -1.796652 0.000000 -0.000000 112.420448<br>
qto_xyz:2 0.000000 1.795833 -0.054337 -90.885376<br>
qto_xyz:3 0.000000 0.054236 1.799180 54.572971<br>
qto_xyz:4 0.000000 0.000000 0.000000 1.000000<br>
qform_xorient Right-to-Left<br>
qform_yorient Posterior-to-Anterior<br>
qform_zorient Inferior-to-Superior<br>
sform_name Scanner Anat<br>
sform_code 1<br>
sto_xyz:1 -1.796652 0.000000 0.000000 112.420448<br>
sto_xyz:2 0.000000 1.795833 -0.054337 -90.885376<br>
sto_xyz:3 0.000000 0.054236 1.799180 54.572971<br>
sto_xyz:4 0.000000 0.000000 0.000000 1.000000<br>
sform_xorient Right-to-Left<br>
sform_yorient Posterior-to-Anterior<br>
sform_zorient Inferior-to-Superior<br>
<br>
Nibabel recreated header<br>
<br>
<br>
qform_name Unknown<br>
qform_code 0<br>
qto_xyz:1 1.796652 0.000000 0.000000 0.000000<br>
qto_xyz:2 0.000000 1.796652 0.000000 0.000000<br>
qto_xyz:3 0.000000 0.000000 1.800000 0.000000<br>
qto_xyz:4 0.000000 0.000000 0.000000 1.000000<br>
qform_xorient Left-to-Right<br>
qform_yorient Posterior-to-Anterior<br>
qform_zorient Inferior-to-Superior<br>
sform_name Aligned Anat<br>
sform_code 2<br>
sto_xyz:1 -1.796652 0.000000 0.000000 112.420448<br>
sto_xyz:2 0.000000 1.795833 -0.054337 -90.885376<br>
sto_xyz:3 0.000000 0.054236 1.799180 54.572971<br>
sto_xyz:4 0.000000 0.000000 0.000000 1.000000<br>
sform_xorient Right-to-Left<br>
sform_yorient Posterior-to-Anterior<br>
sform_zorient Inferior-to-Superior<br>
<br>
<br>
</div>
<div class="gmail_extra">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.<br>
So, two questions : <br>
- Is there any adverse effect to using original headers if I know
for certain nothing changed except dtype?<br>
- 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) <br>
or is that some nibabel RAS convention? I am still confused as to
what happened to the orientation for the recreated header.<br>
<br>
Samuel<br>
<br>
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.<br>
<br>
fslorient -swaporient 'out.nii.gz'<br>
<br>
In [1]: import nibabel as nib<br>
<br>
In [3]: vol=nib.load('out.nii.gz')<br>
<br>
In [4]: data=vol.get_data()<br>
<br>
In [5]: aff=vol.get_affine()<br>
<br>
In [6]: hdr=vol.get_header()<br>
<br>
In [7]: nib.save(nib.Nifti1Image(data,aff,hdr),'out2.nii.gz')<br>
<br>
In [8]: nib.save(nib.Nifti1Image(data,aff),'out3.nii.gz')<br>
<br>
<br>
<div class="gmail_quote">2016-06-28 15:13 GMT+02:00 Matthew Brett
<span dir="ltr"><<a href="mailto:matthew.brett@gmail.com"
target="_blank">matthew.brett@gmail.com</a>></span>:<br>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<span class=""><br>
On Mon, Jun 27, 2016 at 11:50 PM, Samuel St-Jean <<a
href="mailto:stjeansam@gmail.com">stjeansam@gmail.com</a>>
wrote:<br>
> I'll need to play a bit with it today and ask some guy
about the flipping, I<br>
> am reporting for someone else actually. So, it seems to
be harmless to put<br>
> back the header in the case of unchanged affine (as it
is in my situation),<br>
> could be that other software downstream does not really
like something else.<br>
> I did not reuse it because of dtypes, voxelsize and
other things which may<br>
> wildly change on processed data.<br>
><br>
><br>
> Anyway, this example is using your case number 1, no
header, affine is<br>
> gotten from get_affine. Of course it was not modified
during the processing,<br>
> and I end up with a different sform/qform. Accoridng to
your first point, I<br>
> expected them to be identical, but I end up with a
sligthly different (and<br>
> diagonal) qform. They also have different names, so
ifthey were set to the<br>
> same thing I would expect them to be pristine copies.<br>
><br>
> That's a bit troublesome now as JC pointed out, since
we all use the same<br>
> set of scripts for the heavy processing, which don't
reuse headers as I can<br>
> remember. Does not seem to cause any problem for us,
don't want to receive<br>
> hate mail by other people using some of our stuff and
saying we broke their<br>
> data though.<br>
><br>
> Are sform and qform set to match the affine in exactly
the same way, or does<br>
> some transformation is applied and then they are
identical? I went through<br>
> the info on the nibabel website about headers and
affine, so maybe I just<br>
> missed it also if anyone has other info to add.<br>
<br>
</span>Well - remember that the qform is stored differently
from the sform.<br>
In particular, the qform cannot store shears, because it's the<br>
composition of the translations on a pure rotation on the
zooms,<br>
whereas the sform can, because it stores a full 3 x 4 affine
matrix.<br>
<br>
The sform and the qform will have different so-called
"transform<br>
codes", if the sform and qform both get set (rules as
described in my<br>
last email). This is because the default transform codes are<br>
different for the sform and qform, and we use the defaults.<br>
<br>
The flip should always be the same though, when the sform and
qform<br>
get set together - at least if the external software is
reading the<br>
header correctly.<br>
<div class="HOEnZb">
<div class="h5"><br>
Cheers,<br>
<br>
Matthew<br>
_______________________________________________<br>
Neuroimaging mailing list<br>
<a href="mailto:Neuroimaging@python.org">Neuroimaging@python.org</a><br>
<a
href="https://mail.python.org/mailman/listinfo/neuroimaging"
rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/neuroimaging</a><br>
</div>
</div>
</blockquote>
</div>
<br>
</div>
</body>
</html>