Coder Social home page Coder Social logo

jfortin1 / ravel Goto Github PK

View Code? Open in Web Editor NEW
26.0 5.0 12.0 1.15 MB

Intensity normalization of structural MRIs using RAVEL

R 3.26% HTML 96.74%
brain-imaging image-normalization image-preprocessing image-processing mri normalization ravel smri structural-mri

ravel's Introduction

RAVEL

Intensity normalization methods for structural MRIs

Creator: Jean-Philippe Fortin, [email protected]

Authors: Jean-Philippe Fortin, John Muschelli

License: GPL-2

Software status
Resource: Travis CI
Platform: OSX
R CMD check Build status
References
Method Citation Paper Link
RAVEL Jean-Philippe Fortin, Elizabeth M Sweeney, John Muschelli, Ciprian M Crainiceanu, Russell T Shinohara, Alzheimer’s Disease Neuroimaging Initiative, et al. Removing inter-subject technical variability in magnetic resonance imaging studies. NeuroImage, 132:198–212, 2016. Link
WhiteStripe Russell T Shinohara, Elizabeth M Sweeney, Jeff Goldsmith, Navid Shiee, Farrah J Mateen, Peter A Calabresi, Samson Jarso, Dzung L Pham, Daniel S Reich, Ciprian M Crainiceanu, Australian Imaging Biomarkers Lifestyle Flagship Study of Ageing, and Alzheimer’s Disease Neuroimaging Initiative. Statistical normalization techniques for magnetic resonance imaging. Neuroimage Clin, 6:9–19, 2014. Link

Table of content

1. Introduction

RAVEL is an R package that combines the preprocessing and statistical analysis of magnetic resonance imaging (MRI) datasets within one framework. Users can start with raw images in the NIfTI format, and end up with a variety of statistical results associated with voxels and regions of interest (ROI) in the brain. RAVEL stands for Removal of Artificial Voxel Effect by Linear regression, the main preprocessing function of the package that allows an effective removal of between-scan unwanted variation. We have shown in a recent paper that RAVEL improves significantly population-wide statistical inference. RAVEL is now part of the Neuroconductor project.

Installation

The following dependencies need to be installed first:

install.packages("devtools")
devtools::install_github("muschellij2/neurobase")
devtools::install_github("muschellij2/WhiteStripe")

RAVEL can be installed using the following command:

devtools::install_github("jfortin1/RAVEL")

2. Image preprocessing

We present a pre-normalization preprocessing pipeline implemented in the R software, from raw images to images ready for intensity normalization and statistical analysis. Once the images are preprocessed, users can apply their favorite intensity normalization and the scan-effect correction tool RAVEL as presented in Section 1 above. We present a preprocessing pipeline that uses the R packages ANTsR and fslr. While we have chosen to use a specific template space (JHU-MNI-ss), a specific registration (non-linear diffeomorphic registration) and a specific tissue segmentation (FSL FAST), users can choose other algorithms prior to intensity normalization and in order for RAVEL to work. The only requirement is that the images are registered to the same template space.

2.1. Prelude

To preprocess the images, we use the packages fslr and ANTsR. The package fslr is available on CRAN, and requires FSL to be installed on your machine; see the FSL website for installation. For ANTsR, we recommend to install the latest stable version available at the ANTsR GitHub page. The version used for this vignette was ANTsR_0.3.2.tgz. For the template space, we use the JHU-MNI-ss atlas (see Section 1.2) included in the EveTemplate package, available on GitHub at https://github.com/Jfortin1/EveTemplate. For data examples, we use 4 T1-w scans from the package RAVELData available on GitHub at https://github.com/Jfortin1/RAVELData. Once the packages are properly installed, we are ready to start our preprocessing of T1-w images. We first load the packages into R:

library(fslr)
library(ANTsR)
library(RAVELData)
library(EveTemplate)
have.fsl() # Should be TRUE if fsl is correctly installed

and let’s specify the path for the different files that we will need:

# JHU-MNI-ss template:
library(EveTemplate)
template_path <- getEvePath("T1")
# JHU-MNI-ss template brain mask:
template_brain_mask_path <- getEvePath("Brain_Mask")
# Example of T1-w MPRAGE image
scan_path <- system.file(package="RAVELData", "extdata/scan1.nii.gz")

