Spatial Normalization: AFNI, SPM, and FSL
Purpose:
Characterize relative accuracy of SPM5's high-order, FSL's fnirt, and AFNI's @auto_tlrc methods for spatially normalizing images. @auto_tlrc is at a disadvantage because it is a 9-parameter affine warp while both SPM and FSL use many more parameters. The method in SPM5 uses a discrete cosine transform as a basis set, and this is parameterized by roughly 450 3-element vectors. FSL's fnirt uses a basis set that appears to have a similar spatial resolution but it enforces a diffeomorphic constraint. See the FSL website fnirt and the SPM website
Method:
This not meant to be a precise analysis but rather to give a rough indication of the performance of the various methods. The approach is to analyze a difficult-to-normalize dataset with each method, stack the normalized images from each subject into a single "time-series," and then make a Quicktime movie of it.
Data:
The data were taken from a study of roughly 180 10-14 year-old children. Two of four epi runs were included. The data acquisition order was EPIs first, then a dti acquisition, then a T1-weighted structural image. The delay between the last EPI and the structural image resulted in signficant misalignment between the last EPI frame and the structural image.
Analyses:
- AFNI: AFNI's @auto_tlrc script was used to normalize T1 weighted images. AFNI's @align_epi_anat.py script was used to compute a rigid body transformation from the EPI image to the subjects own T1-weighted image. 3drotate was used to register the EPI with the anatomical, then adwarp was used to transform it to MNI coordinates.
- SPM: SPM5's normalization was scripted to normalize the T1 images. AFNI's @auto_tlrc script was used to register the EPI's as above. 3drotate from AFNI and SPM were then used to normalize the EPI's
- FSL: flirt was used to compute an intial affine normalization of the T1 weighted images, this was then fed to fnirt to compute the overall transformation. flirt was also used to register the EPI's to the subject's structural image. This was then used along with fnirt-s warp in applywarp to normalize the EPIs.
Results:
The following links go to Quicktime movies of the normalized images displayed in cine mode
- AFNI vs. SPM5, T1-weighted images: AFNI images are on the left, SPM5 images on the right. The template is displayed as a red overlay.
- FSL vs. SPM5, T1-weighted images: Images normalized with fnirt are on the left, SPM5 images on the right. The template is displayed as a red overlay.
- AFNI vs. AFNI/SPM5, EPI SNR images: Images normalized with AFNI's align_epi_anat.py and @auto_tlrc are on the left, those normalized with @auto_tlrc and SPM5 are on the right.
- FSL vs. AFNI/SPM5, EPI SNR images: Images normalized with FSL's flirt/fnirt combo are on the left, those normalized with @auto_tlrc/SPM5 are on the right.
Quick Summary
The upshot is that fnirt normalizations win the beauty contest: they look much better than either auto_tlrc or SPM5 normalizations. That may or may not result in better alignment of functional maps, but it probably won't hurt. The EPI normalizations were pretty awful, mostly because of misalignment between the EPIs and structurals, which neither program handled well.
Script for normalizing the T1-weighted structurals to the template:
#!bin/bash
TOP=/Users/jmo/data2/brdevel
SUBJECTS=`cat subjects_to_use.txt`
TEMPLATE=/Users/jmo/data2/aut05/face_study.nii
AFNI_TEMPLATE=/Users/jmo/data2/aut05/face_study+tlrc
function get_nprocesses {
export nflirt=`ps | grep flirt | grep usesqform | awk 'BEGIN{n=0}{n+=1}END{print n}'`
export nfnirt=`ps | grep fnirt | grep iout | awk 'BEGIN{n=0}{n+=1}END{print n}'`
}
NPROC=6
nsub=0
for subject in ${SUBJECTS} do
echo ""
echo -n "Processing subject ${subject} "
get_nprocesses
echo Number of flirts running: ${nflirt}, Number of fnirts running: ${nfnirt}
# echo ""
# echo __${nflirt}__${NPROC}__
while [ ${nfnirt} -ge ${NPROC} ] do
sleep 20
get_nprocesses
done
nsub=$((nsub + 1))
regfile=wT1High_ns.nii
anatdir=${TOP}/data/${subject}/anat
matfile=wT1High_ns_sn.mat
spm_matfile_out=T1High_ns_sn_kids.mat
afni_matfile_out=T1High_ns_autotlrc.Xaff12.1D
if [ -e ${anatdir}/T1High+orig.BRIK ] & \
([ ! -e ${anatdir}/${spm_matfile_out} ] || \
[ ! -e ${anatdir}/${afni_matfile_out} ]) then
if [ -e ${anatdir}/${regfile} ] then
/bin/rm ${anatdir}/${regfile}
fi
skstrip_afni=${anatdir}/T1High_ns
skstrip_nifti=/tmp/T1High_ns_${subject}
if [ ! -e ${anatdir}/${spm_matfile_out} ] then
infile=${anatdir}/T1High+orig
if [ ! -e ${skstrip_afni}+orig.HEAD ] then
echo 3dSkullstrip -input ${infile} -prefix ${skstrip_afni} > /dev/null
ARGS="-input ${infile} -prefix ${skstrip_afni} > /dev/null"
echo 3dSkullstrip ${ARGS}
3dSkullstrip ${ARGS}
fi
# Do spm's normalization
echo "spm_norm -t ${TEMPLATE} ${skstrip_afni}+orig"
spm_norm -t ${TEMPLATE} ${skstrip_afni}+orig > /dev/null
mv ${anatdir}/${matfile} ${anatdir}/${spm_matfile_out}
fi
if [ ! -e ${skstrip_afni}_autotlrc+tlrc.HEAD ] then
# Now do @auto_tlrc
ARGS="-no_ss -base ${AFNI_TEMPLATE} \
-input ${skstrip_afni}+orig \
-suffix _autotlrc"
echo "@auto_tlrc ${ARGS}"
cd ${anatdir} & @auto_tlrc ${ARGS} 2> spatnorm.log
fi
flirt_norm=${anatdir}/T1High_ns_flirt
flirt_mat=${anatdir}/T1High_ns_flirt.mat
fnirt_norm=${anatdir}/T1High_fnirt
fnirt_mat=${anatdir}/T1High_ns_fnirtwarp
if [ ! -e ${fnirt_norm}.nii ] & [ ! -e ${fnirt_norm}.nii.gz ] then
# if [ -e ${skstrip_nifti}.nii ] || [ -e ${skstrip_nifti}.nii.gz ] then
# /bin/rm ${skstrip_nifti}.nii*
# fi
echo 3dcopy ${skstrip_afni}+orig ${skstrip_nifti}.nii
3dcopy ${skstrip_afni}+orig ${skstrip_nifti}.nii > /dev/null
if [ ! -e ${flirt_mat} ] & [ ! -e ${flirt_mat}.nii.gz ] then
ARGS=" -in ${skstrip_nifti}.nii \
-ref ${TEMPLATE} \
-out ${flirt_norm} \
-usesqform \
-omat ${flirt_mat}"
# echo flirt ${ARGS}
# flirt ${ARGS} > flirt_${subject}.log&
fi
if [ ! -e ${fnirt_norm}.nii ] & [ ! -e ${fnirt_norm}.nii.gz ] then
ARGS=" --in=${skstrip_nifti} \
--ref=${TEMPLATE} \
--iout=${fnirt_norm}.nii \
--fout=${anatdir}/T1High_fnirt_fieldcoeff \
--aff=${flirt_mat} \
--cout=${fnirt_mat}"
echo fnirt ${ARGS}
# fnirt ${ARGS} > fnirt_${subject}.log&
fi
fi
epidir=${TOP}/data/${subject}/gonogo
mat_epiflirt=${epidir}/gonogo_flirt.mat
t1high_ns=${anatdir}/T1High_ns
t1high_ns_tmp=/tmp/T1High_ns_${subject}.nii
if [ ! -e ${mat_epiflirt} ] then
if [ -e ${t1high_ns_tmp} ] then
/bin/rm ${t1high_ns_tmp}
fi
ARGS="${t1high_ns}+orig ${t1high_ns_tmp}"
echo "3dcopy ${ARGS}"
3dcopy ${ARGS} > /dev/null
epi=${epidir}/gonogo
epimean=/tmp/mean_${subject}.nii
if [ -e ${epimean} ] then
/bin/rm ${epimean}
fi
ARGS="-mean -prefix ${epimean} ${epi}+orig"
echo 3dTstat ${ARGS}
3dTstat ${ARGS} > /dev/null
ARGS="-usesqform -ref ${t1high_ns_tmp} -in ${epimean} -dof 7 -omat ${mat_epiflirt}"
echo flirt ${ARGS}
flirt ${ARGS}&
# /bin/rm ${t1high_ns_tmp}
fi
fi
done
Script for normalizing the EPIs (actually the SNR computed from the EPIs:
#!/bin/bash
RUNS="1 2"
DATADIR=/study/BRDEVEL/data/orig3
DATADIR_LOCAL=/Users/jmo/data2/brdevel/data/
EPIDIR_LOCAL=/Users/jmo/data2/bloch_sims/brdevel/epis
TOPOUT=/Users/jmo/data2/bloch_sims/brdevel/snrs
SUBNUMS=`cat subjects_to_use.txt`
OUTFILE=${TOPOUT}/mean_snrs_fm_prealign.txt
TEMPLATE=face_study.nii
echo -n "" > ${OUTFILE}
for subnum in ${SUBNUMS} do
echo Subject: ${subnum}
for run in ${RUNS} do
anat_local=${DATADIR_LOCAL}/${subnum}/anat
epidir=${DATADIR_LOCAL}/${subnum}/gonogo
EPI=${epidir}/epi_run${run}_mf
mat_autoalign=`ls ${DATADIR}/${subnum}/fMRI/gonogo/epi_run?_mf_al_mat.aff12.1D`
mat_epiflirt=${DATADIR}/${subnum}/fMRI/gonogo/epi_run1_mf_flirt.mat
TMPEPI=/tmp/tmpsnr_epi
motcor=
snr_subj=${TOPOUT}/snr_imgs_fm/snr_${subnum}_run${run}
snr_prenorm=/tmp/snr_${subnum}_run${run}
if [ -e ${EPI}+orig.HEAD ] & [ -e ${mat_autoalign} ] then
if [ ! -e ${snr_subj}+orig.HEAD ] then
# echo Computing ${snr_subj}+orig
snrs=`get_snr ${motcor} --prefix=${snr_subj} --write-signal ${EPI}+orig`
echo ${snrs}
echo ${subnum}_${run} ${snrs} >> ${OUTFILE}
fi
snr_norm=${snr_subj}_mni
matfile=${anat_local}/T1High_ns_sn_kids.mat
if [ ! -e ${snr_norm}_sn.nii ] & [ -e ${matfile} ] then
ARGS="-dfile ${mat_autoalign} -prefix ${snr_prenorm} ${snr_subj}+orig"
# echo 3drotate ${ARGS}
3drotate ${ARGS}
ARGS="--matfile=${matfile} --prefix=${snr_norm} --nifti ${snr_prenorm}+orig"
# echo spm_norm ${ARGS}
spm_norm ${ARGS}
/bin/rm ${snr_prenorm}+orig.*
fi
matauto=${anat_local}/T1High_ns.Xaff12.1D
mat_autoalign_inv=${DATADIR}/${subnum}/`basename -s .aff12.1D ${mat_autoalign}`_inverse.aff12.1D
anatpar=${anat_local}/T1High_ns_autotlrc+tlrc
snr_norm=${snr_subj}_mni_autotlrc
if [ ! -e ${snr_norm}+tlrc.HEAD ] then
if [ -e ${snr_prenorm}+orig.HEAD ] then
/bin/rm ${snr_prenorm}+orig.*
fi
ARGS="-dfile ${mat_autoalign} -prefix ${snr_prenorm} ${snr_subj}+orig"
echo 3drotate ${ARGS}
3drotate ${ARGS}
ARGS="-dxyz 2 -apar ${anatpar} -prefix ${snr_norm} -dpar ${snr_prenorm}+orig"
echo adwarp ${ARGS}
adwarp ${ARGS}
/bin/rm ${snr_prenorm}+orig.*
fi