-
Notifications
You must be signed in to change notification settings - Fork 6
White matter hyperintensity (WMH) segmentation
White Matter Hyperintensities (WMHs) are abnormalities in the brain's white matter that are usually detected on FLAIR MRI images. They represent markers of cerebral small vessel disease. They appear mostly in aging populations and are linked with vascular risk factors, adverse cognitive outcomes, and dementia.
This wiki explains how to use an automated WMH segmentation pipeline developed by Dr. Mahsa Dadar (see Dadar et al., 2017a; Dadar et al., 2017b; and many others)
One strength of this pipeline is that it can use any combination of T1w, T2w, and FLAIR inputs (i.e., even if FLAIR is the optimal modality for WMH segmentation, you can still use the pipeline to segment WMHs with only T1w and/or T2w, although with reduced sensitivity).
However, this wiki is made for using T1w, T2w, and FLAIR, but the code can be easily adapted for other modality combinations.
Of note, the code works with the ADNI template as opposed to the ICBM template. For non-AD subjects, the code would have to be adapted to work with the ICBM template.
The WMH segmentation code requires:
- Python 2.7.15
- numpy 1.10.4
- scikit-learn 0.17
- pyezminc
The preprocessing also requires
- minc-toolkit 1.9.17
- minc-toolkit-extras 1.9.17
- minc-stuffs 0.1.24
- iterativeN3.sh (https://github.com/CoBrALab/iterativeN3)
It is recommended to work in a virtual environment. On Niagara, a virtual environment can be created and all dependencies installed/loaded with the following code (specify /path/to/your/WMH/segmentation/directory)
# Load python modules
module load cobralab/2019b
module unload intelpython3
module load python/2.7.15
# Create and activate virtual environment
cd ~/.virtualenvs
virtualenv --system-site-packages ~/.virtualenvs/WMH_env
source ~/.virtualenvs/WMH_env/bin/activate
# Install the right versions of python packages
pip install --upgrade numpy
pip install --upgrade scikit-learn==0.17
# Download and install pyezminc
git clone https://github.com/BIC-MNI/pyezminc/
cd pyezminc
~/.virtualenvs/WMH_env/bin/python setup.py install
cd /path/to/your/WMH/segmentation/directory
# Download and install iterativeN3.sh
git clone https://github.com/CoBrALab/iterativeN3
To use the ADNI template with the iterativeN3.sh script (which is needed), the iterativeN3.sh needs to be slightly modified. More specifically, comment lines 17 to 21 (KEEP LINE 22), and uncomment lines 11-15, as follows:
#!/bin/bash
set -euo pipefail
set -x
BEASTLIBRARY_DIR="${QUARANTINE_PATH}/resources/BEaST_libraries/combined"
RESAMPLEMODEL="${QUARANTINE_PATH}/resources/mni_icbm152_nlin_sym_09c_minc2/mni_icbm152_t1_tal_nlin_sym_09c.mnc"
RESAMPLEMASK="${QUARANTINE_PATH}/resources/mni_icbm152_nlin_sym_09c_minc2/mni_icbm152_t1_tal_nlin_sym_09c_mask.mnc"
# ADNI Model
REGISTRATIONMODEL="${QUARANTINE_PATH}/resources/adni_model_3d_v2/model_t1w.mnc"
REGISTRATIONMODELMASK="${QUARANTINE_PATH}/resources/adni_model_3d_v2/model_t1w_mask.mnc"
WMPRIOR="${QUARANTINE_PATH}/resources/adni_model_3d_v2/wm.mnc"
GMPRIOR="${QUARANTINE_PATH}/resources/adni_model_3d_v2/gm.mnc"
CSFPRIOR="${QUARANTINE_PATH}/resources/adni_model_3d_v2/csf.mnc"
# REGISTRATIONMODEL="${QUARANTINE_PATH}/resources/mni_icbm152_nlin_sym_09c_minc2/mni_icbm152_t1_tal_nlin_sym_09c.mnc"
# REGISTRATIONMODELMASK="${QUARANTINE_PATH}/resources/mni_icbm152_nlin_sym_09c_minc2/mni_icbm152_t1_tal_nlin_sym_09c_mask.mnc"
# WMPRIOR="${QUARANTINE_PATH}/resources/mni_icbm152_nlin_sym_09c_minc2/mni_icbm152_wm_tal_nlin_sym_09c.mnc"
# GMPRIOR="${QUARANTINE_PATH}/resources/mni_icbm152_nlin_sym_09c_minc2/mni_icbm152_gm_tal_nlin_sym_09c.mnc"
# CSFPRIOR="${QUARANTINE_PATH}/resources/mni_icbm152_nlin_sym_09c_minc2/mni_icbm152_csf_tal_nlin_sym_09c.mnc"
DEEPGMPRIOR=""
Create the following directory structure:
mkdir Preprocessed
mkdir T1
mkdir T2
mkdir FLAIR
mkdir Trained_Classifiers
mkdir WMH_mask_native
mkdir results_csv
Populate the folders with the following files:
- T1: raw T1w scans in minc format with with the pattern ID_t1.mnc
- T2: raw T2w scans in minc format with with the pattern ID_t2.mnc
- FLAIR: raw FLAIR scans in minc format with with the pattern ID_FLAIR.mnc
- Trained Classifiers: previously-trained classifiers from this dropbox
- Main folder: WMHSP.py from this dropbox
This custom preprocessing script does:
- bias-field correction of the T1w with the iterative N3 script (includes brain mask extraction with BeAST)
- denoising with minc_anlm
- bias-field correction for the other modalities with nu_correct
- intensity normalization of every scan between 0-100
- rigid registration of other modalities to optimal modality (see below) with ANTs
- linear+non-linear registration of optimal modality to ADNI template with ANTs
- generates csv used as input for the WMH segmentation pipeline.
The optimal modality is the one with the best contrast for WMHs (FLAIR > T2w > T1w) The following script assumes that the user has FLAIR, T2w and T1w, and thus registers the other scans to FLAIR. However, this can be modified depending on the types of scans available. It is recommended to save this code as a script named WMH_preprocessing.sh, then call the script from bash with the ID as an argument (see below)
# All preprocessing required for WMH segmentation algorithm
# Dependencies
# - module load cobralab
# - iterativeN3.sh (modified for ADNI template) in iterativeN3 folder
# - raw T1s in T1 folder with ID_t1.mnc names
# - raw T2s in T2 folder with ID_t2.mnc names
# - raw FLAIR in FLAIR folder with ID_FLAIR.mnc names
# - Preprocessed folder for outputs
# Outputs for WMH segmentation inputs
# - Preprocessed T1w: ./Preprocessed/ID_t1_itN3.NLM.NORM.linregFLAIR.mnc
# - Preprocessed T2w: ./Preprocessed/ID_t2.linregFLAIR.RSL.NLM.N3.NORM.mnc
# - Preprocessed FLAIR: ./Preprocessed/ID_FLAIR.NLM.N3.NORM.mnc
# - Brain mask: ./Preprocessed/ID_t1_itN3.mask.linregFLAIR.mnc
# - Transform to ADNI: ./Preprocessed/ID_FLAIR_to_ADNI.xfm
ID=$1
######################## T1w ###########################
# iterativeN3 processing for T1w (to ADNI template)
./iterativeN3/iterativeN3.sh ./T1/$(basename $ID)_t1.mnc ./Preprocessed/$(basename $ID)_t1_itN3.mnc
# Additional denoising for T1w
minc_anlm --mt 1 --beta 0.7 --clobber ./Preprocessed/$(basename $ID)_t1_itN3.mnc ./Preprocessed/$(basename $ID)_t1_itN3.NLM.mnc
# Intensity normalization (1-100) for T1w
mincnorm -short -noclamp -clobber -mask ./Preprocessed/$(basename $ID)_t1_itN3.mask.mnc -out_floor 0 -out_ceil 100 ./Preprocessed/$(basename $ID)_t1_itN3.NLM.mnc ./Preprocessed/$(basename $ID)_t1_itN3.NLM.NORM.mnc
######################## FLAIR ###########################
# Register raw T1w to raw FLAIR
antsRegistration_affine_SyN.sh --clobber --linear-type rigid --close --skip-nonlinear ./T1/$(basename $ID)_t1.mnc ./FLAIR/$(basename $ID)_FLAIR.mnc ./Preprocessed/$(basename $ID)_T1.linregFLAIR.
# Resample preprocessed T1w and mask to FLAIR
mincresample -clobber -like ./FLAIR/$(basename $ID)_FLAIR.mnc -invert_transformation -transform ./Preprocessed/$(basename $ID)_T1.linregFLAIR.0_GenericAffine.xfm ./Preprocessed/$(basename $ID)_t1_itN3.NLM.NORM.mnc ./Preprocessed/$(basename $ID)_t1_itN3.NLM.NORM.linregFLAIR.mnc
mincresample -nearest -clobber -like ./FLAIR/$(basename $ID)_FLAIR.mnc -invert_transformation -transform ./Preprocessed/$(basename $ID)_T1.linregFLAIR.0_GenericAffine.xfm ./Preprocessed/$(basename $ID)_t1_itN3.mask.mnc ./Preprocessed/$(basename $ID)_t1_itN3.mask.linregFLAIR.mnc
# Denoising for FLAIR
minc_anlm --mt 1 --beta 0.7 --clobber ./FLAIR/$(basename $ID)_FLAIR.mnc ./Preprocessed/$(basename $ID)_FLAIR.NLM.mnc
# N3 bias field correction for FLAIR
nu_correct -iter 200 -distance 50 -clobber -mask ./Preprocessed/$(basename $ID)_t1_itN3.mask.linregFLAIR.mnc ./Preprocessed/$(basename $ID)_FLAIR.NLM.mnc ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.mnc
# Intensity normalization (1-100) for FLAIR
mincnorm -short -clamp -clobber -mask ./Preprocessed/$(basename $ID)_t1_itN3.mask.linregFLAIR.mnc -out_floor 0 -out_ceil 100 ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.mnc ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.mnc
# Register FLAIR to ADNI template
antsRegistration_affine_SyN.sh --mask-extract --clobber --moving-mask ./Preprocessed/$(basename $ID)_t1_itN3.mask.linregFLAIR.mnc --fixed-mask /project/m/mchakrav/quarantine/resources/adni_model_3d_v2/model_t1w_mask.mnc --resampled-output ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.ADNI.RSL.mnc ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.mnc ./Trained_Classifiers/Av_FLAIR.mnc ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.ADNI.
######################## T2w ###########################
# Register raw T2w to raw FLAIR
antsRegistration_affine_SyN.sh --clobber --linear-type rigid --close --skip-nonlinear ./T2/$(basename $ID)_t2.mnc ./FLAIR/$(basename $ID)_FLAIR.mnc ./Preprocessed/$(basename $ID)_t2.linregFLAIR.
# Resample raw T2w to FLAIR
mincresample -clobber -like ./FLAIR/$(basename $ID)_FLAIR.mnc -invert_transformation -transform ./Preprocessed/$(basename $ID)_t2.linregFLAIR.0_GenericAffine.xfm ./T2/$(basename $ID)_t2.mnc ./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.mnc
# Denoising for T2w
minc_anlm --mt 1 --beta 0.7 --clobber ./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.mnc ./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.NLM.mnc
# N3 bias field correction for T2w
nu_correct -iter 200 -distance 50 -clobber -mask ./Preprocessed/$(basename $ID)_t1_itN3.mask.linregFLAIR.mnc ./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.NLM.mnc ./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.NLM.N3.mnc
# Intensity normalization (1-100) for T2w
mincnorm -short -clamp -clobber -mask ./Preprocessed/$(basename $ID)_t1_itN3.mask.linregFLAIR.mnc -out_floor 0 -out_ceil 100 ./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.NLM.N3.mnc ./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.NLM.N3.NORM.mnc
######################## Final touches ###########################
# Get inverse of linear transformation from FLAIR to ADNI
xfminvert -clobber ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.ADNI.0_GenericAffine.xfm ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.ADNI.0_GenericAffine_inverse.xfm
# Concatenate transforms to get T1w to ADNI
xfmconcat -clobber ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.ADNI.0_GenericAffine_inverse.xfm ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.ADNI.1_inverse_NL.xfm ./Preprocessed/$(basename $ID)_FLAIR_to_ADNI.xfm
# Make csv for WMH segmentation alg input
echo "Subjects,T1s,Masks,XFMs,T2s,FLAIR" > ./Preprocessed/$(basename $ID)_Preprocessed.csv
echo "$(basename $ID),./Preprocessed/$(basename $ID)_t1_itN3.NLM.NORM.linregFLAIR.mnc,./Preprocessed/$(basename $ID)_t1_itN3.mask.linregFLAIR.mnc,./Preprocessed/$(basename $ID)_FLAIR_to_ADNI.xfm,./Preprocessed/$(basename $ID)_t2.linregFLAIR.RSL.NLM.N3.NORM.mnc,./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.mnc" >> ./Preprocessed/$(basename $ID)_Preprocessed.csv
Then, to run the preprocessing pipeline for all subjects:
for file in ./T1/*;
do
echo ./WMH_preprocessing.sh $(basename $file _t1.mnc)
done > joblist_preprocessing
qbatch -w 12:00:00 -c 20 -N WMH_pre joblist_preprocessing
For the WMH segmentation on all subjects, simply run this code (adapt the path to the ADNI template brain mask if not on Niagara).
for file in ./Preprocessed/*_Preprocessed.csv;
do
echo python ./WMHSP.py -c RF -i $file -d N -m /project/m/mchakrav/quarantine/resources/adni_model_3d_v2/model_t1w_mask.mnc -f 10 -o ./WMH_mask_native/ -t ./Preprocessed/ -e PT -n $file -p ./Trained_Classifiers/
done > joblist_WMH
qbatch -w 2:00:00 -c 20 -N WMH_seg joblist_WMH
To remove the RF_ prefix from files generated (remove echo to actually do it):
cd WMH_mask_native
for x in *; do
echo mv $x `echo $x | cut -c 4-`
done
cd ..
QC images for the registration to the ADNI template can me generated with the following code. It is recommended to QC the registration, as important errors will results in errors in the final WMH segmentation.
for file in ./FLAIR/*;
do
echo minc_qc.pl --clobber --big --mask ./Trained_Classifiers/Av_FLAIR.mnc --image-range 5 100 --mask-range 5 100 ./Preprocessed/$(basename $file _FLAIR.mnc)_FLAIR.NLM.N3.NORM.ADNI.RSL.mnc ./Preprocessed/$(basename $file _FLAIR.mnc).RSL.ADNI.QC.jpg
done > joblist_ADNIreg_QC
qbatch joblist_ADNIreg_QC
Images of the T2w and WMH masks are available in the WMH_mask_native folder for the QC.
WMHs are typically parcellated in periventricular (PV) and deep regions, but a recent paper by Dadar et al., 2019 added the distinction between superficial white matter (SWM) and deep WMHs. The following code can be used to parcellate WMHs and normal-appearing white matter (NAWM) into PV/deep/SWM regions. The deep and SWM regions can be combined if this added distinction is not desired.
To do this parcellation, a mask of the ventricules of the ADNI template is required, and is available on the CIC at this location: /data/chamal/projects/paroli/ressources/ADNI_template_ventricules.mnc. Copy-paste this file to your main folder.
Save this code as WMH_segment_PV_SWM_deep.sh in your main folder.
*** WARNING: This only works for 1mm isotropic data ***
# Parcelatte WMHs in periventricular (PV), superficial white matter (SWM) and deep
ID=$1
# Resample classify image from T1w to FLAIR
mincresample -clobber -nearest -like ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.mnc -invert_transform -transform ./Preprocessed/$(basename $ID)_T1.linregFLAIR.0_GenericAffine.xfm ./Preprocessed/$(basename $ID)_t1_itN3.classify.mnc ./Preprocessed/$(basename $ID)_t1_itN3.classify.linregFLAIR.RSL.mnc
# Create WM, GM, CSF masks from classify file
mincmath -clobber -eq -constant 1 ./Preprocessed/$(basename $ID)_t1_itN3.classify.linregFLAIR.RSL.mnc ./WMH_mask_native/$(basename $ID)_CSF.mnc
mincmath -clobber -eq -constant 2 ./Preprocessed/$(basename $ID)_t1_itN3.classify.linregFLAIR.RSL.mnc ./WMH_mask_native/$(basename $ID)_GM.mnc
mincmath -clobber -eq -constant 3 ./Preprocessed/$(basename $ID)_t1_itN3.classify.linregFLAIR.RSL.mnc ./WMH_mask_native/$(basename $ID)_WM.mnc
# TBV mask by adding GM and WM masks
mincmath -clobber -add ./WMH_mask_native/$(basename $ID)_GM.mnc ./WMH_mask_native/$(basename $ID)_WM.mnc ./WMH_mask_native/$(basename $ID)_GM_WM.mnc
# Dilate WMH mask by 2mm (to exclude unhealthy tissue from NAWM mask)
mincmorph -clobber -3D26 -successive DD ./WMH_mask_native/$(basename $ID)_WMH.mnc ./WMH_mask_native/$(basename $ID)_WMH_dilated2mm.mnc
# Create normal-appearing WM (NAWM) masks
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_WM.mnc ./WMH_mask_native/$(basename $ID)_WMH_dilated2mm.mnc ./WMH_mask_native/$(basename $ID)_WM_WMH_overlap.mnc
mincmath -clobber -sub ./WMH_mask_native/$(basename $ID)_WM.mnc ./WMH_mask_native/$(basename $ID)_WM_WMH_overlap.mnc ./WMH_mask_native/$(basename $ID)_NAWM.mnc
######### Periventricular WMHs
# Transform ventricule mask from ADNI to t1w space
mincresample -clobber -nearest -invert_transform -like ./Preprocessed/$(basename $ID)_FLAIR.NLM.N3.NORM.mnc -transform ./Preprocessed/$(basename $ID)_FLAIR_to_ADNI.xfm ./ADNI_template_ventricules.mnc ./WMH_mask_native/$(basename $ID)_ventricules.mnc
# Dilate ventricule mask by 8mm
mincmorph -clobber -3D26 -successive DDDDDDDD ./WMH_mask_native/$(basename $ID)_ventricules.mnc ./WMH_mask_native/$(basename $ID)_ventricules_dilated8mm.mnc
# Periventricular WMHs mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_WMH.mnc ./WMH_mask_native/$(basename $ID)_ventricules_dilated8mm.mnc ./WMH_mask_native/$(basename $ID)_WMH_PV.mnc
# Periventricular NAWM mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_NAWM.mnc ./WMH_mask_native/$(basename $ID)_ventricules_dilated8mm.mnc ./WMH_mask_native/$(basename $ID)_NAWM_PV.mnc
######## SWM WMHs
# Dilate GM mask by 1mm for SWM WMHs
mincmorph -clobber -3D26 -successive D ./WMH_mask_native/$(basename $ID)_GM.mnc ./WMH_mask_native/$(basename $ID)_GM_dilated1mm.mnc
# Overlap between WM and dilated GM mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_WM.mnc ./WMH_mask_native/$(basename $ID)_GM_dilated1mm.mnc ./WMH_mask_native/$(basename $ID)_WM_GM_dilated1mm_overlap.mnc
# Overlap between dilated GM and dilated ventricules
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_GM_dilated1mm.mnc ./WMH_mask_native/$(basename $ID)_ventricules_dilated8mm.mnc ./WMH_mask_native/$(basename $ID)_dilated_WM_dilated_ventricules_overlap.mnc
# Remove PV from dilated GM
mincmath -clobber -sub ./WMH_mask_native/$(basename $ID)_GM_dilated1mm.mnc ./WMH_mask_native/$(basename $ID)_dilated_WM_dilated_ventricules_overlap.mnc ./WMH_mask_native/$(basename $ID)_GM_dilated1mm_noPV.mnc
# SWM WMHs mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_WMH.mnc ./WMH_mask_native/$(basename $ID)_GM_dilated1mm_noPV.mnc ./WMH_mask_native/$(basename $ID)_WMH_SWM.mnc
# SWM NAWM mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_NAWM.mnc ./WMH_mask_native/$(basename $ID)_GM_dilated1mm_noPV.mnc ./WMH_mask_native/$(basename $ID)_NAWM_SWM.mnc
########## Deep WMHs
# Overlap between WM and dilated ventricule mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_WM.mnc ./WMH_mask_native/$(basename $ID)_ventricules_dilated8mm.mnc ./WMH_mask_native/$(basename $ID)_WM_ventricules_dilated8mm_overlap.mnc
# WM without periventricular WM
mincmath -clobber -sub ./WMH_mask_native/$(basename $ID)_WM.mnc ./WMH_mask_native/$(basename $ID)_WM_ventricules_dilated8mm_overlap.mnc ./WMH_mask_native/$(basename $ID)_WM_noPV.mnc
# Overlap between WM without dilated ventricules AND GM dilated without dilated ventricules
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_WM_noPV.mnc ./WMH_mask_native/$(basename $ID)_GM_dilated1mm_noPV.mnc ./WMH_mask_native/$(basename $ID)_WM_noPV_GM_dilated1mm_noPV_overlap.mnc
# WM without periventricular WM and SWM
mincmath -clobber -sub ./WMH_mask_native/$(basename $ID)_WM_noPV.mnc ./WMH_mask_native/$(basename $ID)_WM_noPV_GM_dilated1mm_noPV_overlap.mnc ./WMH_mask_native/$(basename $ID)_WM_deep.mnc
# Deep WMHs mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_WMH.mnc ./WMH_mask_native/$(basename $ID)_WM_deep.mnc ./WMH_mask_native/$(basename $ID)_WMH_deep.mnc
# Deep NAWM mask
mincmath -clobber -and ./WMH_mask_native/$(basename $ID)_NAWM.mnc ./WMH_mask_native/$(basename $ID)_WM_deep.mnc ./WMH_mask_native/$(basename $ID)_NAWM_deep.mnc
# WMH mask where 1=PV, 2=Deep, 3=SWM
mincmath -clobber -add ./WMH_mask_native/$(basename $ID)_WMH.mnc ./WMH_mask_native/$(basename $ID)_WMH_SWM.mnc ./WMH_mask_native/$(basename $ID)_WMH_SWM.mnc ./WMH_mask_native/$(basename $ID)_WMH_plus_SWM.mnc
mincmath -clobber -add ./WMH_mask_native/$(basename $ID)_WMH_plus_SWM.mnc ./WMH_mask_native/$(basename $ID)_WMH_deep.mnc ./WMH_mask_native/$(basename $ID)_WMH_PV_deep_SWM.mnc
# NAWM mask where 1=PV, 2=Deep, 3=SWM
mincmath -clobber -add ./WMH_mask_native/$(basename $ID)_NAWM.mnc ./WMH_mask_native/$(basename $ID)_NAWM_SWM.mnc ./WMH_mask_native/$(basename $ID)_NAWM_SWM.mnc ./WMH_mask_native/$(basename $ID)_NAWM_plus_SWM.mnc
mincmath -clobber -add ./WMH_mask_native/$(basename $ID)_NAWM_plus_SWM.mnc ./WMH_mask_native/$(basename $ID)_NAWM_deep.mnc ./WMH_mask_native/$(basename $ID)_NAWM_PV_deep_SWM.mnc
# QC figure with mask divided by region
minc_qc.pl -mask ./WMH_mask_native/$(basename $ID)_WMH_PV_deep_SWM.mnc ./Preprocessed/$(basename $ID)_t1_itN3.NLM.NORM.linregFLAIR.mnc ./WMH_mask_native/$(basename $ID)_WMH_PV_deep_SWM.jpg --big --clobber --image-range 0 250 --spectral-mask --mask-range 0 3
minc_qc.pl -mask ./WMH_mask_native/$(basename $ID)_NAWM_PV_deep_SWM.mnc ./Preprocessed/$(basename $ID)_t1_itN3.NLM.NORM.linregFLAIR.mnc ./WMH_mask_native/$(basename $ID)_NAWM_PV_deep_SWM.jpg --big --clobber --image-range 0 250 --spectral-mask --mask-range 0 3
Then, to parcellate the WMHs and NAWM for each subject:
for file in ./T1/*;
do
echo ./WMH_segment_PV_SWM_deep.sh $(basename $file _t1.mnc)
done > joblist_segment_PV_SWM_deep
qbatch -w 1:00:00 -N WMH_segment joblist_segment_PV_SWM_deep
The final and important masks in the WMH_mask_native folder are the following
- ID_GM_WM.mnc: for TBV calculation (GM and WM, but no CSF)
- ID_NAWM.mnc: global NAWM mask, excluding WMHs and 2mm around WMHs
- ID_WMH.mnc: global WMH mask
- ID_WMH_{PV,deep,WMH}.mnc and ID_NAWM_{PV,deep,WMH}.mnc: parcellated WMH and NAWM masks
Furthermore, the parcellation of WMHs can be visualized with the ./WMH_mask_native/ID_WMH_PV_deep_SWM.jpg figure
From the masks, it is then possible to calculate the total volume of every region, as well as signal measures inside the masks (mean, median, variance, max, min), which can be useful. First, extract these measures from the masks and save as txt (this is not done with qbatch, so might take a while if there is a lot of subjects)
masks=("NAWM" "NAWM_deep" "NAWM_PV" "NAWM_SWM" "WMH" "WMH_deep" "WMH_PV" "WMH_SWM")
for file in ./Preprocessed/*_FLAIR.NLM.N3.NORM.mnc;
do
for i in ${!masks[@]};
do
volume_stats -mask ./WMH_mask_native/$(basename $file _FLAIR.NLM.N3.NORM.mnc)_${masks[i]}.mnc -all $file > ./WMH_mask_native/$(basename $file _FLAIR.NLM.N3.NORM.mnc)_mask_${masks[i]}_FLAIR_stats.txt
done
done
Secondly, save results in a csv that includes all participants
masks=("WMH" "NAWM" "NAWM_deep" "NAWM_PV" "NAWM_SWM" "WMH" "WMH_deep" "WMH_PV" "WMH_SWM")
for i in ${!masks[@]};
do
echo "ID,${masks[i]} volume,${masks[i]} FLAIR_min,${masks[i]} FLAIR_max,${masks[i]} FLAIR_mean,${masks[i]} FLAIR_stddev,${masks[i]} FLAIR_median" > ./results_csv/FLAIR_${masks[i]}.csv
for file in ./WMH_mask_native/*_mask_${masks[i]}_FLAIR_stats.txt;
do
ID=$(basename $file _mask_${masks[i]}_FLAIR_stats.txt)
volume=$(sed '5q;d' $file | tr " " "\n" | tail -n 1)
min=$(sed '6q;d' $file | tr " " "\n" | tail -n 1)
max=$(sed '7q;d' $file | tr " " "\n" | tail -n 1)
mean=$(sed '10q;d' $file | tr " " "\n" | tail -n 1)
stddev=$(sed '12q;d' $file | tr " " "\n" | tail -n 1)
median=$(sed '13q;d' $file | tr " " "\n" | tail -n 1)
echo "$ID,$volume,$min,$max,$mean,$stddev,$median" >> ./results_csv/FLAIR_${masks[i]}.csv
done
done
This can also be done for the preprocessed T1w and T2w if signal measures inside those images are of interest. Since these volumes are in the same space as the FLAIR volumes, there is no need to transform the masks. For signal measures on other scans, linear registration has to be done first.