Tutorial: How to Make a Symmetric Brain

Introduction

This tutorial will teach the user how to remove asymmetry in brain data, creating a symmetric brain where the left and right hemispheres appear the same, using a combination of Python scripts and Advanced Normalization Tools (ANTs).

Why Make a Symmetric Brain?

Brain atlasing annotation is often done on a single hemisphere as it is a difficult and time consuming process.  For species that have no apparent lateralization, the annotation procedure might also introduce bias in the drawing of brain structure boundaries. For the marmoset brain, mapping data with a symmetric reference/average brain can allow us to discover any asymmetries in the individual data.

When only one hemisphere is annotated, the annotation is usually mirrored into the other hemisphere, thus making the atlas symmetric. The symmetric property can also be useful to simplify computations when processing data and comparing hemispheres.

When making a reference or average brain, we can convert  asymmetric data into symmetric data, making it easier to map it with new data and to make sure all brain structures are represented equally.

 

ANTs and Python Installation

This tutorial uses ANTs v.2.3.5 [Ecphorella] (all ANTs releases can be found on the official github page).

Please follow the guide to compile and install ANTs for Linux/MacOS or Windows.

We used Python Version 3.7.1.1 in this tutorial. Compatible versions of SimpleITK and NumPy packages for Python must be installed as well. We recommend to set up an isolated Python virtual environment for the tutorial, as described in this Visual Studio Code documentation (terminal command instructions can be used even if you’re not using VS Code as your Python IDE).

Download Sample Data

In this tutorial we will use the data sets from the data portal atlas download page.

We will use BMA 2019 Ex Vivo v1.0.0.

Step 1:Flip the Original Brain Across the Sagittal Plane

We will use sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz under base_data folder from BMA2019, this is the average T2WI MRI brain with N=25.

To flip the brain, please run the following Python code:

				
					import SimpleITK as sitk
import numpy as np

img = sitk.ReadImage('sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz')
imgNda = sitk.GetArrayFromImage(img)

imgNda = np.flip(imgNda, 2)

out = sitk.GetImageFromArray(imgNda)
out.CopyInformation(img)

sitk.WriteImage(out, 'sp2_avg_mri_exvivo_t2wi_v1.0.0_flip.nii.gz')

				
			

You can view Nifti files before and after the flip using tools such as ITK-SNAP or 3D Slicer as shown below:

Original Average T2WI MRI Brain (Axial View)

Difference Between 2 Brains (Axial View)

Flipped Average T2WI MRI Brain (Axial View)

Original Average T2WI MRI Brain (Coronal View)

Difference Between 2 Brains (Coronal View)

Flipped Average T2WI MRI Brain (Coronal View)

Step 2: Register Flipped Brain to Original Brain

Run the following command using ANTs to register the flipped brain to the original brain:

antsRegistrationSyN.sh -d 3 -f sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz -m sp2_avg_mri_exvivo_t2wi_v1.0.0_flip.nii.gz -o avg_mri_reg_ -n 8

Lets go over each arguments in the above command:

-d 3: This is the dimension, since we are working with 3D volumes, the dimension is 3.

-f sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz: This is the fixed image or the image we want to register to, in our case, this will be original average T2WI MRI brain.

-m sp2_avg_mri_exvivo_t2wi_v1.0.0_flip.nii.gz: This is the moving image or the image we want to register, in our case, this will be the flipped average T2WI MRI brain from Step 1.

-o avg_mri_reg_: This is the output prefix, in this example, the output files will all have the prefix ”avg_mri_reg_”

-n 8: This is the number of threads to use during registration to speed things up. Here, we use 8 threads.

The above step should output the following 5 files:

avg_mri_reg_0GenericAffine.mat: This is the output for affine transform.

avg_mri_reg_1InverseWarp.nii.gz: This is the output for inverse displacement field.

avg_mri_reg_1Warp.nii.gz: This is the output for displacement field.

avg_mri_reg_InverseWarped.nii.gz: This is the result of original brain registered to flipped brain.

avg_mri_reg_Warped.nii.gz: This is the result of flipped brain registered to the original brain.

Step 3: Combine Affine and Displacement Fields

Run the following commands using ANTs to combine transformation files from Step 2 to be used in the next step:

To combine transforms of flipped brain to original brain:

ComposeMultiTransform 3 outcompose_fwd.nii.gz -R sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz avg_mri_reg_0GenericAffine.mat avg_mri_reg_1Warp.nii.gz

Lets go over each arguments in the above command:

3: The 1st argument is the dimension, since we are working with 3D volumes, the dimension is 3.

outcompose_fwd.nii.gz: The 2nd argument is the output file name, here, we name it “outcompose_fwd.nii.gz”

-R sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz: The 3rd argument is the reference image  we used for registration, in this case, it is the original average T2WI MRI brain.