2.2. JHU-MNI-ss template (_EVE_ atlas)

2.3. Registration to template

Tp perform a non-linear registration to the JHU-MNI-ss template, one can use the diffeomorphism algorithm via the ANTsR package. Note that we perform the registration with the skulls on. Here is an example where we register the scan1 from the RAVELData package to the JHU-MNI-ss template:

library(ANTsRCore)
library(ANTsR)
template    <- antsImageRead(template_path, 3)
scan <- antsImageRead(scan_path,3)
outprefix <- gsub(".nii.gz","",scan_path) # Prefix for the output files
output <- antsRegistration(fixed = template, moving = scan, typeofTransform = "SyN",  outprefix = outprefix)
scan_reg   <- antsImageClone(output$warpedmovout) # Registered brain

The object scan_reg contains the scan registed to the template. Note that the object is in the ANTsR format. Since I prefer to work with the oro.nifti package, which is compatible with flsr, I convert the object to a nifti object using the function ants2oro as follows:

# devtools::install_github("muschellij2/extrantsr")
# or
# source("https://neuroconductor.org/sites/default/files/neurocLite.R")
# neuro_install("extrantsr")
library(extrantsr)
scan_reg <- extrantsr::ants2oro(scan_reg)

We can save the registered brain in the NIfTi format using the writeNIfTI command:

writeNIfTI(scan_reg, "scan_reg")

Since scan_reg is converted to a nifti object, we can use the function ortho2 from the fslr package to visualize the scan:

ortho2(scan_reg, crosshairs=FALSE, mfrow=c(1,3), add.orient=FALSE)

2.4. Intensity inhomogeneity correction

We perform intensity inhomogeneity correction on the registered scan using the N4 Correction from the ANTsR package:

scan_reg <- extrantsr::oro2ants(scan_reg) # Convert to ANTsR object
scan_reg_n4 <- n4BiasFieldCorrection(scan_reg)
scan_reg_n4 <- extrantsr::ants2oro(scan_reg_n4) # Conversion to nifti object for further processing

2.5. Skull stripping

template_brain_mask <- readNIfTI(template_brain_mask_path, reorient=FALSE)
scan_reg_n4_brain <- niftiarr(scan_reg_n4, scan_reg_n4*template_brain_mask)
ortho2(scan_reg_n4_brain, crosshairs=FALSE, mfrow=c(1,3), add.orient=FALSE)

2.6. Tissue Segmentation

There are different tissue segmentation algorithms available in R. My favorite is the FSL FAST segmentation via the fslr package. Let’s produce the tissue segmentation for the scan_reg_n4_brain scan above:

ortho2(scan_reg_n4_brain, crosshairs=FALSE, mfrow=c(1,3), add.orient=FALSE, ylim=c(0,400))

The last line of code produces via the ortho2 function from the fslr package the following visualization of the template:

We perform a 3-class tissue segmentation on the T1-w image with the FAST segmentation algorithm:

scan_reg_n4_brain_seg <- fast(scan_reg_n4_brain, verbose=FALSE, opts="-t 1 -n 3") 
ortho2(scan_reg_n4_brain_seg, crosshairs=FALSE, mfrow=c(1,3), add.orient=FALSE)

The object scan_reg_n4_brain_seg is an image that contains the segmentation labels 0,1,2 and 3 referring to Background, CSF, GM and WM voxels respectively.

2.7. Creation of a tissue mask

Suppose we want to create a mask for CSF.

scan_reg_n4_brain_csf_mask <- scan_reg_n4_brain_seg
scan_reg_n4_brain_csf_mask[scan_reg_n4_brain_csf_mask!=1] <- 0
ortho2(scan_reg_n4_brain_csf_mask, crosshairs=FALSE, mfrow=c(1,3), add.orient=FALSE)

We use the fact that the file scan_reg_n4_brain_seg is equal to 1 for CSF, 2 for GM and 3 for WM. For instance, a WM mask could be created as follows:

