Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5ttgen: Add Deep Atropos algorithm #3057

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
115 changes: 114 additions & 1 deletion docs/reference/commands/5ttgen.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Usage

5ttgen algorithm [ options ] ...

- *algorithm*: Select the algorithm to be used; additional details and options become available once an algorithm is nominated. Options are: freesurfer, fsl, gif, hsvs
- *algorithm*: Select the algorithm to be used; additional details and options become available once an algorithm is nominated. Options are: deep_atropos, freesurfer, fsl, gif, hsvs

Description
-----------
Expand Down Expand Up @@ -90,6 +90,119 @@ See the Mozilla Public License v. 2.0 for more details.

For more details, see http://www.mrtrix.org/.

.. _5ttgen_deep_atropos:

5ttgen deep_atropos
===================

Synopsis
--------

Generate the 5TT image based on a Deep Atropos segmentation or probabilities image

Usage
-----

::

5ttgen deep_atropos input output [ options ]

- *input*: The input Deep Atropos segmentation image
- *output*: The output 5TT image

Description
-----------

This algorithm can accept the outputs of Deep Atropos in one of two forms. The "segmentation image" is a 3D image, of integer datatype, with indices mapping to discrete tissue classes as follows: 0: Background; 1: CSF; 2: Gray Matter; 3: White Matter; 4: Deep Gray Matter; 5: Brain Stem; 6: Cerebellum. The "probabilities images" are a set of seven 3D volumes, each corresponding to the posterior probability of one of the seven tissue classes above. These can be provided as input to this command by concatenating into a 4D image series with 7 volumes (the order of which must match that above).

The example usages provided in this help page, which include execution of Deep Atropos itself within a Python environment, require that "ants" and "antspynet" be installed via Python's "pip"; use of the "probability images" also requires that nibabel and numpy be installed.

Example usages
--------------

- *To utilise the "segmentation" image*::

$ python3 -c "import ants, antspynet; t1w = ants.image_read('T1w.nii.gz'); result = antspynet.deep_atropos(t1w); ants.image_write(result['segmentation_image'], 'segmentation.nii.gz')"; 5ttgen deep_atropos segmentation.nii.gz 5tt_segmentation.mif

Because the input segmentation here is an integer image, where each voxel just contains an index corresponding to the maximal tissue class, the output 5TT image will not possess any fractional partial volumes; it will just contain the value 1.0 in whichever 5TT volume corresponds to the singular assigned tissue class.

- *To utilise the "probability images"*::

$ python3 -c "import ants, antspynet, nibabel, numpy; inpath = 'T1w.nii.gz'; t1w_ants = ants.image_read(inpath); t1w_nib = nibabel.load(inpath); result = antspynet.deep_atropos(t1w_ants); prob_maps = numpy.stack([numpy.array(img.numpy()) for img in result['probability_images']], axis=-1); nibabel.save(nibabel.Nifti1Image(prob_maps, t1w_nib.affine), 'probabilities.nii.gz')"; 5ttgen deep_atropos probabilities.nii.gz 5tt_probabilities.mif

In this use case, the posterior probabilities of these tissue classes are interpreted as partial volume fractions and imported into the derivative 5TT image appropriately.

Options
-------

- **-white_stem** Classify the brainstem as white matter

Options common to all 5ttgen algorithms
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- **-nocrop** Do NOT crop the resulting 5TT image to reduce its size (keep the same dimensions as the input image)

- **-sgm_amyg_hipp** Represent the amygdalae and hippocampi as sub-cortical grey matter in the 5TT image

Additional standard options for Python scripts
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- **-nocleanup** do not delete intermediate files during script execution, and do not delete scratch directory at script completion.

