Skip to content

Commit

Permalink
Add -first_dir option to multiple Python commands
Browse files Browse the repository at this point in the history
Original commit message:
"Added option to provide FSL FIRST data to three scripts which would otherwise run that step repeatedly.
Also takes away the FSL dependency in labelsgmfix for Windows users."
Manual cherry-pick of dc6d87b by: Robert E. Smith <robert.smith@florey.edu.au>
  • Loading branch information
NicDC authored and Lestropie committed Nov 24, 2024
1 parent 0a5daee commit 99af403
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 24 deletions.
45 changes: 37 additions & 8 deletions python/mrtrix3/commands/5ttgen/fsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ def usage(base_parser, subparsers): #pylint: disable=unused-variable
action='store_true',
default=None,
help='Indicate that brain masking has already been applied to the input image')
options.add_argument('-first_dir',
metavar='/path/to/first/dir',
help='use pre-calculated output of FSL FIRST previously run on input T1-weighted image; '
'data must be defined in the same space as input T1w')
options.add_argument('-fast_dir',
metavar='/path/to/fast/dir',
help='use pre-calculated output of FSL FAST previously run on input T1-weighted image; '
'data must be defined in the same space as input T1w')
parser.flag_mutually_exclusive_options( [ 'mask', 'premasked' ] )


Expand Down Expand Up @@ -190,10 +198,22 @@ def execute(): #pylint: disable=unused-variable
# Finish branching based on brain masking

# FAST
if fast_t2_input:
run.command(f'{fast_cmd} -S 2 {fast_t2_input} {fast_t1_input}')
else:
run.command(f'{fast_cmd} {fast_t1_input}')
if not app.args.fast_dir:
if fast_t2_input:
run.command(f'{fast_cmd} -S 2 {fast_t2_input} {fast_t1_input}')
else:
run.command(f'{fast_cmd} {fast_t1_input}')
if app.args.fast_dir:
if not os.path.isdir(os.path.abspath(app.args.fast_dir)):
app.error('FAST directory cannot be found, please check path')
else:
fast_output_prefix = fast_t1_input.split('.')[0]
fast_csf_input = fsl.find_image(app.args.fast_dir + '/' + fast_output_prefix + '_pve_0.nii.gz')
fast_gm_input = fsl.find_image(app.args.fast_dir + '/' + fast_output_prefix + '_pve_1.nii.gz')
fast_wm_input = fsl.find_image(app.args.fast_dir + '/' + fast_output_prefix + '_pve_2.nii.gz')
run.command('cp ' + fast_csf_input + ' .' )
run.command('cp ' + fast_gm_input + ' .' )
run.command('cp ' + fast_wm_input + ' .' )

# FIRST
first_input = 'T1.nii'
Expand All @@ -205,10 +225,19 @@ def execute(): #pylint: disable=unused-variable
first_brain_extracted_option = ['-b'] if app.ARGS.premasked else []
first_debug_option = [] if app.DO_CLEANUP else ['-d']
first_verbosity_option = ['-v'] if app.VERBOSITY == 3 else []
run.command([first_cmd, '-m', 'none', '-s', ','.join(sgm_structures), '-i', first_input, '-o', 'first']
+ first_brain_extracted_option
+ first_debug_option
+ first_verbosity_option)
if not app.args.first_dir:
run.command([first_cmd, '-m', 'none', '-s', ','.join(sgm_structures), '-i', first_input, '-o', 'first']
+ first_brain_extracted_option
+ first_debug_option
+ first_verbosity_option)
elif app.args.first_dir:
if not os.path.isdir(os.path.abspath(app.args.first_dir)):
app.error('FIRST directory cannot be found, please check path')
else:
for struct in sgm_structures:
vtk_in_path = 'first-' + struct + '_first.vtk'
run.command('cp ' + app.args.first_dir + '/' + vtk_in_path + ' .')
run.command('cp -r ' + app.args.first_dir + '/first.logs' + ' .')
fsl.check_first('first', sgm_structures)

# Convert FIRST meshes to partial volume images
Expand Down
17 changes: 15 additions & 2 deletions python/mrtrix3/commands/5ttgen/hsvs.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ def usage(base_parser, subparsers): #pylint: disable=unused-variable
action='store_true',
default=None,
help='Classify the brainstem as white matter')
parser.add_argument('-first_dir',
metavar='/path/to/first/dir',
help='utilise pre-calculated output of FSL FIRST run on input T1-weighted image; '
'must have been computed in the same space as FreeSurfer T1w')
parser.add_citation('Smith, R.; Skoch, A.; Bajada, C.; Caspers, S.; Connelly, A. '
'Hybrid Surface-Volume Segmentation for improved Anatomically-Constrained Tractography. '
'In Proc OHBM 2020')
Expand Down Expand Up @@ -102,6 +106,7 @@ def usage(base_parser, subparsers): #pylint: disable=unused-variable
(57, 5, 'Right-Lesion'),
(62, 4, 'Right-vessel'),
(72, 4, '5th-Ventricle'),
(77, 5, 'WM-Hypointensities'),
(250, 3, 'Fornix') ]


