Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nibabel copying mgz header incorrectly #1402

Open
MRIDude opened this issue Jan 7, 2025 · 6 comments
Open

nibabel copying mgz header incorrectly #1402

MRIDude opened this issue Jan 7, 2025 · 6 comments

Comments

@MRIDude
Copy link

MRIDude commented Jan 7, 2025

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])
@effigies
Copy link
Member

effigies commented Jan 8, 2025

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.

@MRIDude
Copy link
Author

MRIDude commented Jan 8, 2025

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

@effigies
Copy link
Member

effigies commented Jan 8, 2025

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?

@MRIDude
Copy link
Author

MRIDude commented Jan 8, 2025

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

@effigies
Copy link
Member

effigies commented Jan 8, 2025

Oh,

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

@MRIDude
Copy link
Author

MRIDude commented Jan 9, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants