diff --git a/.zenodo.json b/.zenodo.json index 065e188d8b..db64d56b49 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -330,6 +330,11 @@ "name": "Liem, Franz", "orcid": "0000-0003-0646-4810" }, + { + "affiliation": "The Centre for Addiction and Mental Health", + "name": "Joseph, Michael", + "orcid": "0000-0002-0068-230X" + }, { "affiliation": "UniversityHospital Heidelberg, Germany", "name": "Kleesiek, Jens" diff --git a/nipype/interfaces/fsl/epi.py b/nipype/interfaces/fsl/epi.py index 3e47576ec7..bbe84149c8 100644 --- a/nipype/interfaces/fsl/epi.py +++ b/nipype/interfaces/fsl/epi.py @@ -1383,7 +1383,7 @@ def _list_outputs(self): # If the output directory isn't defined, the interface seems to use # the default but not set its value in `self.inputs.output_dir` if not isdefined(self.inputs.output_dir): - out_dir = os.path.abspath(os.path.basename(self.inputs.base_name) + '.qc.nii.gz') + out_dir = os.path.abspath(os.path.basename(self.inputs.base_name) + '.qc') else: out_dir = os.path.abspath(self.inputs.output_dir) @@ -1421,4 +1421,3 @@ def _list_outputs(self): outputs['clean_volumes'] = clean_volumes return outputs - diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 507380c30e..c9c131dde3 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -6,7 +6,7 @@ from .utils import (Mesh2PVE, Generate5tt, BrainMask, TensorMetrics, ComputeTDI, TCK2VTK, MRMath, MRConvert, DWIExtract) from .preprocess import (ResponseSD, ACTPrepareFSL, ReplaceFSwithFIRST, - DWIDenoise) + DWIDenoise, MRDeGibbs, DWIBiasCorrect) from .tracking import Tractography from .reconst import FitTensor, EstimateFOD from .connectivity import LabelConfig, LabelConvert, BuildConnectome diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py index fc3559c918..99c6c4fb03 100644 --- a/nipype/interfaces/mrtrix3/preprocess.py +++ b/nipype/interfaces/mrtrix3/preprocess.py @@ -28,16 +28,18 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec): desc='set the window size of the denoising filter. (default = 5,5,5)') noise = File( argstr='-noise %s', - desc='noise map') + desc='the output noise map') out_file = File(name_template='%s_denoised', name_source='in_file', keep_extension=True, - argstr="%s", + argstr='%s', position=-1, - desc="the output denoised DWI image") + desc='the output denoised DWI image', + genfile=True) class DWIDenoiseOutputSpec(TraitedSpec): - out_file = File(desc="the output denoised DWI image", exists=True) + noise = File(desc='the output noise map', exists=True) + out_file = File(desc='the output denoised DWI image', exists=True) class DWIDenoise(MRTrix3Base): """ @@ -74,6 +76,174 @@ class DWIDenoise(MRTrix3Base): input_spec = DWIDenoiseInputSpec output_spec = DWIDenoiseOutputSpec + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + if self.inputs.noise != Undefined: + outputs['noise'] = op.abspath(self.inputs.noise) + return outputs + + +class MRDeGibbsInputSpec(MRTrix3BaseInputSpec): + in_file = File( + exists=True, + argstr='%s', + position=-2, + mandatory=True, + desc='input DWI image') + axes = traits.ListInt( + default_value=[0,1], + usedefault=True, + sep=',', + minlen=2, + maxlen=2, + argstr='-axes %s', + desc='indicate the plane in which the data was acquired (axial = 0,1; ' + 'coronal = 0,2; sagittal = 1,2') + nshifts = traits.Int( + default_value=20, + usedefault=True, + argstr='-nshifts %d', + desc='discretization of subpixel spacing (default = 20)') + minW = traits.Int( + default_value=1, + usedefault=True, + argstr='-minW %d', + desc='left border of window used for total variation (TV) computation ' + '(default = 1)') + maxW = traits.Int( + default_value=3, + usedefault=True, + argstr='-maxW %d', + desc='right border of window used for total variation (TV) computation ' + '(default = 3)') + out_file = File(name_template='%s_unr', + name_source='in_file', + keep_extension=True, + argstr='%s', + position=-1, + desc='the output unringed DWI image', + genfile=True) + +class MRDeGibbsOutputSpec(TraitedSpec): + out_file = File(desc='the output unringed DWI image', exists=True) + +class MRDeGibbs(MRTrix3Base): + """ + Remove Gibbs ringing artifacts. + + This application attempts to remove Gibbs ringing artefacts from MRI images + using the method of local subvoxel-shifts proposed by Kellner et al. + + This command is designed to run on data directly after it has been + reconstructed by the scanner, before any interpolation of any kind has + taken place. You should not run this command after any form of motion + correction (e.g. not after dwipreproc). Similarly, if you intend running + dwidenoise, you should run this command afterwards, since it has the + potential to alter the noise structure, which would impact on dwidenoise's + performance. + + Note that this method is designed to work on images acquired with full + k-space coverage. Running this method on partial Fourier ('half-scan') data + may lead to suboptimal and/or biased results, as noted in the original + reference below. There is currently no means of dealing with this; users + should exercise caution when using this method on partial Fourier data, and + inspect its output for any obvious artefacts. + + For more information, see + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> unring = mrt.MRDeGibbs() + >>> unring.inputs.in_file = 'dwi.mif' + >>> unring.cmdline + 'mrdegibbs -axes 0,1 -maxW 3 -minW 1 -nshifts 20 dwi.mif dwi_unr.mif' + >>> unring.run() # doctest: +SKIP + """ + + _cmd = 'mrdegibbs' + input_spec = MRDeGibbsInputSpec + output_spec = MRDeGibbsOutputSpec + + +class DWIBiasCorrectInputSpec(MRTrix3BaseInputSpec): + in_file = File( + exists=True, + argstr='%s', + position=-2, + mandatory=True, + desc='input DWI image') + in_mask = File( + argstr='-mask %s', + desc='input mask image for bias field estimation') + _xor_methods = ('use_ants', 'use_fsl') + use_ants = traits.Bool( + default_value=True, + usedefault=True, + argstr='-ants', + desc='use ANTS N4 to estimate the inhomogeneity field', + xor=_xor_methods) + use_fsl = traits.Bool( + argstr='-fsl', + desc='use FSL FAST to estimate the inhomogeneity field', + xor=_xor_methods, + min_ver='5.0.10') + _xor_grads = ('mrtrix_grad', 'fsl_grad') + mrtrix_grad = File( + argstr='-grad %s', + desc='diffusion gradient table in MRtrix format', + xor=_xor_grads) + fsl_grad = File( + argstr='-fslgrad %s %s', + desc='diffusion gradient table in FSL bvecs/bvals format', + xor=_xor_grads) + bias = File( + argstr='-bias %s', + desc='bias field') + out_file = File(name_template='%s_biascorr', + name_source='in_file', + keep_extension=True, + argstr='%s', + position=-1, + desc='the output bias corrected DWI image', + genfile=True) + +class DWIBiasCorrectOutputSpec(TraitedSpec): + bias = File(desc='the output bias field', exists=True) + out_file = File(desc='the output bias corrected DWI image', exists=True) + +class DWIBiasCorrect(MRTrix3Base): + """ + Perform B1 field inhomogeneity correction for a DWI volume series. + + For more information, see + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> bias_correct = mrt.DWIBiasCorrect() + >>> bias_correct.inputs.in_file = 'dwi.mif' + >>> bias_correct.cmdline + 'dwibiascorrect -ants dwi.mif dwi_biascorr.mif' + >>> bias_correct.run() # doctest: +SKIP + """ + + _cmd = 'dwibiascorrect' + input_spec = DWIBiasCorrectInputSpec + output_spec = DWIBiasCorrectOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = op.abspath(self.inputs.out_file) + if self.inputs.bias != Undefined: + outputs['bias'] = op.abspath(self.inputs.bias) + return outputs + class ResponseSDInputSpec(MRTrix3BaseInputSpec): algorithm = traits.Enum( diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py new file mode 100644 index 0000000000..ea4d3f05d8 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py @@ -0,0 +1,70 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..preprocess import DWIBiasCorrect + + +def test_DWIBiasCorrect_inputs(): + input_map = dict( + args=dict(argstr='%s', ), + bias=dict(argstr='-bias %s', ), + bval_scale=dict(argstr='-bvalue_scaling %s', ), + environ=dict( + nohash=True, + usedefault=True, + ), + fsl_grad=dict( + argstr='-fslgrad %s %s', + xor=('mrtrix_grad', 'fsl_grad'), + ), + grad_file=dict(argstr='-grad %s', ), + grad_fsl=dict(argstr='-fslgrad %s %s', ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', ), + in_file=dict( + argstr='%s', + mandatory=True, + position=-2, + ), + in_mask=dict(argstr='-mask %s', ), + mrtrix_grad=dict( + argstr='-grad %s', + xor=('mrtrix_grad', 'fsl_grad'), + ), + nthreads=dict( + argstr='-nthreads %d', + nohash=True, + ), + out_file=dict( + argstr='%s', + genfile=True, + keep_extension=True, + name_source='in_file', + name_template='%s_biascorr', + position=-1, + ), + use_ants=dict( + argstr='-ants', + usedefault=True, + xor=('use_ants', 'use_fsl'), + ), + use_fsl=dict( + argstr='-fsl', + min_ver='5.0.10', + xor=('use_ants', 'use_fsl'), + ), + ) + inputs = DWIBiasCorrect.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_DWIBiasCorrect_outputs(): + output_map = dict( + bias=dict(), + out_file=dict(), + ) + outputs = DWIBiasCorrect.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py index 769ccb34a9..7b6930ee82 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py @@ -32,6 +32,7 @@ def test_DWIDenoise_inputs(): ), out_file=dict( argstr='%s', + genfile=True, keep_extension=True, name_source='in_file', name_template='%s_denoised', @@ -44,7 +45,10 @@ def test_DWIDenoise_inputs(): for metakey, value in list(metadata.items()): assert getattr(inputs.traits()[key], metakey) == value def test_DWIDenoise_outputs(): - output_map = dict(out_file=dict(), ) + output_map = dict( + noise=dict(), + out_file=dict(), + ) outputs = DWIDenoise.output_spec() for key, metadata in list(output_map.items()): diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py new file mode 100644 index 0000000000..c9290b562b --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py @@ -0,0 +1,66 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..preprocess import MRDeGibbs + + +def test_MRDeGibbs_inputs(): + input_map = dict( + args=dict(argstr='%s', ), + axes=dict( + argstr='-axes %s', + maxlen=2, + minlen=2, + sep=',', + usedefault=True, + ), + bval_scale=dict(argstr='-bvalue_scaling %s', ), + environ=dict( + nohash=True, + usedefault=True, + ), + grad_file=dict(argstr='-grad %s', ), + grad_fsl=dict(argstr='-fslgrad %s %s', ), + in_bval=dict(), + in_bvec=dict(argstr='-fslgrad %s %s', ), + in_file=dict( + argstr='%s', + mandatory=True, + position=-2, + ), + maxW=dict( + argstr='-maxW %d', + usedefault=True, + ), + minW=dict( + argstr='-minW %d', + usedefault=True, + ), + nshifts=dict( + argstr='-nshifts %d', + usedefault=True, + ), + nthreads=dict( + argstr='-nthreads %d', + nohash=True, + ), + out_file=dict( + argstr='%s', + genfile=True, + keep_extension=True, + name_source='in_file', + name_template='%s_unr', + position=-1, + ), + ) + inputs = MRDeGibbs.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value +def test_MRDeGibbs_outputs(): + output_map = dict(out_file=dict(), ) + outputs = MRDeGibbs.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value