scan_reg_n4_brain_wm_mask <- scan_reg_n4_brain_seg
scan_reg_n4_brain_wm_mask[scan_reg_n4_brain_wm_mask!=3] <- 0
ortho2(scan_reg_n4_brain_wm_mask, crosshairs=FALSE, mfrow=c(1,3), add.orient=FALSE)

3. Intensity normalization and RAVEL correction

Since MRI intensities are acquired in arbitrary units, image intensities are not comparable across scans, between subjects and across sites. Intensity normalization (or intensity standardization) is paramount before performing between-subject intensity comparisons. The RAVEL package includes the popular histogram matching normalization (normalizeHM) as well as the White Stripe normalization (normalizeWS); see the table below for the reference papers. Once the images intensities are normalized, the RAVEL correction tool can be applied using the function normalizeRAVEL to remove additional unwanted variation using a control region. Because we have found that the combination White Stripe + RAVEL was best at removing unwanted variation, the function normalizeRAVEL performs White Stripe normalization by default prior to the RAVEL correction.

Note: registration is also called spatial normalization which is unrelated to intensity normalization.

Available methods
Function Method Modalities supported at the moment Paper Link
normalizeRaw No normalization T1, T2, FLAIR, PD
normalizeRAVEL RAVEL T1, T2, FLAIR Link
normalizeWS White Stripe T1, T2, FLAIR Link
normalizeHM Histogram Matching T1, T2, FLAIR, PD Link
normalizeZScore Z-score transformation T1, T2, FLAIR, PD

Briefly, each function takes as input a list of NIfTI file paths specifying the images to be normalized, and return a matrix of normalized intensities where rows are voxels and columns are scans. We note that the input files must be the files associated with preprocessed images registered to a common template. The different functions are described below.

3.1 No normalization

The function normalizeRaw takes as input the preprocessed and registered images, and create a matrix of voxel intensities without intensity normalization. For conventional MRI images, we recommend to apply an intensity normalization to the images (see normalizeWS or normalizeRAVEL). The main purpose of the function normalizeRaw is for exploration data analysis (EDA), methods development and methods comparison.

Argument Description Default
input.files vector or list of the paths for the input NIfTI image files to be normalized
output.files Optionnal vector or list of the paths for the output images. By default, will be the input.files with "_RAW" appended at the end. NULL
brain.mask NIfTI image path for the binary brain mask. Must have value 1 for the brain and 0 otherwise
returnMatrix Should the matrix of normalized images be returned? Rows correspond to voxels specified by brain.mask, and columns correspond to scans. TRUE
writeToDisk Should the normalized images be saved to the disk as NIfTI files? FALSE
verbose Should the function be verbose? TRUE

3.2 White Stripe normalization

The function normalizeWS takes as input the preprocessed and registered images, applies the White Stripe normalization algorithm to each image separately via the WhiteStripe R package, and creates a matrix of normalized voxel intensities. Note that the White Stripe normalization is also included as a first step in the RAVEL algorithm implemented in the normalizeRAVEL function.

Argument Description Default
input.files vector or list of the paths for the input NIfTI image files to be normalized
output.files Optionnal vector or list of the paths for the output images. By default, will be the input.files with "_WS" appended at the end. NULL
brain.mask NIfTI image path for the binary brain mask. Must have value 1 for the brain and 0 otherwise
WhiteStripe_Type What is the type of images to be normalized? Must be one of “T1”, “T2” and “FLAIR”. T1
returnMatrix Should the matrix of normalized images be returned? Rows correspond to voxels specified by brain.mask, and columns correspond to scans. TRUE
writeToDisk Should the normalized images be saved to the disk as NIfTI files? FALSE
verbose Should the function be verbose? TRUE

3.3 Histogram matching normalization

The function normalizeHM takes as input the preprocessed and registered images, applies the Histogram matching normalization algorithm to each image separately, and creates a matrix of normalized voxel intensities.

