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:

  1. 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.
  2. 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
  3. 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

  1. 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.
  2. 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.
  3. 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.
  4. 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


Last modified February 24, 2011