import nibabel as nib
from nilearn.plotting import view_img
from nilearn import image
import plotnine as p
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import colormaps as cmaps
Ventricular Mask from MNI to Analysis T1
From TemplateFlow we’ve obtained an MNI152NLin2009cAsym template brain and the Harvard-Oxford subcortical atlas to match.
= nib.load("data/link/t1.nii.gz")
tpim = nib.load("data/link/atlas_sub_d50.nii.gz") im
We can plot the ROI of interest (the ventricles) on the MNI T1 image.
# Ventricles at index 2 and 13 (l and r), add one for zero intensity
# This is all undocumented afaik...
= image.math_img('np.isin(i, [3,14])', i=im)
vent ='viridis') view_img(vent, tpim, cmap
This is saved as a binary mask.
'data/tmp/ventricle_mask_mni_b.nii.gz') nib.save(vent,
If we map an MNI-space ROI mask directly onto a subject’s T1 image, there will be major misalignment.
= nib.load('data/tmp/s4101_t1_brain.nii.gz')
sub ='viridis') view_img(vent, sub, cmap
/share/pkg.8/python3/3.10.12/install/lib/python3.10/site-packages/nilearn/image/resampling.py:294: UserWarning: Resampling binary images with continuous or linear interpolation. This might lead to unexpected results. You might consider using nearest interpolation instead.
The rigid body transform rotates and translates the subjects brain so that it is positioned as is the MNI brain but without spatial scaling (full affine) or warping.
= nib.load('data/tmp/s4101_anal_brain.nii.gz')
sub ='viridis') view_img(vent, sub, cmap
/share/pkg.8/python3/3.10.12/install/lib/python3.10/site-packages/numpy/core/fromnumeric.py:784: UserWarning: Warning: 'partition' will ignore the 'mask' of the MaskedArray.
We’re gonna need the nonlinear registration to get from MNI to T1.
According to FSL’s Registration Practical, the full nonlinear warp file should end in _warp.nii.gz
, whereas FLIRT will output an affine .mat
.
The fMRIPrep provided .h5
combines a field warp and affine transform.
antsApplyTransforms -d 3 -i data/tmp/ventricle_bmask_mni.nii.gz -r data/tmp/s4101_t1_brain.nii.gz -t data/tmp/s4101_mni_to_t1_xfm.h5 -o data/tmp/s4101_t1_ventricle_bmask.nii.gz
= nib.load('data/tmp/s4101_t1_brain.nii.gz')
sub = nib.load('data/tmp/s4101_t1_ventricle_bmask.nii.gz')
warped ='viridis') view_img(warped, sub, cmap
Our analysis T1 is a rigid body transform further. We calculated this as part of the manual pipeline.
antsApplyTransforms -d 3 -i data/tmp/s4101_t1_ventricle_bmask.nii.gz -r data/tmp/s4101_anal_brain.nii.gz -t data/tmp/s4101_t1_to_anal_xfm_itk.txt -o data/tmp/s4101_anal_ventricle_bmask.nii.gz
= nib.load('data/tmp/s4101_anal_brain.nii.gz')
sub = nib.load('data/tmp/s4101_anal_ventricle_bmask.nii.gz')
warped ='viridis') view_img(warped, sub, cmap
/share/pkg.8/python3/3.10.12/install/lib/python3.10/site-packages/numpy/core/fromnumeric.py:784: UserWarning: Warning: 'partition' will ignore the 'mask' of the MaskedArray.
Because we did not specify an interpolation method to antsApplyTransforms
, it defaulted to linear interpolation. Note the intensity values less than one introduced by this step (our mask is no longer binary).
We can rectify this by using NearestNeighbor interpolation instead. Let’s also apply both transforms in one step (MNI -> Analysis T1).
Note the order. The ants documentation specifies that a stack of transformations will be created in the order specified on the command-line. Therefore, the last transformation will be done first.
antsApplyTransforms -d 3 -i data/tmp/ventricle_bmask_mni.nii.gz -r data/tmp/s4101_anal_brain.nii.gz -t data/tmp/s4101_t1_to_anal_xfm_itk.txt -t data/tmp/s4101_mni_to_t1_xfm.h5 -o data/tmp/s4101_anal_ventricle_bmask_corrected.nii.gz -n NearestNeighbor
= nib.load('data/tmp/s4101_anal_brain.nii.gz')
sub = nib.load('data/tmp/s4101_anal_ventricle_bmask_corrected.nii.gz')
warped ='viridis') view_img(warped, sub, cmap