Skip to content

Commit

Permalink
Merge pull request #785 from MRtrix3/tag_0.3.16
Browse files Browse the repository at this point in the history
Tag 0.3.16
  • Loading branch information
jdtournier authored Apr 24, 2017
2 parents bea092c + bfd82fe commit 5b5ef20
Show file tree
Hide file tree
Showing 1,123 changed files with 49,587 additions and 47,550 deletions.
16 changes: 9 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@
*.hdr
*.qrc
*.rste
icons.cpp
/config.*
config
build.*
/configure.log
/build.log
/test/build.log
/lib/version.cpp
/core/version.cpp
/src/project_version.h
/lib/mrtrix3/_version.py
/test/src/project_version.h
/scripts/mrtrix_bash_completion
/release/
/test/bin/
/dev/
/bin/
/tmp/
.cproject
.idea
.project
.settings
.pydevproject
Expand All @@ -44,6 +46,6 @@ icons.cpp
/assert/
testing.log
testing/build.log
testing/release/
testing/src/
testing/bin/
testing/src/project_version.h
.__tmp.log
16 changes: 7 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
sudo: false
language: cpp
os:
- linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- zlib1g-dev
- libgsl0-dev
- libqt4-opengl-dev
- g++-4.8
- python3
compiler:
- clang
env:
- python_version=2
- python_version=3
- py=python2
- py=python3
install:
- export NUMBER_OF_PROCESSORS=4
- export PATH=`pwd`/release/bin:`pwd`/scripts:${PATH}
- export EIGEN_CFLAGS=-I`pwd`/eigen
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8"; fi
- (hg clone https://bitbucket.org/eigen/eigen/; cd eigen; hg update 3.2)
- export EIGEN_CFLAGS=-I`pwd`/../eigen
- (cd ..; hg clone https://bitbucket.org/eigen/eigen/; cd eigen; hg update 3.3)
script:
- if [ ${python_version} = "3" ]; then python3 ./configure -assert && python3 ./build -nowarnings && ./run_tests; else ./configure -assert && ./build -nowarnings && ./run_tests; fi
- ./check_memalign && $py ./configure -assert && $py ./build -nowarnings && ./run_tests

after_failure:
- cat memalign.log
- cat configure.log
- cat build.log
- cat testing.log
Expand Down
57 changes: 57 additions & 0 deletions bin/5ttgen
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python

# Script that generates a five-tissue-type (5TT) segmented image: the format appropriate for ACT
#
# In this script, major stages of processing can be performed in one of two ways:
# - Using FSL tools: BET for brain extraction, FAST for tissue segmentation, FIRST for sub-cortical grey matter segmentation
# - Using segmentations from FreeSurfer
# Alternative algorithms for performing this conversion can be added by creating a new file in lib/mrtrix3/_5ttgen/ and
# defining the appropriate functions; 5ttgen will automatically make that algorithm available at the command-line


# Make the corresponding MRtrix3 Python libraries available
import inspect, os, sys
lib_folder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile(inspect.currentframe()))[0], os.pardir, 'lib')))
if not os.path.isdir(lib_folder):
sys.stderr.write('Unable to locate MRtrix3 Python libraries')
sys.exit(1)
sys.path.insert(0, lib_folder)


from mrtrix3 import algorithm, app, path, run

app.init('Robert E. Smith (robert.smith@florey.edu.au)', 'Generate a 5TT image suitable for ACT')
app.cmdline.addCitation('', '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', False)
app.cmdline.addDescription('5ttgen acts as a \'master\' script for generating a five-tissue-type (5TT) segmented tissue image suitable for use in Anatomically-Constrained Tractography (ACT). A range of different algorithms are available for completing this task. When using this script, the name of the algorithm to be used must appear as the first argument on the command-line after \'5ttgen\'. The subsequent compulsory arguments and options available depend on the particular algorithm being invoked.')
app.cmdline.addDescription('Each algorithm available also has its own help page, including necessary references; e.g. to see the help page of the \'fsl\' algorithm, type \'5ttgen fsl\'.')

common_options = app.cmdline.add_argument_group('Options common to all 5ttgen algorithms')
common_options.add_argument('-nocrop', action='store_true', default=False, help='Do NOT crop the resulting 5TT image to reduce its size (keep the same dimensions as the input image)')
common_options.add_argument('-sgm_amyg_hipp', action='store_true', default=False, help='Represent the amygdalae and hippocampi as sub-cortical grey matter in the 5TT image')

# Import the command-line settings for all algorithms found in the relevant directory
algorithm.initialise()