Expand Down Expand Up @@ -189,7 +194,6 @@ def execute(): #pylint: disable=unused-variable
mri_dir = os.path.join(app.ARGS.input, 'mri')
check_dir(surf_dir)
check_dir(mri_dir)
#aparc_image = os.path.join(mri_dir, 'aparc+aseg.mgz')
aparc_image = 'aparc.mif'
mask_image = os.path.join(mri_dir, 'brainmask.mgz')
reg_file = os.path.join(mri_dir, 'transforms', 'talairach.xfm')
Expand Down Expand Up @@ -557,7 +561,16 @@ def execute(): #pylint: disable=unused-variable
from_first = { key: value for key, value in from_first.items() if 'Hippocampus' not in value and 'Amygdala' not in value }
if thalami_method != 'first':
from_first = { key: value for key, value in from_first.items() if 'Thalamus' not in value }
run.command([first_cmd, '-s', ','.join(from_first.keys()), '-i', 'T1.nii', '-b', '-o', 'first'])
if not app.ARGS.first_dir:
run.command([first_cmd, '-s', ','.join(from_first.keys()), '-i', 'T1.nii', '-b', '-o', 'first'])
elif app.ARGS.first_dir:
if not os.path.isdir(os.path.abspath(app.ARGS.first_dir)):
app.error('FIRST directory cannot be found, please check path')
else:
for key, value in from_first.items():
vtk_in_path = 'first-' + key + '_first.vtk'
run.command('cp ' + app.ARGS.first_dir + '/' + vtk_in_path + ' .')
run.command('cp -r ' + app.ARGS.first_dir + '/first.logs' + ' .')
fsl.check_first('first', from_first.keys())
app.cleanup(glob.glob('T1_to_std_sub.*'))
progress = app.ProgressBar('Mapping FIRST segmentations to image', 2*len(from_first))
Expand Down
42 changes: 28 additions & 14 deletions python/mrtrix3/commands/labelsgmfirst.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ def usage(cmdline): #pylint: disable=unused-variable
default=None,
help='Consider the amygdalae and hippocampi as sub-cortical grey matter structures,'
' and also replace their estimates with those from FIRST')
cmdline.add_argument('-first_dir',
metavar='/path/to/first/dir',
help='use pre-calculated output of FSL FIRST previously run on T1-weighted image; '
'must be defined in the same space as input FreeSurfer parcellation')



Expand All @@ -63,23 +67,24 @@ def usage(cmdline): #pylint: disable=unused-variable
def execute(): #pylint: disable=unused-variable
from mrtrix3 import MRtrixError #pylint: disable=no-name-in-module, import-outside-toplevel
from mrtrix3 import app, fsl, image, path, run, utils #pylint: disable=no-name-in-module, import-outside-toplevel

if utils.is_windows():
raise MRtrixError('Script cannot run on Windows due to FSL dependency')
if not app.ARGS.first_dir:
if utils.is_windows():
raise MRtrixError('Script cannot run on Windows due to FSL dependency')

image.check_3d_nonunity(app.ARGS.t1)

fsl_path = os.environ.get('FSLDIR', '')
if not fsl_path:
raise MRtrixError('Environment variable FSLDIR is not set; '
'please run appropriate FSL configuration script')
if not app.ARGS.first_dir:
fsl_path = os.environ.get('FSLDIR', '')
if not fsl_path:
raise MRtrixError('Environment variable FSLDIR is not set; '
'please run appropriate FSL configuration script')

first_cmd = fsl.exe_name('run_first_all')
first_cmd = fsl.exe_name('run_first_all')

first_atlas_path = os.path.join(fsl_path, 'data', 'first', 'models_336_bin')
if not os.path.isdir(first_atlas_path):
raise MRtrixError('Atlases required for FSL\'s FIRST program not installed; '
'please install fsl-first-data using your relevant package manager')
first_atlas_path = os.path.join(fsl_path, 'data', 'first', 'models_336_bin')
if not os.path.isdir(first_atlas_path):
raise MRtrixError('Atlases required for FSL\'s FIRST program not installed; '
'please install fsl-first-data using your relevant package manager')

# Want a mapping between FreeSurfer node names and FIRST structure names
# Just deal with the 5 that are used in ACT; FreeSurfer's hippocampus / amygdala segmentations look good enough.
Expand Down Expand Up @@ -118,8 +123,17 @@ def execute(): #pylint: disable=unused-variable
first_input_is_brain_extracted = ''
if app.ARGS.premasked:
first_input_is_brain_extracted = ' -b'
structures_string = ','.join(structure_map.keys())
run.command(f'{first_cmd} -m none -s {structures_string} -i T1.nii {first_input_is_brain_extracted} -o first')
if not app.ARGS.first_dir:
structures_string = ','.join(structure_map.keys())
run.command(f'{first_cmd} -m none -s {structures_string} -i T1.nii {first_input_is_brain_extracted} -o first')
elif app.ARGS.first_dir:
if not os.path.isdir(os.path.abspath(app.ARGS.first_dir)):
app.error('FIRST directory cannot be found, please check path')
else:
for key, value in structure_map.items():
vtk_in_path = 'first-' + key + '_first.vtk'
run.command('cp ' + app.ARGS.first_dir + '/' + vtk_in_path + ' .')
run.command('cp -r ' + app.ARGS.first_dir + '/first.logs' + ' .')
fsl.check_first('first', structure_map.keys())

# Generate an empty image that will be used to construct the new SGM nodes
Expand Down

0 comments on commit 99af403

Please sign in to comment.