Skull stripping non-T1 anatomical images

Hi Afni gurus,

I'm trying to use afni @sswarper to move several anatomical images from native to MNI space. Some of my images are not T1, I'm also acquiring FLAIR, T2, T2Star, SWI. The documentation for 3dskullstrip specifies that the input must be a T1 image. Does that mean there is no way of using @sswarper with anatomical imaging that isn't T1?

Thank you!

AFNI version info (afni -ver):

Precompiled binary macos_10.12_local: Aug 19 2022 (Version AFNI_22.2.07 'Marcus Aurelius')

Howdy-

Never say never with AFNI!

You can try using @SSwarper on other tissue contrast types, sure. Sidenote: we have a newer update version, called sswarper2 (that shares the usage syntax of @SSwarper), which you can use if you update your AFNI; and your AFNI is now over 1.5 years old, it might be worth updating for new features, even beyond the sswarper2 program.

The first thing you could consider would be if you have a T1w volume and other contrasts for the same subject. If you are in this scenario, how about just running sswarper2 on your T1w volume, and simply performing linear affine registration of the other subject anatomicals to your T1w volume? You can use the T1w-space mask to skullstrip the other volumes, and you can concatenate the, say, T2w->T1w->MNI space transformations to be able to align your non-T1w volumes to standard space, as needed. This would probably be my primary recommendation, as it should be the simplest way to proceed; it lets sswarper2 do what it is best at, and aligning the other anatomicals should be pretty straightforward (he sez, tempting the universe...), since they should have minimal distortions and good quality. The biggest consideration here is using a cost function for cross-modality alignment, which will typically be lpc or the slower-but-more stable lpc+ZZ; if that fails, we could try nmi.