app.parse()

# Find out which algorithm the user has requested
alg = algorithm.getModule(app.args.algorithm)

app.checkOutputPath(app.args.output)
alg.checkOutputPaths()

app.makeTempDir()
run.command('mrconvert ' + path.fromUser(app.args.input, True) + ' ' + path.toTemp('input.mif', True))
alg.getInputs()

app.gotoTempDir()

alg.execute()

(stdout,stderr) = run.command('5ttcheck result.mif', False)
if len(stderr) and 'ERROR' in stderr:
app.warn('Generated image does not perfectly conform to 5TT format')

run.command('mrconvert result.mif ' + path.fromUser(app.args.output, True) + (' -force' if app.force else ''))
app.complete()

File renamed without changes.
File renamed without changes.
File renamed without changes.
118 changes: 118 additions & 0 deletions bin/dwi2response
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/usr/bin/env python

# Script for estimating response functions for spherical deconvolution
# A number of different approaches are available within this script for performing response function estimation.


# Make the corresponding MRtrix3 Python libraries available
import inspect, os, sys
lib_folder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile(inspect.currentframe()))[0], os.pardir, 'lib')))
if not os.path.isdir(lib_folder):
sys.stderr.write('Unable to locate MRtrix3 Python libraries')
sys.exit(1)
sys.path.insert(0, lib_folder)


from mrtrix3 import algorithm, app, image, path, run


app.init('Robert E. Smith (robert.smith@florey.edu.au) and Thijs Dhollander (thijs.dhollander@gmail.com)',
'Estimate response function(s) for spherical deconvolution')
app.cmdline.addDescription('dwi2response acts as a \'master\' script for performing various types of response function estimation; a range of different algorithms are available for completing this task. When using this script, the name of the algorithm to be used must appear as the first argument on the command-line after \'dwi2response\'. The subsequent compulsory arguments and options available depend on the particular algorithm being invoked.')
app.cmdline.addDescription('Each algorithm available also has its own help page, including necessary references; e.g. to see the help page of the \'fa\' algorithm, type \'dwi2response fa\'.')

# General options
common_options = app.cmdline.add_argument_group('Options common to all dwi2response algorithms')
common_options.add_argument('-shell', help='The b-value shell(s) to use in response function estimation (single value for single-shell response, comma-separated list for multi-shell response)')
common_options.add_argument('-lmax', help='The maximum harmonic degree(s) of response function estimation (single value for single-shell response, comma-separated list for multi-shell response)')
common_options.add_argument('-mask', help='Provide an initial mask for response voxel selection')
common_options.add_argument('-voxels', help='Output an image showing the final voxel selection(s)')
common_options.add_argument('-grad', help='Pass the diffusion gradient table in MRtrix format')
common_options.add_argument('-fslgrad', nargs=2, metavar=('bvecs', 'bvals'), help='Pass the diffusion gradient table in FSL bvecs/bvals format')
app.cmdline.flagMutuallyExclusiveOptions( [ 'grad', 'fslgrad' ] )

# Import the command-line settings for all algorithms found in the relevant directory
algorithm.initialise()


app.parse()


# Find out which algorithm the user has requested
alg = algorithm.getModule(app.args.algorithm)


# Check for prior existence of output files, and grab any input files, used by the particular algorithm
if app.args.voxels:
app.checkOutputPath(app.args.voxels)
alg.checkOutputPaths()


# Sanitise some inputs, and get ready for data import
if app.args.lmax:
try:
lmax = [ int(x) for x in app.args.lmax.split(',') ]
if any([lmax_value%2 for lmax_value in lmax]):
app.error('Value of lmax must be even')
except:
app.error('Parameter lmax must be a number')
if alg.needsSingleShell() and not len(lmax) == 1:
app.error('Can only specify a single lmax value for single-shell algorithms')
shell_option = ''
if app.args.shell:
try:
shell_values = [ int(x) for x in app.args.shell.split(',') ]
except:
app.error('-shell option should provide a comma-separated list of b-values')
if alg.needsSingleShell() and not len(shell_values) == 1:
app.error('Can only specify a single b-value shell for single-shell algorithms')
shell_option = ' -shell ' + app.args.shell
singleshell_option = ''
if alg.needsSingleShell():
singleshell_option = ' -singleshell -no_bzero'

