I’ve been spending a lot of time in python manipulating nifti files in nibabel and have been running into some trouble with afni extensions. The only one that’s really causing me grief is the template space specification, i.e. suppose that I load a nifti file that has bee processed by AFNI and marked as TLRC and then compute some function on it and write it back out again, I lose the AFNI extensions get lost, and then when I load it back into AFNI it’s treated as being in ORIG.
Is there a doc somewhere, or some example code, that creates/modifies AFNI extensions so that I can make my python code produce sensible output?
3drefit works fine, but I’d rather avoid that step if possible.
What is happening to the sform code? What is
the sform_code field before and after your python
processing? For each such file DSET.nii, what
does this show?
nifti_tool -disp_hdr -infile DSET.nii | grep form
Yup that’s what’s happening. The sform_code is not doing being set as I expect. I’m using nibabel like this:
input_image = nibabel.load(input_filename)
# compute the output data by applying a function to the input data
out = f(input_image.get_data())
# write out the result
output_image = nibabel.nifti2.Nifti2Image(out, im.affine)
So, unfortunately, the sform_code is getting set to a different value:
input_image.header[‘sform_code’] is 1
output_image.header[‘sform_code’] is 3
Ugh. I’m going to have to really understand this API. Any thoughts?
Besides the obvious “ask the nibabel folks”
I guess the 3 was from the input and the 1 was from
Actually, the way you have written it here, I do not
see how it would know what space to use. From:
output_image = nibabel.nifti2.Nifti2Image(out, im.affine),
all it knows is the data and the transformation matrix.
Looking at the docs, perhaps you might call
input_image.save(out, FILENAME)? I have not done
Okay, I figured it out. You were right about needing to use more of the header information to specify the sform and qform codes. Passing a header in explicitly worked beautifully.
out_image = type(im)(out, affine=None, header=im.header)
(the bit about type(im) is to let me switch between using Nifti1 and Nift2 depending on what the input image was)
So that solves my main issue with the spaces.
Going forward, how do you think I should handle the extensions? It would be nice to be somewhat consistent with what the AFNI tools do, maybe update the history, have a way of handling labels, etc.
That is good news.
Handling extensions in a reasonably nice way would
surely take a lot of effort. I don’t see how that
would be worth the time, particularly if you want
those extensions to propagate into other software.
Even labels would be messy. The history could be
dumped in as comment extensions, but still, other
software will probably not even see them.