avg_mri_reg_0GenericAffine.mat avg_mri_reg_1Warp.nii.gz: The 4th and 5th are the transformations we want to combine. Here the order is very important, as transformations are applied from right to left. Here, we apply the displacement field first then the affine transforms to go from flipped brain to original brain.

To combine transforms of original brain to flippedl brain:

ComposeMultiTransform 3 outcompose_bck.nii.gz -R sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz avg_mri_reg_1InverseWarp.nii.gz -i avg_mri_reg_0GenericAffine.mat

Lets go over each arguments in the above command:

3: The 1st argument is the dimension, since we are working with 3D volumes, the dimension is 3.

outcompose_bck.nii.gz: The 2nd argument is the output file name, here, we name it “outcompose_bck.nii.gz”

-R sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz: The 3rd argument is the reference image  we used for registration, in this case, it is the original average T2WI MRI brain.

avg_mri_reg_1InverseWarp.nii.gz -i avg_mri_reg_0GenericAffine.mat: The 4th and 5th are the transformations we want to combine. Here we first apply the inverse affine transforms (-i here invert the affine transforms) then the inverse displacement field to go from original brain to flipped brain.

Step 4: Calculate Half-way Transforms in Both Directions

In this step, we want to generate half way transforms in both directions so that we can transform both the original brain and the flipped brain into a “half way” space.

				
					import SimpleITK as sitk

transformIn = sitk.ReadImage("outcompose_fwd.nii.gz")
c = sitk.GetArrayFromImage(transformIn)
c = c * 0.5
out = sitk.GetImageFromArray(c)
out.CopyInformation(transformIn)

sitk.WriteImage(out,"outcompose_half_fwd.nii.gz")

transformIn = sitk.ReadImage("outcompose_bck.nii.gz")
c = sitk.GetArrayFromImage(transformIn)
c = c * 0.5
out = sitk.GetImageFromArray(c)
out.CopyInformation(transformIn)

sitk.WriteImage(out,"outcompose_half_bck.nii.gz")
				
			

Step 5: Apply Half Way Transforms

To apply half way transforms from Step 4, please run the following commands using ANTs:

First we apply half way transform to the flipped brain:

antsApplyTransforms -d 3 -r sp2_avg_mri_exvivo_t2wi_v1.0.0_flip.nii.gz -i sp2_avg_mri_exvivo_t2wi_v1.0.0_flip.nii.gz -t outcompose_half_fwd.nii.gz -o avg_mri_warp_fwd.nii.gz

Lets go over each arguments in the above command:

-d 3: This is the dimension, since we are working with 3D volumes, the dimension is 3.

-r sp2_avg_mri_exvivo_t2wi_v1.0.0_flip.nii.gz: This is the reference image, which is the flipped brain.

-i sp2_avg_mri_exvivo_t2wi_v1.0.0_flip.nii.gz: This is input image, which is also the flipped brain.

t outcompose_half_fwd.nii.gz: We apply the half way transform from flipped brain to original brain that was calculated in Step 4.

-o avg_mri_warp_fwd.nii.gz: This is the output file, we name it “avg_mri_warp_fwd.nii.gz”.

Next we apply half way transform to the original brain:

antsApplyTransforms -d 3 -r sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz -i sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz -t outcompose_half_bck.nii.gz -o avg_mri_warp_bck.nii.gz

Lets go over each arguments in the above command:

-d 3: This is the dimension, since we are working with 3D volumes, the dimension is 3.

-r sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz: This is the reference image, which is the original brain.

-i sp2_avg_mri_exvivo_t2wi_v1.0.0.nii.gz: This is input image, which is also the original brain.

t outcompose_half_bck.nii.gz: We apply the half way transform from original brain to flipped brain that was calculated in Step 4.

-o avg_mri_warp_bck.nii.gz: This is the output file, we name it “avg_mri_warp_bck.nii.gz”.

After this step, you can see below that both brain will be in a symmetric space.

Flipped Brain After Half Way Transform

Original Brain After Half Way Transform

Step 6: Generate the Symmetric Brain

Finally, we want to average the two “half way” transformed brain to generate the symmetric brain:

AverageImages 3 avg_mri_symmetric.nii.gz 1 avg_mri_warp_fwd.nii.gz avg_mri_warp_bck.nii.gz

Lets go over each arguments in the above command:

3: This is the dimension, since we are working with 3D volumes, the dimension is 3.

avg_mri_symmetric.nii.gz: This is the output file, we name it “avg_mri_symmetric.nii.gz”.

1: This is the flag to normalize input images.

avg_mri_warp_fwd.nii.gz avg_mri_warp_bck.nii.gz: Those are the half way transformed brains we calculated in Step 5.

Symmetric Average T2WI MRI Brain

By following this guide, you have learnt how to make an asymmetric brain into an symmetric brain, this is useful when making a reference that represent brain structures in both hemisphere equally.

Last updated 12-05-2022