How to change the datatype of a NiftiImage and save it with that datatype?

@effigies - is there a nibabel guide on changing datatype of a NiftiImage object and saving to a NifTI file with that datatype?

In terms of the on-disk dtype or the intent code?

both on_disk and intent. in the example below, something was likely not set appropriately, such that even though the header dtype says uint8, the data array (or the values) does not reflect that. should nibabel have raised an exception when doing the original save (i.e. a mismatch between intent and data dype)?

In [2]: import nibabel as nb
In [3]: img = nb.load('output_means.nii.gz')
In [7]: img.header.get_data_dtype()
Out[7]: dtype('uint8')
In [4]: import numpy as np
In [5]: np.unique(img.get_fdata())
Out[5]: 
array([ 0.        ,  0.96078433,  1.92156866,  3.07450986,  4.03529419,
...
       44.96470669, 45.92549102, 47.07843222, 48.03921655, 49.00000088])
In [6]: np.unique(img.get_data())
Out[6]: 
array([ 0.        ,  0.96078433,  1.92156866,  3.07450986,  4.03529419,
...
       44.96470669, 45.92549102, 47.07843222, 48.03921655, 49.00000088])
In [8]: np.unique(img.dataobj)
Out[8]: 
array([ 0.        ,  0.96078433,  1.92156866,  3.07450986,  4.03529419,
...
       44.96470669, 45.92549102, 47.07843222, 48.03921655, 49.00000088])

possible rewrite solution:

data = np.round(means.get_fdata()).astype(np.uint8)                                               
means = nb.Nifti1Image(data, header=means.header, affine=means.affine)                            
nib.save(means, outfile_means)                                                                    

In that example, what is happening is that your data is floats, so nibabel is doing its best to set scl_slope and scl_inter to capture your data with 8 bits of precision.

So if you want to coerce the interpreted dtype as well as the on-disk dtype, then you need to do something like what you suggest. I would play with it, but you might need to set_data_dtype, as well, since you’re copying the header from an image that presumably had a different on-disk dtype:

data = np.round(means.get_fdata()).astype(np.uint8)                                               
means = nb.Nifti1Image(data, header=means.header, affine=means.affine)        
means.header.set_data_dtype(np.uint8)                    
nib.save(means, outfile_means)   

Annoyingly, intent here doesn’t mean “intended type interpretation”, but more general notions of intent such as “label” or “z score”.

1 Like