As a second way of going, you could use sswarper2 for each modality separately, again just adjusting the cost function used for alignment, to one of the same set as above for starters. You just have to specify the new cost function twice, with these 3 options (and for -cost_nl_* .. don't have lpc+ZZ, you for either lpc* opt you would just specify lpc for those latter stages of alignment and lpc+ZZ perhaps for -cost_aff ..):

  -cost_aff CA :(opt) specify cost function for affine (3dAllineate)
              part of alignment.  Here, 'CA' would be just the name of
              the cost function to be provided after '-cost ..' (def:
              is now "lpa+ZZ").  This is probably only here for
              backwards compatibility to older @SSwarper (where def
              was 'hel').

  -cost_nl_init CNI 
             :(opt) specify cost function for initial nonlinear
              (3dQwarp) part of alignment.  Here, 'CNI' would be the
              cost function name to be provided (def: is now "lpa").
              This is probably only here for backwards compatibility
              to older @SSwarper (where def was 'pcl').

  -cost_nl_final CNF 
             :(opt) specify cost function for final nonlinear
              (3dQwarp) parts of alignment.  Here, 'CNF' would be the
              cost function to be provided (def: is now "pcl").  This
              is separate from the initial nonlinear warp cost values
              '-cost_nl_init ..', because using those here might be
              pretty slow; however, using "lpa" here might help
              results.

Let me know what option sounds more appealing, though again I would suggest the first one.

--pt

Hi Paul,

First of all - thank you so much. This is the first time I've tried to communicate with the message board - and I'm amazed by how quickly and how helpful your response has been.

I indeed have a T1w image in each of my sessions, so I will try your suggestion and use SSwarper2.
Following sswarper2 with my t1w image, what would be the next steps? Which afni function uses a T1w-space mask to skullstrip other volumes / performs allignment using the template space t1w image as a baseline?

Thanks again

Sure thing.

So I would do something like the following:

  1. Nonlinearly align subject T1w dset to template (with skullstripping):
# subject ID
set subj   = sub-001    
# input T1w dset, can include path
set dset_t1w  = DSET_NAME_T1W 
# output dir for results
set sdir_ssw = odir_ssw_t1w
# template to use, might include path
set dset_template = MNI152_2009_template_SSW.nii.gz

sswarper2                                     \
    -base    "${dset_template}"               \
    -subid   "${subj}"                        \
    -input   "${dset_t1w}"                    \
    -odir    "${sdir_ssw}"

Check the alignment+skullstripping from this is key, and there are QC images in the output dir to help. You can turn the output anatSS* dset into a mask directly with, for example:

3dcalc \
    -a anatSS.${subj}.nii \
    -expr 'step(a)' \
    -prefix anatSS.${subj}.mask.nii 

There are 2 important pieces of the transformation from T1w->reference space here, to be concatenated later:

  • anatQQ.${subj}.aff12.1D : affine part
  • anatQQ.${subj}_WARP.nii : nonlinear warp refinement part
  1. Do affine alignment of subj T1w dset to non-T1w dset, like FLAIR. There are some options about how you align the two different subject anatomicals, either using 3dAllineate directly or the wrapper program align_epi_anat.py (which, actually is useful beyond just EPI-anatomical alignment). Maybe we could start with the latter, where for option-naming sake the "anat" is the T1w dset and the "EPI" is the FLAIR, and we ill estimate the transform from T1w->FLAIR (it can always be inverted):

# input FLAIR dset, can include path
set dset_flair  = DSET_NAME_FLAIR
# output dir for T1w-flair align
set sdir_aea_flair = odir_aea_t1w_flair

align_epi_anat.py                                \
    -anat2epi                                    \
    -anat             "${sdir_ssw}/anatSS.${subj}.nii"         \
    -anat_has_skull   no                         \
    -suffix           _al_aea                   \
    -epi              "${dset_flair}"   \
    -epi_strip        None                 \
    -cost             lpc+ZZ                     \
    -giant_move                                  \
    -volreg           off                        \
    -tshift           off                     \
    -output_dir       "${sdir_aea_flair}"

That will create the affine alignment file anatSS.${subj}_al_aea_mat.aff12.1D that would align T1w->FLAIR. It can be inverted to get the FLAIR->T1w alignment, too.

  1. To send the FLAIR to the template, I think you can create the concatenation of the appropriate pieces as (NB: I am doing this without a dataset at the moment, so the paths/names might need a bit of refinement...):
# some name for the first output warp dset
set dset_flair_to_temp_warp = WARP_FLAIR_TO_TEMPLATE.nii
# name for dset in final template space
dset dset_flair_to_temp = FLAIR_IN_TEMPLATE.nii

# create full/concatenated warp
3dNwarpCat    \
   -prefix "${dset_flair_to_temp_warp}" \
   -warp3 "INV(${sdir_aea_flair}/anatSS.${subj}_al_aea_mat.aff12.1D)" \
   -warp2 "${sdir_ssw}/anatQQ.${subj}.aff12.1D" \
   -warp1 "${sdir_ssw}/anatQQ.${subj}_WARP.nii" 

# apply full/concatenated warp
3dNwarpApply \
    -nwarp "${dset_flair_to_temp_warp}" \
    -source "${dset_flair}" \
    -master "${dset_template}" \
    -interp wsinc5 \
    -prefix "${dset_flair_to_temp_warp}"

Do you want to start with the first couple pieces and see how that looks?

--pt

Hi Paul,

Thank you again for answering with so much detail - it really helps when trying to work things out.
I have been trying different things with regard to what you detailed - and it seems that it's working out pretty good.

I had a couple of questions -
(1) I've been having difficulties with getting a good skull strip using SSwarper2. I've tried many variations of the command, including:

for file in anatQQ.*; do
    if [[ -f $file ]]; then
    	echo 'anat.QQ FILES exsist'
    	break
        else 
        cd $path
        echo 'preforming @SSwraper'
        export OMP_NUM_THREADS 4
        sswarper2                                                                      		\
		   -input  anat_mask_inv2/$subject.$experiment.$session.mp2r.den_SS+orig.BRIK       \
		   -base   $abin_path/MNI152_2009_template_SSW.nii.gz                           	\
		   -subid  $subject.$experiment.$session.$anattype									\
		   -odir   $output_path 															\
		   -unifize_off																		\
		   -aniso_off																		\
		   -ceil_off																		
		 #  -init_skullstr_off																\
    fi
done

No matter how hard I push the SS to 'do as less as you can' I still sometimes miss some parts of cerebellum and temporal lobe.

I've opted instead to use 3dSkullstrip directly with the Inv-2 as a base - and it seems to get pretty good results. I then use that result as a mask for the rest of my mp2rage sequences, including the denoised one, which is the dset I'm trying to move to MNI.
As you can see in the code above - I'm inputting a SS mp2rage denoised dataset to move to MNI (mp2r.den=mp2rage denoised), but I can't seem to find an option to let SSwarper know I'm only interested in the transition to template, without the stripping. See attached anatSS file -

I also tried using the mask_ss option -

       sswarper2                                                                       \
		   -input  anat_mask_inv2/$subject.$experiment.$session.mp2r.den_SS+orig.BRIK   \
		   -base   $abin_path/MNI152_2009_template_SSW.nii.gz                           \
		   -subid  $subject.$experiment.$session.$anattype								\
		   -odir   $output_path															\
		   -mask_ss $data/7TMS/$subject/anat/$session/mp2r.inv2/anat_mask_inv2/Automask_inv2+orig.BRIK
    fi

The result from this looks awfully similar to the one I posted above.
I then tried running again using SSwarper (#1, not 2) -

 @sswarper                                                                       \
		   -input  anat_mask_inv2/$subject.$experiment.$session.mp2r.den_SS+orig.BRIK   \
		   -base   $abin_path/MNI152_2009_template_SSW.nii.gz                           \
		   -subid  $subject.$experiment.$session.$anattype								\
		   -odir   $output_path															\
		   -mask_ss $data/7TMS/$subject/anat/$session/mp2r.inv2/anat_mask_inv2/Automask_inv2+orig.BRIK
    fi

The result looks a little better, but still not perfect (or is it good enough? I'm not sure - I'm posting the photo in the next post b/c of the media limit) -

I also tried running the init_skullstr_off option (although I'm not sure it fits here) and it caused an error saying that the option is not known..

The thing is that the SS using 3dSkullstrip outside of SSwarper looks really good! I also tried stripping with Freesurfer and that also looks good.

So it boils down to several options (I think :slight_smile: )
a. Using SSwarper without any stripping at all - is there a way to do so?
b. Using another AFNI command to move to MNI, and receiving the 2 warp files that SSwarper outputs in order to use them as a matrix for the other anatomical sequences (FLAIR, SWI, T2*, T2).
Which commands should I look at? How should I use them?

The issue with option b is that I think that might cause problems when I move on to using the proc.py command, as SSwarper outputs nice files that proc needs and is sometimes upset otherwise :). If I move to MNI using a dataset that I stripped with Freesurfer, how can I make sure that I have everything I need to use proc py later on?

I hope this is clear, Thank you again!!!!

anatSS for running SSwarper1 with a input dataset that is skullstripped ahead of time using INV2 as a base for making a mask to deploy on the denoised output.