grad_import_option = ''
if app.args.grad:
grad_import_option = ' -grad ' + path.fromUser(app.args.grad, True)
elif app.args.fslgrad:
grad_import_option = ' -fslgrad ' + path.fromUser(app.args.fslgrad[0], True) + ' ' + path.fromUser(app.args.fslgrad[1], True)
elif not image.headerField(path.fromUser(app.args.input, False), 'dwgrad'):
app.error('Script requires diffusion gradient table: either in image header, or using -grad / -fslgrad option')

app.makeTempDir()

# Get standard input data into the temporary directory
if alg.needsSingleShell() or shell_option:
run.command('mrconvert ' + path.fromUser(app.args.input, True) + ' - -stride 0,0,0,1' + grad_import_option + ' | dwiextract - ' + path.toTemp('dwi.mif', True) + shell_option + singleshell_option)
else: # Don't discard b=0 in multi-shell algorithms
run.command('mrconvert ' + path.fromUser(app.args.input, True) + ' ' + path.toTemp('dwi.mif', True) + ' -stride 0,0,0,1' + grad_import_option)
if app.args.mask:
run.command('mrconvert ' + path.fromUser(app.args.mask, True) + ' ' + path.toTemp('mask.mif', True) + ' -datatype bit')

alg.getInputs()

app.gotoTempDir()


# Generate a brain mask (if necessary)
# Otherwise, check that the mask provided is appropriate
if os.path.exists('mask.mif'):
dwi_size = [ int(x) for x in image.headerField('dwi.mif', 'size').split() ]
mask_size = [ int(x) for x in image.headerField('mask.mif', 'size').split() ]
if not mask_size[:3] == dwi_size[:3]:
app.error('Dimensions of provided mask image do not match DWI')
if int(image.statistic('mask.mif', 'count', 'mask.mif')) == 0:
app.error('Input mask does not contain any voxels')
else:
run.command('dwi2mask dwi.mif mask.mif')


# From here, the script splits depending on what estimation algorithm is being used
alg.execute()


# Finalize for all algorithms
if app.args.voxels:
run.command('mrconvert voxels.mif ' + path.fromUser(app.args.voxels, True) + (' -force' if app.force else ''))
app.complete()

128 changes: 128 additions & 0 deletions bin/dwibiascorrect
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/env python

# Script that performs B1 field inhomogeneity correction for a DWI volume series
# Bias field is estimated using the mean b=0 image, and subsequently used to correct all volumes


# Make the corresponding MRtrix3 Python libraries available
import inspect, os, sys
lib_folder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile(inspect.currentframe()))[0], os.pardir, 'lib')))
if not os.path.isdir(lib_folder):
sys.stderr.write('Unable to locate MRtrix3 Python libraries')
sys.exit(1)
sys.path.insert(0, lib_folder)


from distutils.spawn import find_executable
from mrtrix3 import app, fsl, image, path, run


app.init('Robert E. Smith (robert.smith@florey.edu.au)',
'Perform B1 field inhomogeneity correction for a DWI volume series')
app.cmdline.addCitation('If using -fast option', 'Zhang, Y.; Brady, M. & Smith, S. Segmentation of brain MR images through a hidden Markov random field model and the expectation-maximization algorithm. IEEE Transactions on Medical Imaging, 2001, 20, 45-57', True)
app.cmdline.addCitation('If using -fast option', 'Smith, S. M.; Jenkinson, M.; Woolrich, M. W.; Beckmann, C. F.; Behrens, T. E.; Johansen-Berg, H.; Bannister, P. R.; De Luca, M.; Drobnjak, I.; Flitney, D. E.; Niazy, R. K.; Saunders, J.; Vickers, J.; Zhang, Y.; De Stefano, N.; Brady, J. M. & Matthews, P. M. Advances in functional and structural MR image analysis and implementation as FSL. NeuroImage, 2004, 23, S208-S219', True)
app.cmdline.addCitation('If using -ants option', 'Tustison, N.; Avants, B.; Cook, P.; Zheng, Y.; Egan, A.; Yushkevich, P. & Gee, J. N4ITK: Improved N3 Bias Correction. IEEE Transactions on Medical Imaging, 2010, 29, 1310-1320', True)
app.cmdline.add_argument('input', help='The input image series to be corrected')
app.cmdline.add_argument('output', help='The output corrected image series')
options = app.cmdline.add_argument_group('Options for the dwibiascorrect script')
options.add_argument('-mask', help='Manually provide a mask image for bias field estimation')
options.add_argument('-bias', help='Output the estimated bias field')
options.add_argument('-ants', action='store_true', help='Use ANTS N4 to estimate the inhomogeneity field')
options.add_argument('-fsl', action='store_true', help='Use FSL FAST to estimate the inhomogeneity field')
app.cmdline.flagMutuallyExclusiveOptions( [ 'ants', 'fsl' ] )
options.add_argument('-grad', help='Pass the diffusion gradient table in MRtrix format')
options.add_argument('-fslgrad', nargs=2, metavar=('bvecs', 'bvals'), help='Pass the diffusion gradient table in FSL bvecs/bvals format')
app.cmdline.flagMutuallyExclusiveOptions( [ 'grad', 'fslgrad' ] )
app.parse()