Argument Description Default
input.files vector or list of the paths for the input NIfTI image files to be normalized
output.files Optionnal vector or list of the paths for the output images. By default, will be the input.files with "_WS" appended at the end. NULL
brain.mask NIfTI image path for the binary brain mask. Must have value 1 for the brain and 0 otherwise
type What is the type of images to be normalized? Must be one of “T1”, “T2”, "PD", and “FLAIR”. T1
returnMatrix Should the matrix of normalized images be returned? Rows correspond to voxels specified by brain.mask, and columns correspond to scans. TRUE
writeToDisk Should the normalized images be saved to the disk as NIfTI files? FALSE
verbose Should the function be verbose? TRUE

3.4 Z-score transformation (whole-brain)

The function normalizeZScore takes as input the preprocessed and registered images, applies a whole-brain z-score transformation to each image separately, and creates a matrix of normalized voxel intensities.

Argument Description Default
input.files vector or list of the paths for the input NIfTI image files to be normalized
output.files Optionnal vector or list of the paths for the output images. By default, will be the input.files with "_WS" appended at the end. NULL
brain.mask NIfTI image path for the binary brain mask. Must have value 1 for the brain and 0 otherwise
type What is the type of images to be normalized? Must be one of “T1”, “T2”, "PD", and “FLAIR”. T1
returnMatrix Should the matrix of normalized images be returned? Rows correspond to voxels specified by brain.mask, and columns correspond to scans. TRUE
writeToDisk Should the normalized images be saved to the disk as NIfTI files? FALSE
verbose Should the function be verbose? TRUE

3.5 RAVEL normalization

The function normalizeRAVEL takes as input the preprocessed and registered images, and a control region mask, and applies the RAVEL correction method to create a matrix of normalized voxel intensities. The White Stripe normalization is included by default as a first step in the RAVEL algorithm. The next section explains how to create a control region mask.

Argument Description Default
input.files vector or list of the paths for the input NIfTI image files to be normalized
output.files Optionnal vector or list of the paths for the output images. By default, will be the input.files with "_RAVEL" appended at the end. NULL
brain.mask NIfTI image path for the binary brain mask. Must have value 1 for the brain and 0 otherwise
control.mask NIfTI image path for the binary control region mask. Must have value 1 for the control region and 0 otherwise. See the helper function mask_intersect for the creation of a control.mask.
mod Model matrix for outcome of interest and other covariates NULL
WhiteStripe Should White Stripe normalization be performed before RAVEL? TRUE
WhiteStripe_Type If WhiteStripe is TRUE, what is the type of images to be normalized? Must be one of “T1”, “T2” and “FLAIR”. T1
k Integer specifying the number of principal components to be included in the RAVEL correction. 1
returnMatrix Should the matrix of normalized images be returned? Rows correspond to voxels specified by brain.mask, and columns correspond to scans. TRUE
writeToDisk Should the normalized images be saved to the disk as NIfTI files? FALSE
verbose Should the function be verbose? TRUE

3.6 Creation of a control region for RAVEL

RAVEL uses a control region of the brain to infer unwanted variation across subjects. The control region is made of voxels known to be not associated with the phenotype of interest. For instance, it is known that CSF intensities on T1-w images are not associated with the progression of AD. The control region must be specified in the argument control.mask of the function normalizeRAVEL as a path to a NIfTI file storing a binary mask. In the case of a CSF control region, one way to create such a binary mask is to create a CSF binary mask for each scan first, and then to take the intersection of all those binary masks. This can be done with the function maskIntersect in RAVEL. The function takes as input a list of binary masks (either nifti objects or a list of NIfTI file paths), and will output the intersection of all the binary masks. By default, the function will save the intersection mask to the disk as a NIfTI file, as specified by output.file:

Example:

dir   <- file.path(find.package("RAVELData"), "extdata")
masks <- list.files(dir, full.names=TRUE, pattern="*mask*.nii*")
intersect_mask  <- maskIntersect(masks, output.file=tempfile())

When the number of subjects is large, the intersection mask may be empty, as a consequence of anatomical variation between subjects. As a solution, the function maskIntersect has the option to create an intersection mask that is less stringent by requiring the control region to be present in only a given percentage of the subjects, using the option prob. By default, prob is equal to 1, meaning 100% of the subjects has the final voxels labelled as CSF. For instance, to require that the final control region is shared for at least 90% of the subjects, one would type

