```{r setup, include=FALSE} library(methods) knitr::opts_chunk$set(echo = TRUE, comment = "") library(extrantsr) ``` ## Overall Pipeline ## Brain Extraction 3 Different Attempts In this tutorial we will discuss performing brain segmentation using: - the brain extraction tool (BET) [@smith_fast_2002] in `FSL` [@jenkinson_fsl_2012] - without bias correction (method 1) and with (method 2) - a multi-atlas approach, called "multi-atlas label fusion" with the `malf` command (method 3). - (extra slides) a robust version using a wrapper function in `extrantsr`, `fslbet_robust` ## MS Lesion T1 Let's reset and read in the T1 image from a MS lesion data set: ```{r reading_in_image, message = FALSE, eval = FALSE} library(neurobase) t1_fname = "training01_01_t1.nii.gz" t1 = neurobase::readnii(t1_fname) rt1 = robust_window(t1, probs = c(0, 0.975)); red0.5 = scales::alpha("red", 0.5) # for plotting later ``` ```{r reading_in_image_run, message = FALSE, echo = FALSE} library(neurobase) t1_fname = "../training01_01_t1.nii.gz" t1 = neurobase::readnii(t1_fname) rt1 = robust_window(t1, probs = c(0, 0.975)); red0.5 = scales::alpha("red", 0.5) # for plotting later ``` ## T1-weighted T1 Image ```{r t1_plot_robust} ortho2(rt1) ``` ## Attempt 1: Brain Extraction of T1 image using BET Here we will use FSL's Brain Extraction Tool (BET) to extract the brain tissue from the rest of the image (general overview): - 2nd and 98th percentiles are calculated. (98th - 2nd) * 10% + 2nd percentile used to threshold out background - From non-thresholded voxels - calculate center of gravity (COG) - Calculate radius of brain and median intensity of all points within "spherical brain" (used in last step) - Perform region growing and iterating to get brain surface - Smooth surface - Use median intensity to shrink surface to the "real" surface ## Attempt 1: Brain Extraction of T1 image using BET `fslr` - wraps FSL commands to use in R - registration, image manipulation `fslr::fslbet` - takes in a filename/nifti and calls FSL `bet` function - additional options can be passed to FSL command in using `opts` ```{r t1_naive_ss, eval = FALSE, cache = FALSE, message = FALSE, warning = FALSE} library(fslr) ss = fslbet(infile = t1_fname) ``` ```{r t1_naive_ss_run, echo = FALSE, cache = FALSE, message = FALSE, warning = FALSE} library(fslr) out_fname = "../output/naive_ss.nii.gz" if (!file.exists(out_fname)) { ss = fslbet(infile = t1_fname) writenii(ss, out_fname) } else { ss = readnii(out_fname) } ``` ## FSL BET Results - Missing Brain Tissues (Posterior) ```{r t1_naive_plot_ss} ortho2(robust_window(ss)) ``` ## FSL BET Results not Satisfactory ```{r t1_ss_plot} ortho2(rt1, ss > 0, col.y = red0.5) ``` ## Attempt 2: Bias Correct before BET (recommended) Before doing skull-stripping/brain extraction, we would do bias correction: ```{r bc_show, eval = FALSE} library(extrantsr) bc_img = bias_correct(file = t1, correction = "N4") ``` ```{r bc_show_run, echo = FALSE} bc_fname = "../output/training01_01_t1_n4.nii.gz" if (!file.exists(bc_fname)) { bc_img = bias_correct(file = t1, correction = "N4") writenii(bc_img, bc_fname) } else { bc_img = readnii(bc_fname) } bc_img = robust_window(bc_img) ``` ```{r bc_bet, eval = FALSE, message = FALSE} bc_bet = fslbet(bc_img); ortho2(bc_img, bc_bet > 0, col.y = red0.5) ``` ```{r bc_bet_run, message = FALSE, echo = FALSE} out_fname = "../output/bc_bet_ss.nii.gz" if (!file.exists(out_fname)) { bc_bet = fslbet(bc_img); writenii(bc_bet, out_fname) } else { bc_bet = readnii(out_fname) } ortho2(bc_img, bc_bet > 0, col.y = red0.5) ``` ## MALF for Skull Stripping
Figure from Multi-Atlas Skull Stripping method paper [@mass]:
- Register templates to an image using the T1 for that subject - Apply transformation to the label/mask - Average each voxel over all templates - there are "smarter" (e.g. weighted) ways
## MALF - use `extrantsr::malf` - Function requires arguments: `template.images` (T1-weighted images in this case) and `template.structs` (labels/structures/masks, brain masks here) - We will use the `extrantsr::malf` function - Performs non-linear registration using Symmetric Normalization (`SyN`) [@avants_symmetric_2008], a form of diffeomorphic registration: - combines the template structures ```{r t1_malf_ss, echo = TRUE, eval = FALSE} library(malf.templates) # load the data package library(extrantsr) timgs = mass_images(n_templates = 5) # let's register 5 templates ss = extrantsr::malf( infile = bc_img, template.images = timgs$images, template.structs = timgs$masks, keep_images = FALSE # don't keep the registered images ) mask = ss > 0 ``` ```{r t1_malf_ss_run, echo = FALSE, message = FALSE} library(malf.templates) library(extrantsr) timgs = mass_images(n_templates = 5) outfile = "../output/training01_01_t1_mask.nii.gz" if (!file.exists(outfile)) { ss = malf( infile = bc_fname, template.images = timgs$images, template.structs = timgs$masks, keep_images = FALSE, verbose = FALSE, outfile = outfile ) } else { ss = readnii(outfile) } mask = ss > 0 ``` ## MALF performs well ```{r show_them, eval = FALSE} mask = readnii("training01_01_t1_mask.nii.gz") # already computed ``` ```{r display_malf_result} ortho2(bc_img, mask, col.y = red0.5) ``` ## Conclusions from the MS data - FSL BET can perform brain extraction (additional ex shows when it works) - It did not work sufficiently here - There are options you can change for performance - Bias-correction before brain extraction is a good idea - Especially if the method depends on intensities - Didn't change the results here - MALF/MASS is a good option, but needs templates and is computationally expensive - weighted templates or local weighting is done in other software (not discussed) ## Website http://johnmuschelli.com/imaging_in_r # Extra Slides are showing additional BET options ## Additional Example FSL BET did not work in the previous data set. It works in many cases, though. We will look at a subject from the kirby21 dataset [@landman2011multi]. ```{r} library(kirby21.t1) t1_fname = get_t1_filenames()[1] t1 = readnii(t1_fname) ``` ## T1 image has the neck! ```{r kirby21_t1_plot} ortho2(robust_window(t1)) ``` ## Neck messes up BET ```{r kirby21_t1_naive_ss_run, cache = FALSE, message = FALSE, echo = FALSE} out_fname = "../output/kirby_naive_ss.nii.gz" if (!file.exists(out_fname)) { ss = fslbet(infile = t1_fname) writenii(ss, out_fname) } else { ss = readnii(out_fname) } ortho2(robust_window(ss)) ``` ```{r kirby21_t1_naive_ss_show, eval = FALSE, cache = FALSE, message = FALSE} ss = fslbet(infile = t1_fname); ortho2(robust_window(ss)) ``` ## Recommend to Bias Correct first: not fixed ```{r kirby21_bc_bet_show, message = FALSE, eval = FALSE} bc_img = bias_correct(t1, correction = "N4"); bc_bet = fslbet(bc_img) ortho2(robust_window(t1), bc_bet > 0, col.y = red0.5) ``` ```{r kirby21_bc_bet_run, message = FALSE, echo = FALSE} out_fname = "../output/kirby_bc.nii.gz" if (!file.exists(out_fname)) { bc_img = bias_correct(t1, correction = "N4"); writenii(bc_img, out_fname) } else { bc_img = readnii(out_fname) } out_fname = "../output/kirby_bc_bet.nii.gz" if (!file.exists(out_fname)) { bc_bet = fslbet(bc_img) writenii(bc_bet, out_fname) } else { bc_bet = readnii(out_fname) } ortho2(robust_window(t1), bc_bet > 0, col.y = red0.5) ``` ## BET with neck removal We use the modification of BET in `extrantsr`, which is called through `fslbet_robust`. `fslbet_robust`: - bias correct image - remove neck (`double_remove_neck` performs 2 registration steps, more robust than one (which is the default).) - run BET - estimate center of gravity (COG) - run BET again with new COG ## `fslbet_robust` syntax ```{r, eval = FALSE} ss = extrantsr::fslbet_robust( t1, remover = "double_remove_neck", correct = TRUE, correction = "N4", recog = TRUE) ``` ## BET with neck removal - works well! ```{r t1_ss, cache = FALSE, echo = FALSE} outfile = nii.stub(t1_fname, bn = TRUE) outfile = file.path("..", "output", paste0(outfile, "_SS.nii.gz")) if (!file.exists(outfile)) { ss = extrantsr::fslbet_robust(t1_fname, remover = "double_remove_neck", outfile = outfile) } else { ss = readnii(outfile) } ``` ```{r kirby21_t1_ss_plot_show, cache = TRUE, eval = FALSE} ortho2(ss) ``` ```{r kirby21_t1_ss_plot_run, echo = FALSE, cache = TRUE} ortho2(dropEmptyImageDimensions(ss)) ``` ## Conclusions - Brain extraction allows you to analyze the brain only - Important for tissue segmentation/registration - BET may work (look at your data!) - Should bias correct first - May need to remove neck - High values may affect results - may need to remove/Winsorize them ## Website http://johnmuschelli.com/imaging_in_r ## References {.smaller}