- **-scratch /path/to/scratch/** manually specify an existing directory in which to generate the scratch directory.

- **-continue ScratchDir LastFile** continue the script from a previous execution; must provide the scratch directory path, and the name of the last successfully-generated file.

Standard options
^^^^^^^^^^^^^^^^

- **-info** display information messages.

- **-quiet** do not display information messages or progress status. Alternatively, this can be achieved by setting the MRTRIX_QUIET environment variable to a non-empty string.

- **-debug** display debugging messages.

- **-force** force overwrite of output files.

- **-nthreads number** use this number of threads in multi-threaded applications (set to 0 to disable multi-threading).

- **-config key value** *(multiple uses permitted)* temporarily set the value of an MRtrix config file entry.

- **-help** display this information page and exit.

- **-version** display version information and exit.

References
^^^^^^^^^^

* Smith, R. E.; Tournier, J.-D.; Calamante, F. & Connelly, A. Anatomically-constrained tractography: Improved diffusion MRI streamlines tractography through effective use of anatomical information. NeuroImage, 2012, 62, 1924-1938

* Use of the ANTsX ecosystem should be accompanied by the following citation:
N.J. Tustison, P.A. Cook, A.J. Holbrook, H.J. Johnson, J. Muschelli, G.A. Devenyi, J.T. Duda, S.R. Das, N.C. Cullen, D.L. Gillen, M.A. Yassa, J.R. Stone, J.C. Gee, and B.B. Avants. The ANTsX ecosystem for quantitative biological and medical imaging. Scientific Reports, 11(1):9068 (2021), pp. 1-13.

Tournier, J.-D.; Smith, R. E.; Raffelt, D.; Tabbara, R.; Dhollander, T.; Pietsch, M.; Christiaens, D.; Jeurissen, B.; Yeh, C.-H. & Connelly, A. MRtrix3: A fast, flexible and open software framework for medical image processing and visualisation. NeuroImage, 2019, 202, 116137

--------------



**Author:** Lucius S. Fekonja (lucius.fekonja[at]charite.de) and Robert E. Smith (robert.smith@florey.edu.au)

**Copyright:** Copyright (c) 2008-2024 the MRtrix3 contributors.

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.

Covered Software is provided under this License on an "as is"
basis, without warranty of any kind, either expressed, implied, or
statutory, including, without limitation, warranties that the
Covered Software is free of defects, merchantable, fit for a
particular purpose or non-infringing.
See the Mozilla Public License v. 2.0 for more details.

For more details, see http://www.mrtrix.org/.

.. _5ttgen_freesurfer:

5ttgen freesurfer
Expand Down
2 changes: 1 addition & 1 deletion python/mrtrix3/commands/5ttgen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
# For more details, see http://www.mrtrix.org/.

# pylint: disable=unused-variable
ALGORITHMS = ['freesurfer', 'fsl', 'gif', 'hsvs']
ALGORITHMS = ['deep_atropos', 'freesurfer', 'fsl', 'gif', 'hsvs']
131 changes: 131 additions & 0 deletions python/mrtrix3/commands/5ttgen/deep_atropos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Copyright (c) 2008-2024 the MRtrix3 contributors.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Covered Software is provided under this License on an "as is"
# basis, without warranty of any kind, either expressed, implied, or
# statutory, including, without limitation, warranties that the
# Covered Software is free of defects, merchantable, fit for a
# particular purpose or non-infringing.
# See the Mozilla Public License v. 2.0 for more details.
#
# For more details, see http://www.mrtrix.org/.

import os
from mrtrix3 import MRtrixError
from mrtrix3 import app, image, run

def usage(base_parser, subparsers): #pylint: disable=unused-variable
parser = subparsers.add_parser('deep_atropos', parents=[base_parser])
parser.set_author('Lucius S. Fekonja (lucius.fekonja[at]charite.de) and Robert E. Smith (robert.smith@florey.edu.au)')
parser.set_synopsis('Generate the 5TT image based on a Deep Atropos segmentation or probabilities image')
parser.add_citation('Use of the ANTsX ecosystem should be accompanied by the following citation:\n'
'N.J. Tustison, P.A. Cook, A.J. Holbrook, H.J. Johnson, J. Muschelli, G.A. Devenyi, J.T. Duda, S.R. Das, '
'N.C. Cullen, D.L. Gillen, M.A. Yassa, J.R. Stone, J.C. Gee, and B.B. Avants. '
'The ANTsX ecosystem for quantitative biological and medical imaging. '
'Scientific Reports, 11(1):9068 (2021), pp. 1-13.',
is_external=True)
parser.add_description('This algorithm can accept the outputs of Deep Atropos in one of two forms. '
'The "segmentation image" is a 3D image, of integer datatype, '
'with indices mapping to discrete tissue classes as follows: '
'0: Background; 1: CSF; 2: Gray Matter; 3: White Matter; 4: Deep Gray Matter; 5: Brain Stem; 6: Cerebellum. '
'The "probabilities images" are a set of seven 3D volumes, '
'each corresponding to the posterior probability of one of the seven tissue classes above. '
'These can be provided as input to this command by concatenating into a 4D image series with 7 volumes '
'(the order of which must match that above).')
parser.add_description('The example usages provided in this help page, '
'which include execution of Deep Atropos itself within a Python environment, '
'require that "ants" and "antspynet" be installed via Python\'s "pip"; '
'use of the "probability images" also requires that nibabel and numpy be installed.')
parser.add_example_usage('To utilise the "segmentation" image',
'python3 -c "import ants, antspynet; '
't1w = ants.image_read(\'T1w.nii.gz\'); '
'result = antspynet.deep_atropos(t1w); '
'ants.image_write(result[\'segmentation_image\'], \'segmentation.nii.gz\')"; '
'5ttgen deep_atropos segmentation.nii.gz 5tt_segmentation.mif',
'Because the input segmentation here is an integer image, '
'where each voxel just contains an index corresponding to the maximal tissue class, '
'the output 5TT image will not possess any fractional partial volumes; '
'it will just contain the value 1.0 in whichever 5TT volume corresponds to the singular assigned tissue class.')
parser.add_example_usage('To utilise the "probability images"',
'python3 -c "import ants, antspynet, nibabel, numpy; '
'inpath = \'T1w.nii.gz\'; '
't1w_ants = ants.image_read(inpath); '
't1w_nib = nibabel.load(inpath); '
'result = antspynet.deep_atropos(t1w_ants); '
'prob_maps = numpy.stack([numpy.array(img.numpy()) for img in result[\'probability_images\']], axis=-1); '
'nibabel.save(nibabel.Nifti1Image(prob_maps, t1w_nib.affine), \'probabilities.nii.gz\')"; '
'5ttgen deep_atropos probabilities.nii.gz 5tt_probabilities.mif',
'In this use case, the posterior probabilities of these tissue classes are interpreted as partial volume fractions '
'and imported into the derivative 5TT image appropriately.')
parser.add_argument('input',
type=app.Parser.ImageIn(),
help='The input Deep Atropos segmentation image')
parser.add_argument('output',
type=app.Parser.ImageOut(),
help='The output 5TT image')
parser.add_argument('-white_stem',
action='store_true',
default=None,
help='Classify the brainstem as white matter')

def execute(): #pylint: disable=unused-variable
if app.ARGS.sgm_amyg_hipp:
app.warn('Option -sgm_amyg_hipp has no effect on deep_atropos algorithm')

dim = image.Header(app.ARGS.input).size()
if not(len(dim) == 3 or (len(dim) == 4 and dim[3] == 7)):
raise MRtrixError(f'Image \'{str(app.ARGS.input)}\' does not look like Deep Atropos segmentation'
f' (expected either a 3D image, or a 4D image with 7 volumes; input image is {dim})')

run.command(['mrconvert', app.ARGS.input, 'input.mif'])

if len(dim) == 3:
# Generate tissue-specific masks
run.command('mrcalc input.mif 2 -eq cGM.mif')
run.command('mrcalc input.mif 4 -eq input.mif 6 -eq -add sGM.mif')
run.command(f'mrcalc input.mif 3 -eq{" input.mif 5 -eq -add" if app.ARGS.white_stem else ""} WM.mif')
run.command('mrcalc input.mif 1 -eq CSF.mif')
run.command(f'mrcalc input.mif {("0 -mult" if app.ARGS.white_stem else "5 -eq")} path.mif')
else:
# Brain mask = non-brain probability is <50%
run.command('mrconvert input.mif -coord 3 0 -axes 0,1,2 - | '
'mrthreshold - -abs 0.5 -comparison le mask.mif')
# Need to rescale model probabilities so that, excluding the non-brain component,
# the sum across all tissues will be 1.0
run.command('mrconvert input.mif -coord 3 1:end - | '
'mrmath - sum -axis 3 - | '
'mrcalc 1 - -div multiplier.mif')
# Generate tissue-specific probability maps
run.command('mrconvert input.mif -coord 3 2 -axes 0,1,2 cGM.mif')
run.command('mrconvert input.mif -coord 3 4,6 - | '
'mrmath - sum -axis 3 sGM.mif')
if app.ARGS.white_stem:
run.command('mrconvert input.mif -coord 3 3,5 - | '
'mrmath - sum -axis 3 WM.mif')
else:
run.command('mrconvert input.mif -coord 3 3 -axes 0,1,2 WM.mif')
run.command('mrconvert input.mif -coord 3 1 -axes 0,1,2 CSF.mif')
if app.ARGS.white_stem:
run.command('mrcalc cGM.mif 0 -mult path.mif')
else:
run.command('mrconvert input.mif -coord 3 5 -axes 0,1,2 path.mif')

# Concatenate into the 5TT image
run.command('mrcat cGM.mif sGM.mif WM.mif CSF.mif path.mif - -axis 3 | '
f'{"mrcalc - multiplier.mif -mult mask.mif -mult - | " if len(dim) == 4 else ""}'
'mrconvert - combined_precrop.mif -strides +2,+3,+4,+1')

# Apply cropping unless disabled
if app.ARGS.nocrop:
run.function(os.rename, 'combined_precrop.mif', 'result.mif')
else:
run.command('mrmath combined_precrop.mif sum - -axis 3 | '
'mrthreshold - - -abs 0.5 | '
'mrgrid combined_precrop.mif crop result.mif -mask -')

run.command(['mrconvert', 'result.mif', app.ARGS.output],
mrconvert_keyval=app.ARGS.input,
force=app.FORCE_OVERWRITE)
8 changes: 4 additions & 4 deletions testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ include(ExternalProject)
ExternalProject_Add(BinariesTestData
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/binaries_data
GIT_REPOSITORY ${mrtrix_binaries_data_url}
GIT_TAG 2169ebc06040a0b1380017f5f2a11d6380c69922
GIT_TAG 2169ebc06040a0b1380017f5f2a11d6380c69922
GIT_PROGRESS TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
Expand All @@ -27,19 +27,19 @@ ExternalProject_Add(BinariesTestData
ExternalProject_Add(ScriptsTestData
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/scripts_data
GIT_REPOSITORY ${mrtrix_scripts_data_url}
GIT_TAG 76f47633cd0a37e901c42320f4540ecaffd51367
GIT_TAG 7f3dae1e1bbbb383d710c0db66f469b5f812a298
GIT_PROGRESS TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)

set(BINARY_DATA_DIR
set(BINARY_DATA_DIR
${CMAKE_CURRENT_BINARY_DIR}/binaries_data/src/BinariesTestData
)

set(SCRIPT_DATA_DIR
set(SCRIPT_DATA_DIR
${CMAKE_CURRENT_BINARY_DIR}/scripts_data/src/ScriptsTestData
)

Expand Down
4 changes: 4 additions & 0 deletions testing/scripts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ function(add_bash_script_test file_path)
)
endfunction()

add_bash_script_test(5ttgen/deepatropos_fromseg_default "pythonci")
add_bash_script_test(5ttgen/deepatropos_fromseg_whitestem)
add_bash_script_test(5ttgen/deepatropos_fromprob_default "pythonci")
add_bash_script_test(5ttgen/deepatropos_fromprob_whitestem)
add_bash_script_test(5ttgen/freesurfer_default "pythonci")
add_bash_script_test(5ttgen/freesurfer_nocrop)
add_bash_script_test(5ttgen/freesurfer_piping)
Expand Down
6 changes: 6 additions & 0 deletions testing/scripts/tests/5ttgen/deepatropos_fromprob_default
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
# Verify default operation of "5ttgen deep_atropos"
# where the input is the concatenation of tissue probability images
# Outcome is compared to that generated using a prior software version
5ttgen deep_atropos 5ttgen/deep_atropos/probability_images.nii.gz tmp.mif -force
testing_diff_image tmp.mif 5ttgen/deep_atropos/fromprob_default.mif.gz
7 changes: 7 additions & 0 deletions testing/scripts/tests/5ttgen/deepatropos_fromprob_whitestem
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
# Verify default operation of "5ttgen deep_atropos"
# where the input is the concatenation of tissue probability images
# and the brain stem is allocated to WM rather than 5th volume
# Outcome is compared to that generated using a prior software version
5ttgen deep_atropos 5ttgen/deep_atropos/probability_images.nii.gz tmp.mif -white_stem -force
testing_diff_image tmp.mif 5ttgen/deep_atropos/fromprob_whitestem.mif.gz
6 changes: 6 additions & 0 deletions testing/scripts/tests/5ttgen/deepatropos_fromseg_default
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
# Verify default operation of "5ttgen deep_atropos"
# where input image is the segmentation label image
# Outcome is compared to that generated using a prior software version
5ttgen deep_atropos 5ttgen/deep_atropos/segmentation_image.nii.gz tmp.mif -force
testing_diff_image tmp.mif 5ttgen/deep_atropos/fromseg_default.mif.gz
7 changes: 7 additions & 0 deletions testing/scripts/tests/5ttgen/deepatropos_fromseg_whitestem
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash
# Verify default operation of "5ttgen deep_atropos"
# where input image is the segmentation label image
# and the brain stem is allocated to WM rather than 5th volume
# Outcome is compared to that generated using a prior software version
5ttgen deep_atropos 5ttgen/deep_atropos/segmentation_image.nii.gz tmp.mif -white_stem -force
testing_diff_image tmp.mif 5ttgen/deep_atropos/fromseg_whitestem.mif.gz