intersect_mask  <- maskIntersect(masks, output.file=tempfile(), prob=0.9)

For studies with a small number of subjects, the opposite problem may arise: too many voxels labelled as CSF, close to the skull, might be retained in the final intersection mask. Mask erosion, for instance using fslr, may be performed to remove such voxels and refine the control mask.

3.7 Controlling for biological covariates in RAVEL

In removing the unwanted variation estimated using control voxels, it is possible to preserve biological variation by specifying biological covariates in the normalizeRAVEL function, similar to ComBat harmonization.

For instance, suppose we want to normalize intensities across participants using CSF, and also want to make sure that we don't remove variation in intensities associated with age. We first need to build a model matrix for the biological covariates (here age):

age <- c(70,62,43,76) #Simulated age
gender <- c("M", "M", "F", "F")
mod <- model.matrix(~age+gender)

Note that while the model matrix has an intercept column, this will be automatically handled internally by the normalizeRAVEL function. To run RAVEL while adjusting for age and gender, we include mod as an argument as follows:

Y.ravel.mod <- normalizeRAVEL(input.files=input.files,
	control.mask=control.mask,
	brain.mask=brain.mask,
	k=1, 
	mod=mod,
	returnMatrix=TRUE,
	WhiteStripe=FALSE
)

Logo from: https://openclipart.org/detail/14743/violin-bow

ravel's People

Contributors

jfortin1 avatar muschellij2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

ravel's Issues

RAVEL normalisation in subject space

Hello,

I'm performing RAVEL normalisation of T1- and T2-weighted images following the README.md, but this involves non-linear registration to a template and I need the output in the original subject space.

It's possible to back-transform the RAVEL normalised images to the subject space using antsApplyTransforms, but this leads to multiple transformations with ensuing interpolations. Is there any way to perform the RAVEL normalisation directly in the subject space?

Bad output

I am trying to use RAVEL on a set of deformably co-registered T1-w MR images, but the algorithm is not working as expected. An example result is shown in the picture below:

ravel_result

For more information, the control (CSF) mask I am using seems to make sense and I am providing the input in the way the documentation seems to suggest using the RAVEL package. Note that I am using the WhiteStripe option in this example, but I have used the package without WhiteStripe and gotten similar results.

Does the input require any additional processing that I am not doing to produce a good result? I can provide more detail as needed.

Thanks for the help

Possible Bug - normalizeRAVEL output

Hello,

I am normalizing MRI images of glioma patients using several methods. I have noticed that the output matrix of normalized images is exactly the same using the RAVEL and White Stripe method. Although the actual normalized images are different.

Looking deeper into the code, I think I have found a small bug in the normalizeRAVEL function, specifically in the final lines, where it reads:
if (returnMatrix) { return(V) }
Shouldn't it be?
if (returnMatrix) { return(V.norm) }

Thanks for your help!

could not find function "ants2oro"

Hi JP
I got to here scan_reg <- ants2oro(scan_reg) and then got an error message
Error in ants2oro(scan_reg) : could not find function "ants2oro"

I've got oro.nifti all loaded up but ......

Thanks
Anna

Funky "normalized" T1w's

Hello human(s),

I am attempting to execute normalizeRAVEL on a patient set of 10. The command I execute is rav <- normalizeRAVEL(infiles, out.files = NULL, brain.mask = bmask, control.mask = cmask, WhiteStripe_Type = "T1", writeToDisk = TRUE, stripped = TRUE)

The cmask variable was created using cmask <- maskIntersect(csf_masks, output.file="intersection_mask.nii.gz", prob=1.0)

An image of cmask:

image

The underlying T1w is MNI-registered, and while it contains a skull (used to evaluate CSF mask) the T1w's in the normalization command above are skull-stripped.

An image of a single normalization brain:

image

Any ideas? Across the 10 patients the intensities ranges are -

(0.000000 3728.828125) | (0.000000 5149.502441) | (0.000000 2619.226074) | (0.000000 2390.880127) | (0.000000 4490.105469) | (0.000000 1955.639648) | (0.000000 4625.776855) | (0.000000 5375.570801) | (0.000000 4419.894043)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.