nibabel icon indicating copy to clipboard operation
nibabel copied to clipboard

nibabel copying mgz header incorrectly

Open MRIDude opened this issue 11 months ago • 6 comments

I am currently using nibabel 5.3.2. I wrote a script to makes an edit to an mgz image. After running the script I noticed that nibabel adds what looks like rounding error to some of the mgz header. Below is my whole script.

import nibabel as nb
import numpy as np
import sys

oldfilledmgz = nb.freesurfer.mghformat.load(sys.argv[1])
newfilledmgz = nb.freesurfer.mghformat.load(sys.argv[2])
WMmgz        = nb.freesurfer.mghformat.load(sys.argv[3])

oldfilled=np.asanyarray(oldfilledmgz.dataobj)
newfilled=np.asanyarray(newfilledmgz.dataobj)
WM=np.asanyarray(WMmgz.dataobj)

if not np.equal(oldfilled,newfilled):
    WM[(oldfilled == 0) & ((newfilled == 127) | (newfilled==255)) ] = 255
    WM[(newfilled == 0) & ((oldfilled == 127) | (oldfilled==255)) ] = 1
    WMnew = nb.freesurfer.mghformat.MGHImage(WM, WMmgz.affine, header=WMmgz)
    WMnew.set_filename(sys.argv[3])
    nb.save(WMnew, sys.argv[3])

MRIDude avatar Jan 07 '25 21:01 MRIDude

Since you're passing the affine, it's being converted back into the header format. If you use affine=None, the header will not be modified.

effigies avatar Jan 08 '25 03:01 effigies

OK, I tried that out. everything look good except it set the c_ras to zeros.

MRIDude avatar Jan 08 '25 17:01 MRIDude

Can you print(img.header) for the WMmgz input image, the WMnew image, and then reload the file that you save and print its header too?

effigies avatar Jan 08 '25 18:01 effigies

Ok here is the updated script

import nibabel as nb
import numpy as np
import sys

 
oldfilledmgz = nb.freesurfer.mghformat.load(sys.argv[1])
newfilledmgz = nb.freesurfer.mghformat.load(sys.argv[2])
WMmgz        = nb.freesurfer.mghformat.load(sys.argv[3])

oldfilled=np.asanyarray(oldfilledmgz.dataobj)
newfilled=np.asanyarray(newfilledmgz.dataobj)
WM=np.asanyarray(WMmgz.dataobj)

if not np.array_equal(oldfilled,newfilled):
    WM[(oldfilled == 0) & ((newfilled == 127) | (newfilled==255)) ] = 255
    WM[(newfilled == 0) & ((oldfilled == 127) | (oldfilled==255)) ] = 1
    print(WMmgz.header)
    WMnew = nb.freesurfer.mghformat.MGHImage(WM, affine=None, header=WMmgz)
    print(WMnew.header)
    WMnew.set_filename(sys.argv[3])
    nb.save(WMnew, sys.argv[3])
else:
    print('No changes were made to the filled.mgz image.')

Here is the output

<class 'nibabel.freesurfer.mghformat.MGHHeader'> object, endian='>' version : 1 dims : [256 256 256 1] type : 0 dof : 1 goodRASFlag : 1 delta : [1. 1. 1.] Mdc : [[-9.9999982e-01 0.0000000e+00 -1.8626451e-09] [ 3.7252903e-09 6.9849193e-10 -9.9999994e-01] [ 0.0000000e+00 9.9999988e-01 -2.5611371e-09]] Pxyz_c : [-0.17240906 21.117714 19.475388 ] tr : 2400.0 flip_angle : 0.13962634 te : 3.18 ti : 1000.0 fov : 256.0 <class 'nibabel.freesurfer.mghformat.MGHHeader'> object, endian='>' version : 1 dims : [256 256 256 1] type : 3 dof : 0 goodRASFlag : 1 delta : [1. 1. 1.] Mdc : [[-1. 0. 0.] [ 0. 0. 1.] [ 0. -1. 0.]] Pxyz_c : [0. 0. 0.] tr : 0.0 flip_angle : 0.0 te : 0.0 ti : 0.0 fov : 0.0

Than I loaded the wm file in python. the header output is

<class 'nibabel.freesurfer.mghformat.MGHHeader'> object, endian='>' version : 1 dims : [256 256 256 1] type : 3 dof : 0 goodRASFlag : 1 delta : [1. 1. 1.] Mdc : [[-1. 0. 0.] [ 0. 0. 1.] [ 0. -1. 0.]] Pxyz_c : [0. 0. 0.] tr : 0.0 flip_angle : 0.0 te : 0.0 ti : 0.0 fov : 0.0

MRIDude avatar Jan 08 '25 20:01 MRIDude

Oh,

-    WMnew = nb.freesurfer.mghformat.MGHImage(WM, affine=None, header=WMmgz)
+    WMnew = nb.freesurfer.mghformat.MGHImage(WM, affine=None, header=WMmgz.header)

effigies avatar Jan 08 '25 20:01 effigies

This does help. I ran the code again and used the output for it in FreeSurfer's recon-all and it fails. After some investigation i figured out that the output of the python script is still producing a mgz with the incorrect header. I was able to copy over the header from the original wm.mgz using FreeSurfer's mri_convert with the --in_like flag. After coping the header FreeSurfer over recon-all run all the way through with out an issue. So nibabel is till not coping over all of the header. I have place two images in the following URL, wm1.mgz and wm2.mgz. wm1.mgz is the output of the python script while wm2.mgz is after using mri_convert to correct the head. I can not tell the difference between the images. Both nibabel and FreeSurfer's mri_head says that both images have identical headers. However after decompressing the mgz to mgh I noticed the size of both files are not the same. I am assuming I am doing this all wrong.

MRIDude avatar Jan 09 '25 14:01 MRIDude