if app.args.fsl:

if app.isWindows():
app.error('Script cannot run using FSL on Windows due to FSL dependency')

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

fast_cmd = 'fast'
if not find_executable(fast_cmd):
fast_cmd = 'fsl5.0-fast'
if not find_executable(fast_cmd):
app.error('Could not find FSL program fast; please verify FSL install')

fsl_suffix = fsl.suffix()
if fast_cmd == 'fast':
fast_suffix = fsl_suffix
else:
fast_suffix = '.nii.gz'

elif app.args.ants:

if not find_executable('N4BiasFieldCorrection'):
app.error('Could not find ANTS program N4BiasFieldCorrection; please check installation')

else:
app.error('No bias field estimation algorithm specified')

grad_import_option = ''
if app.args.grad:
grad_import_option = ' -grad ' + path.fromUser(app.args.grad, True)
elif app.args.fslgrad:
grad_import_option = ' -fslgrad ' + path.fromUser(app.args.fslgrad[0], True) + ' ' + path.fromUser(app.args.fslgrad[1], True)

app.checkOutputPath(app.args.output)
app.checkOutputPath(app.args.bias)

app.makeTempDir()

run.command('mrconvert ' + path.fromUser(app.args.input, True) + ' ' + path.toTemp('in.mif', True) + grad_import_option)
if app.args.mask:
run.command('mrconvert ' + path.fromUser(app.args.mask, True) + ' ' + path.toTemp('mask.mif', True))

app.gotoTempDir()

# Make sure it's actually a DWI that's been passed
dwi_sizes = image.headerField('in.mif', 'size').split()
if len(dwi_sizes) != 4:
app.error('Input image must be a 4D image')
DW_scheme = image.headerField('in.mif', 'dwgrad').split('\n')
if len(DW_scheme) != int(dwi_sizes[3]):
app.error('Input image does not contain valid DW gradient scheme')

# Generate a brain mask if required, or check the mask if provided
if app.args.mask:
mask_sizes = image.headerField('mask.mif', 'size').split()
if not mask_sizes[:3] == dwi_sizes[:3]:
app.error('Provided mask image does not match input DWI')
else:
run.command('dwi2mask in.mif mask.mif')

# Generate a mean b=0 image
run.command('dwiextract in.mif - -bzero | mrmath - mean mean_bzero.mif -axis 3')

if app.args.fsl:
# FAST doesn't accept a mask input; therefore need to explicitly mask the input image
run.command('mrcalc mean_bzero.mif mask.mif -mult - | mrconvert - mean_bzero_masked.nii -stride -1,+2,+3')
run.command(fast_cmd + ' -t 2 -o fast -n 3 -b mean_bzero_masked.nii')
bias_path = 'fast_bias' + fast_suffix
elif app.args.ants:

# If the mask image was provided manually, and doesn't match the input image perfectly
# (i.e. also transform and voxel sizes), N4 will fail
if app.args.mask:
if not image.match('mean_bzero.mif', 'mask.mif'):
app.error('Input mask header does not perfectly match DWI as required by N4')

# Use the brain mask as a weights image rather than a mask; means that voxels at the edge of the mask
# will have a smoothly-varying bias field correction applied, rather than multiplying by 1.0 outside the mask
run.command('mrconvert mean_bzero.mif mean_bzero.nii -stride +1,+2,+3')
run.command('mrconvert mask.mif mask.nii -stride +1,+2,+3')
bias_path = 'bias.nii'
run.command('N4BiasFieldCorrection -d 3 -i mean_bzero.nii -w mask.nii -o [corrected.nii,' + bias_path + '] -s 2 -b [150] -c [200x200,0.0]')

run.command('mrcalc in.mif ' + bias_path + ' -div result.mif')
run.command('mrconvert result.mif ' + path.fromUser(app.args.output, True) + (' -force' if app.force else ''))
if app.args.bias:
run.command('mrconvert ' + bias_path + ' ' + path.fromUser(app.args.bias, True) + (' -force' if app.force else ''))
app.complete()

Loading

0 comments on commit 5b5ef20

Please sign in to comment.