From af8d36c90cfcf4ba6393835bc048dff4f45de7c3 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Sat, 2 Apr 2022 13:05:19 -0400 Subject: [PATCH] ENH: Add MRTrix3 interfaces (pared-down gh-3426) Co-authored-by: GalBenZvi Co-authored-by: Zvi Baratz --- nipype/interfaces/mrtrix3/__init__.py | 41 +-- nipype/interfaces/mrtrix3/base.py | 11 + .../mrtrix3/tests/test_auto_BrainMask.py | 7 + ..._auto_ConstrainedSphericalDeconvolution.py | 7 + .../mrtrix3/tests/test_auto_DWIBiasCorrect.py | 7 + .../mrtrix3/tests/test_auto_DWIDenoise.py | 7 + .../mrtrix3/tests/test_auto_DWIExtract.py | 7 + .../mrtrix3/tests/test_auto_DWIPreproc.py | 7 + .../mrtrix3/tests/test_auto_EstimateFOD.py | 7 + .../mrtrix3/tests/test_auto_FitTensor.py | 7 + .../mrtrix3/tests/test_auto_Generate5tt.py | 7 + .../mrtrix3/tests/test_auto_MRCat.py | 80 +++++ .../mrtrix3/tests/test_auto_MRConvert.py | 26 ++ .../mrtrix3/tests/test_auto_MRDeGibbs.py | 7 + .../mrtrix3/tests/test_auto_MRMath.py | 7 + .../mrtrix3/tests/test_auto_MRResize.py | 7 + .../mrtrix3/tests/test_auto_MRTransform.py | 113 +++++++ .../mrtrix3/tests/test_auto_ResponseSD.py | 7 + .../mrtrix3/tests/test_auto_TensorMetrics.py | 35 ++ .../mrtrix3/tests/test_auto_Tractography.py | 7 + .../tests/test_auto_TransformFSLConvert.py | 93 ++++++ nipype/interfaces/mrtrix3/utils.py | 303 +++++++++++++++++- 22 files changed, 780 insertions(+), 20 deletions(-) create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_MRCat.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_MRTransform.py create mode 100644 nipype/interfaces/mrtrix3/tests/test_auto_TransformFSLConvert.py diff --git a/nipype/interfaces/mrtrix3/__init__.py b/nipype/interfaces/mrtrix3/__init__.py index 9ea9850b1b..0ff8daa510 100644 --- a/nipype/interfaces/mrtrix3/__init__.py +++ b/nipype/interfaces/mrtrix3/__init__.py @@ -2,29 +2,32 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: # -*- coding: utf-8 -*- """MRTrix3 provides software tools to perform various types of diffusion MRI analyses.""" +from .connectivity import BuildConnectome, LabelConfig, LabelConvert +from .preprocess import ( + ACTPrepareFSL, + DWIBiasCorrect, + DWIDenoise, + DWIPreproc, + MRDeGibbs, + ReplaceFSwithFIRST, + ResponseSD, +) +from .reconst import ConstrainedSphericalDeconvolution, EstimateFOD, FitTensor +from .tracking import Tractography from .utils import ( - Mesh2PVE, - Generate5tt, + TCK2VTK, BrainMask, - TensorMetrics, ComputeTDI, - TCK2VTK, - MRMath, + DWIExtract, + Generate5tt, + Mesh2PVE, + MRCat, MRConvert, + MRMath, MRResize, - DWIExtract, - SHConv, + MRTransform, SH2Amp, + SHConv, + TensorMetrics, + TransformFSLConvert, ) -from .preprocess import ( - ResponseSD, - ACTPrepareFSL, - ReplaceFSwithFIRST, - DWIPreproc, - DWIDenoise, - MRDeGibbs, - DWIBiasCorrect, -) -from .tracking import Tractography -from .reconst import FitTensor, EstimateFOD, ConstrainedSphericalDeconvolution -from .connectivity import LabelConfig, LabelConvert, BuildConnectome diff --git a/nipype/interfaces/mrtrix3/base.py b/nipype/interfaces/mrtrix3/base.py index 7684e06cd7..af96b5a9f3 100644 --- a/nipype/interfaces/mrtrix3/base.py +++ b/nipype/interfaces/mrtrix3/base.py @@ -79,6 +79,15 @@ class MRTrix3BaseInputSpec(CommandLineInputSpec): exists=True, argstr="-fslgrad %s %s", desc="bvecs file in FSL format" ) in_bval = File(exists=True, desc="bvals file in FSL format") + out_bvec = File( + exists=False, + argstr="-export_grad_fsl %s %s", + desc="export bvec file in FSL format", + ) + out_bval = File( + exists=False, + desc="export bval file in FSL format", + ) class MRTrix3Base(CommandLine): @@ -96,6 +105,8 @@ def _format_arg(self, name, trait_spec, value): if name == "in_bvec": return trait_spec.argstr % (value, self.inputs.in_bval) + if name == "out_bvec": + return trait_spec.argstr % (value, self.inputs.out_bval) return super(MRTrix3Base, self)._format_arg(name, trait_spec, value) diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py index ddf96a9c5f..26f94fcab0 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_BrainMask.py @@ -40,6 +40,13 @@ def test_BrainMask_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_ConstrainedSphericalDeconvolution.py b/nipype/interfaces/mrtrix3/tests/test_auto_ConstrainedSphericalDeconvolution.py index c395f0d1c8..1348326728 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_ConstrainedSphericalDeconvolution.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ConstrainedSphericalDeconvolution.py @@ -77,6 +77,13 @@ def test_ConstrainedSphericalDeconvolution_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), predicted_signal=dict( argstr="-predicted_signal %s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py index 0028748ab9..82beccfa9d 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIBiasCorrect.py @@ -48,6 +48,13 @@ def test_DWIBiasCorrect_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py index efa722c81d..edd2ee254d 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIDenoise.py @@ -55,6 +55,13 @@ def test_DWIDenoise_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIExtract.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIExtract.py index 379e67d397..a2d05a6fdc 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIExtract.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIExtract.py @@ -46,6 +46,13 @@ def test_DWIExtract_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py b/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py index 7f226fe3cd..bc53d67b4b 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_DWIPreproc.py @@ -56,6 +56,13 @@ def test_DWIPreproc_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py index 2d15207571..378dd4a220 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_EstimateFOD.py @@ -80,6 +80,13 @@ def test_EstimateFOD_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), predicted_signal=dict( argstr="-predicted_signal %s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py index 7cf38faf8c..884b87be06 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_FitTensor.py @@ -47,6 +47,13 @@ def test_FitTensor_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py b/nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py index 1b135a5917..2e9a36c502 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Generate5tt.py @@ -45,6 +45,13 @@ def test_Generate5tt_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRCat.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRCat.py new file mode 100644 index 0000000000..25bfea5d37 --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRCat.py @@ -0,0 +1,80 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from ..utils import MRCat + + +def test_MRCat_inputs(): + input_map = dict( + args=dict( + argstr="%s", + ), + axis=dict( + argstr="-axis %s", + ), + bval_scale=dict( + argstr="-bvalue_scaling %s", + ), + datatype=dict( + argstr="-datatype %s", + ), + environ=dict( + nohash=True, + usedefault=True, + ), + grad_file=dict( + argstr="-grad %s", + extensions=None, + xor=["grad_fsl"], + ), + grad_fsl=dict( + argstr="-fslgrad %s %s", + xor=["grad_file"], + ), + in_bval=dict( + extensions=None, + ), + in_bvec=dict( + argstr="-fslgrad %s %s", + extensions=None, + ), + in_files=dict( + argstr="%s", + mandatory=True, + position=-2, + ), + nthreads=dict( + argstr="-nthreads %d", + nohash=True, + ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), + out_file=dict( + argstr="%s", + extensions=None, + mandatory=True, + position=-1, + usedefault=True, + ), + ) + inputs = MRCat.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_MRCat_outputs(): + output_map = dict( + out_file=dict( + extensions=None, + ), + ) + outputs = MRCat.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_MRConvert.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRConvert.py index 578ffb9b1a..0cd3c95794 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_MRConvert.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRConvert.py @@ -44,10 +44,27 @@ def test_MRConvert_inputs(): mandatory=True, position=-2, ), + json_export=dict( + argstr="-json_export %s", + extensions=None, + mandatory=False, + ), + json_import=dict( + argstr="-json_import %s", + extensions=None, + mandatory=False, + ), nthreads=dict( argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, @@ -73,6 +90,15 @@ def test_MRConvert_inputs(): def test_MRConvert_outputs(): output_map = dict( + json_export=dict( + extensions=None, + ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + extensions=None, + ), out_file=dict( extensions=None, ), diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py index f1ef52ab88..cd15f36ac6 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRDeGibbs.py @@ -59,6 +59,13 @@ def test_MRDeGibbs_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRMath.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRMath.py index 6446b2ceda..10470bea7a 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_MRMath.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRMath.py @@ -48,6 +48,13 @@ def test_MRMath_inputs(): mandatory=True, position=-2, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRResize.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRResize.py index ee982c9561..4728309194 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_MRResize.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRResize.py @@ -49,6 +49,13 @@ def test_MRResize_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_MRTransform.py b/nipype/interfaces/mrtrix3/tests/test_auto_MRTransform.py new file mode 100644 index 0000000000..b50ee2c67f --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_MRTransform.py @@ -0,0 +1,113 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from ..utils import MRTransform + + +def test_MRTransform_inputs(): + input_map = dict( + args=dict( + argstr="%s", + ), + bval_scale=dict( + argstr="-bvalue_scaling %s", + ), + debug=dict( + argstr="-debug", + position=1, + ), + environ=dict( + nohash=True, + usedefault=True, + ), + flip_x=dict( + argstr="-flipx", + position=1, + ), + grad_file=dict( + argstr="-grad %s", + extensions=None, + xor=["grad_fsl"], + ), + grad_fsl=dict( + argstr="-fslgrad %s %s", + xor=["grad_file"], + ), + in_bval=dict( + extensions=None, + ), + in_bvec=dict( + argstr="-fslgrad %s %s", + extensions=None, + ), + in_files=dict( + argstr="%s", + mandatory=True, + position=-2, + ), + invert=dict( + argstr="-inverse", + position=1, + ), + linear_transform=dict( + argstr="-linear %s", + extensions=None, + position=1, + ), + nthreads=dict( + argstr="-nthreads %d", + nohash=True, + ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), + out_file=dict( + argstr="%s", + extensions=None, + genfile=True, + position=-1, + ), + quiet=dict( + argstr="-quiet", + position=1, + ), + reference_image=dict( + argstr="-reference %s", + extensions=None, + position=1, + ), + replace_transform=dict( + argstr="-replace", + position=1, + ), + template_image=dict( + argstr="-template %s", + extensions=None, + position=1, + ), + transformation_file=dict( + argstr="-transform %s", + extensions=None, + position=1, + ), + ) + inputs = MRTransform.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_MRTransform_outputs(): + output_map = dict( + out_file=dict( + extensions=None, + ), + ) + outputs = MRTransform.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_ResponseSD.py b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py index f7e556f466..1b9d4db9b9 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_ResponseSD.py @@ -68,6 +68,13 @@ def test_ResponseSD_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), wm_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py b/nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py index b23813aaf4..bbe12033cb 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_TensorMetrics.py @@ -29,10 +29,26 @@ def test_TensorMetrics_inputs(): modulate=dict( argstr="-modulate %s", ), + out_ad=dict( + argstr="-ad %s", + extensions=None, + ), out_adc=dict( argstr="-adc %s", extensions=None, ), + out_cl=dict( + argstr="-cl %s", + extensions=None, + ), + out_cp=dict( + argstr="-cp %s", + extensions=None, + ), + out_cs=dict( + argstr="-cs %s", + extensions=None, + ), out_eval=dict( argstr="-value %s", extensions=None, @@ -45,6 +61,10 @@ def test_TensorMetrics_inputs(): argstr="-fa %s", extensions=None, ), + out_rd=dict( + argstr="-rd %s", + extensions=None, + ), ) inputs = TensorMetrics.input_spec() @@ -55,9 +75,21 @@ def test_TensorMetrics_inputs(): def test_TensorMetrics_outputs(): output_map = dict( + out_ad=dict( + extensions=None, + ), out_adc=dict( extensions=None, ), + out_cl=dict( + extensions=None, + ), + out_cp=dict( + extensions=None, + ), + out_cs=dict( + extensions=None, + ), out_eval=dict( extensions=None, ), @@ -67,6 +99,9 @@ def test_TensorMetrics_outputs(): out_fa=dict( extensions=None, ), + out_rd=dict( + extensions=None, + ), ) outputs = TensorMetrics.output_spec() diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py index 2a70fe09f6..87fac016f3 100644 --- a/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py +++ b/nipype/interfaces/mrtrix3/tests/test_auto_Tractography.py @@ -95,6 +95,13 @@ def test_Tractography_inputs(): argstr="-nthreads %d", nohash=True, ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), out_file=dict( argstr="%s", extensions=None, diff --git a/nipype/interfaces/mrtrix3/tests/test_auto_TransformFSLConvert.py b/nipype/interfaces/mrtrix3/tests/test_auto_TransformFSLConvert.py new file mode 100644 index 0000000000..48a528a75e --- /dev/null +++ b/nipype/interfaces/mrtrix3/tests/test_auto_TransformFSLConvert.py @@ -0,0 +1,93 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from ..utils import TransformFSLConvert + + +def test_TransformFSLConvert_inputs(): + input_map = dict( + args=dict( + argstr="%s", + ), + bval_scale=dict( + argstr="-bvalue_scaling %s", + ), + environ=dict( + nohash=True, + usedefault=True, + ), + flirt_import=dict( + argstr="flirt_import", + mandatory=True, + position=-2, + usedefault=True, + ), + grad_file=dict( + argstr="-grad %s", + extensions=None, + xor=["grad_fsl"], + ), + grad_fsl=dict( + argstr="-fslgrad %s %s", + xor=["grad_file"], + ), + in_bval=dict( + extensions=None, + ), + in_bvec=dict( + argstr="-fslgrad %s %s", + extensions=None, + ), + in_file=dict( + argstr="%s", + extensions=None, + mandatory=True, + position=1, + ), + in_transform=dict( + argstr="%s", + extensions=None, + mandatory=True, + position=0, + ), + nthreads=dict( + argstr="-nthreads %d", + nohash=True, + ), + out_bval=dict( + extensions=None, + ), + out_bvec=dict( + argstr="-export_grad_fsl %s %s", + extensions=None, + ), + out_transform=dict( + argstr="%s", + extensions=None, + mandatory=True, + position=-1, + usedefault=True, + ), + reference=dict( + argstr="%s", + extensions=None, + mandatory=True, + position=2, + ), + ) + inputs = TransformFSLConvert.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_TransformFSLConvert_outputs(): + output_map = dict( + out_transform=dict( + extensions=None, + ), + ) + outputs = TransformFSLConvert.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/utils.py b/nipype/interfaces/mrtrix3/utils.py index 77c3047f20..d5f8c2c5f5 100644 --- a/nipype/interfaces/mrtrix3/utils.py +++ b/nipype/interfaces/mrtrix3/utils.py @@ -4,6 +4,7 @@ import os.path as op +from ...utils.filemanip import split_filename from ..base import ( CommandLineInputSpec, CommandLine, @@ -64,6 +65,101 @@ def _list_outputs(self): return outputs +class MRCatInputSpec(MRTrix3BaseInputSpec): + in_files = traits.List( + File(exists=True), + argstr="%s", + position=-2, + mandatory=True, + desc="files to concatenate", + ) + + out_file = File( + "concatenated.mif", + argstr="%s", + mandatory=True, + position=-1, + usedefault=True, + desc="output concatenated image", + ) + + axis = traits.Int( + argstr="-axis %s", + desc="""specify axis along which concatenation should be performed. By default, + the program will use the last non-singleton, non-spatial axis of any of + the input images - in other words axis 3 or whichever axis (greater than + 3) of the input images has size greater than one""", + ) + + datatype = traits.Enum( + "float32", + "float32le", + "float32be", + "float64", + "float64le", + "float64be", + "int64", + "uint64", + "int64le", + "uint64le", + "int64be", + "uint64be", + "int32", + "uint32", + "int32le", + "uint32le", + "int32be", + "uint32be", + "int16", + "uint16", + "int16le", + "uint16le", + "int16be", + "uint16be", + "cfloat32", + "cfloat32le", + "cfloat32be", + "cfloat64", + "cfloat64le", + "cfloat64be", + "int8", + "uint8", + "bit", + argstr="-datatype %s", + desc="specify output image data type", + ) + + +class MRCatOutputSpec(TraitedSpec): + out_file = File(exists=True, desc="the output concatenated image") + + +class MRCat(CommandLine): + """ + Concatenate several images into one + + + Example + ------- + + >>> import nipype.interfaces.mrtrix3 as mrt + >>> mrcat = mrt.MRCat() + >>> mrcat.inputs.in_files = ['dwi.mif','mask.mif'] + >>> mrcat.cmdline # doctest: +ELLIPSIS + 'mrcat dwi.mif mask.mif concatenated.mif' + >>> mrcat.run() # doctest: +SKIP + """ + + _cmd = "mrcat" + input_spec = MRCatInputSpec + output_spec = MRCatOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs["out_file"] = op.abspath(self.inputs.out_file) + return outputs + + class Mesh2PVEInputSpec(CommandLineInputSpec): in_file = File( exists=True, argstr="%s", mandatory=True, position=-3, desc="input mesh" @@ -173,11 +269,20 @@ def _list_outputs(self): class TensorMetricsInputSpec(CommandLineInputSpec): in_file = File( - exists=True, argstr="%s", mandatory=True, position=-1, desc="input DTI image" + exists=True, + argstr="%s", + mandatory=True, + position=-1, + desc="input DTI image", ) out_fa = File(argstr="-fa %s", desc="output FA file") out_adc = File(argstr="-adc %s", desc="output ADC file") + out_ad = File(argstr="-ad %s", desc="output AD file") + out_rd = File(argstr="-rd %s", desc="output RD file") + out_cl = File(argstr="-cl %s", desc="output CL file") + out_cp = File(argstr="-cp %s", desc="output CP file") + out_cs = File(argstr="-cs %s", desc="output CS file") out_evec = File(argstr="-vector %s", desc="output selected eigenvector(s) file") out_eval = File(argstr="-value %s", desc="output selected eigenvalue(s) file") component = traits.List( @@ -209,6 +314,11 @@ class TensorMetricsInputSpec(CommandLineInputSpec): class TensorMetricsOutputSpec(TraitedSpec): out_fa = File(desc="output FA file") out_adc = File(desc="output ADC file") + out_ad = File(desc="output AD file") + out_rd = File(desc="output RD file") + out_cl = File(desc="output CL file") + out_cp = File(desc="output CP file") + out_cs = File(desc="output CS file") out_evec = File(desc="output selected eigenvector(s) file") out_eval = File(desc="output selected eigenvalue(s) file") @@ -580,10 +690,28 @@ class MRConvertInputSpec(MRTrix3BaseInputSpec): argstr="-scaling %s", desc="specify the data scaling parameter", ) + json_import = File( + exists=True, + argstr="-json_import %s", + mandatory=False, + desc="import data from a JSON file into header key-value pairs", + ) + json_export = File( + exists=False, + argstr="-json_export %s", + mandatory=False, + desc="export data from an image header key-value pairs into a JSON file", + ) class MRConvertOutputSpec(TraitedSpec): out_file = File(exists=True, desc="output image") + json_export = File( + exists=True, + desc="exported data from an image header key-value pairs in a JSON file", + ) + out_bvec = File(exists=True, desc="export bvec file in FSL format") + out_bval = File(exists=True, desc="export bvec file in FSL format") class MRConvert(MRTrix3Base): @@ -610,9 +738,182 @@ class MRConvert(MRTrix3Base): def _list_outputs(self): outputs = self.output_spec().get() outputs["out_file"] = op.abspath(self.inputs.out_file) + if self.inputs.json_export: + outputs["json_export"] = op.abspath(self.inputs.json_export) + if self.inputs.out_bvec: + outputs["out_bvec"] = op.abspath(self.inputs.out_bvec) + if self.inputs.out_bval: + outputs["out_bval"] = op.abspath(self.inputs.out_bval) + return outputs + + +class TransformFSLConvertInputSpec(MRTrix3BaseInputSpec): + in_file = File( + exists=True, + argstr="%s", + mandatory=True, + position=1, + desc="FLIRT input image", + ) + reference = File( + exists=True, + argstr="%s", + mandatory=True, + position=2, + desc="FLIRT reference image", + ) + in_transform = File( + exists=True, + argstr="%s", + mandatory=True, + position=0, + desc="FLIRT output transformation matrix", + ) + out_transform = File( + "transform_mrtrix.txt", + argstr="%s", + mandatory=True, + position=-1, + usedefault=True, + desc="output transformed affine in mrtrix3's format", + ) + flirt_import = traits.Bool( + True, + argstr="flirt_import", + mandatory=True, + usedefault=True, + position=-2, + desc="import transform from FSL's FLIRT.", + ) + + +class TransformFSLConvertOutputSpec(TraitedSpec): + out_transform = File( + exists=True, desc="output transformed affine in mrtrix3's format" + ) + + +class TransformFSLConvert(MRTrix3Base): + """ + Perform conversion between FSL's transformation matrix format to mrtrix3's. + """ + + _cmd = "transformconvert" + input_spec = TransformFSLConvertInputSpec + output_spec = TransformFSLConvertOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs["out_transform"] = op.abspath(self.inputs.out_transform) return outputs +class MRTransformInputSpec(MRTrix3BaseInputSpec): + in_files = InputMultiPath( + File(exists=True), + argstr="%s", + mandatory=True, + position=-2, + desc="Input images to be transformed", + ) + out_file = File( + genfile=True, + argstr="%s", + position=-1, + desc="Output image", + ) + invert = traits.Bool( + argstr="-inverse", + position=1, + desc="Invert the specified transform before using it", + ) + linear_transform = File( + exists=True, + argstr="-linear %s", + position=1, + desc=( + "Specify a linear transform to apply, in the form of a 3x4 or 4x4 ascii file. " + "Note the standard reverse convention is used, " + "where the transform maps points in the template image to the moving image. " + "Note that the reverse convention is still assumed even if no -template image is supplied." + ), + ) + replace_transform = traits.Bool( + argstr="-replace", + position=1, + desc="replace the current transform by that specified, rather than applying it to the current transform", + ) + transformation_file = File( + exists=True, + argstr="-transform %s", + position=1, + desc="The transform to apply, in the form of a 4x4 ascii file.", + ) + template_image = File( + exists=True, + argstr="-template %s", + position=1, + desc="Reslice the input image to match the specified template image.", + ) + reference_image = File( + exists=True, + argstr="-reference %s", + position=1, + desc="in case the transform supplied maps from the input image onto a reference image, use this option to specify the reference. Note that this implicitly sets the -replace option.", + ) + flip_x = traits.Bool( + argstr="-flipx", + position=1, + desc="assume the transform is supplied assuming a coordinate system with the x-axis reversed relative to the MRtrix convention (i.e. x increases from right to left). This is required to handle transform matrices produced by FSL's FLIRT command. This is only used in conjunction with the -reference option.", + ) + quiet = traits.Bool( + argstr="-quiet", + position=1, + desc="Do not display information messages or progress status.", + ) + debug = traits.Bool(argstr="-debug", position=1, desc="Display debugging messages.") + + +class MRTransformOutputSpec(TraitedSpec): + out_file = File(exists=True, desc="the output image of the transformation") + + +class MRTransform(MRTrix3Base): + """ + Apply spatial transformations or reslice images + + Example + ------- + + >>> MRxform = MRTransform() + >>> MRxform.inputs.in_files = 'anat_coreg.mif' + >>> MRxform.run() # doctest: +SKIP + """ + + _cmd = "mrtransform" + input_spec = MRTransformInputSpec + output_spec = MRTransformOutputSpec + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs["out_file"] = self.inputs.out_file + if not isdefined(outputs["out_file"]): + outputs["out_file"] = op.abspath(self._gen_outfilename()) + else: + outputs["out_file"] = op.abspath(outputs["out_file"]) + return outputs + + def _gen_filename(self, name): + if name == "out_file": + return self._gen_outfilename() + else: + return None + + def _gen_outfilename(self): + _, name, _ = split_filename(self.inputs.in_files[0]) + return name + "_MRTransform.mif" + + class MRMathInputSpec(MRTrix3BaseInputSpec): in_file = File( exists=True, argstr="%s", mandatory=True, position=-3, desc="input image"