diff --git a/nipype/interfaces/ants/__init__.py b/nipype/interfaces/ants/__init__.py index 0de5c1646f..5ce3da60a3 100644 --- a/nipype/interfaces/ants/__init__.py +++ b/nipype/interfaces/ants/__init__.py @@ -4,7 +4,8 @@ """Top-level namespace for ants.""" # Registraiton programs -from .registration import ANTS, Registration, MeasureImageSimilarity +from .registration import (ANTS, Registration, RegistrationSynQuick, + MeasureImageSimilarity) # Resampling Programs from .resampling import (ApplyTransforms, ApplyTransformsToPoints, diff --git a/nipype/interfaces/ants/registration.py b/nipype/interfaces/ants/registration.py index 843e9b3043..bcc1d94b89 100644 --- a/nipype/interfaces/ants/registration.py +++ b/nipype/interfaces/ants/registration.py @@ -15,7 +15,7 @@ from ...utils.filemanip import filename_to_list from ..base import TraitedSpec, File, Str, traits, InputMultiPath, isdefined -from .base import ANTSCommand, ANTSCommandInputSpec +from .base import ANTSCommand, ANTSCommandInputSpec, LOCAL_DEFAULT_NUMBER_OF_THREADS class ANTSInputSpec(ANTSCommandInputSpec): @@ -1505,3 +1505,107 @@ def aggregate_outputs(self, runtime=None, needed_outputs=None): stdout = runtime.stdout.split('\n') outputs.similarity = float(stdout[0]) return outputs + + +class RegistrationSynQuickInputSpec(ANTSCommandInputSpec): + dimension = traits.Enum(3, 2, argstr='-d %d', + usedefault=True, desc='image dimension (2 or 3)') + fixed_image = InputMultiPath(File(exists=True), mandatory=True, argstr='-f %s...', + desc='Fixed image or source image or reference image') + moving_image = InputMultiPath(File(exists=True), mandatory=True, argstr='-m %s...', + desc='Moving image or target image') + output_prefix = Str("transform", usedefault=True, argstr='-o %s', + desc="A prefix that is prepended to all output files") + num_threads = traits.Int(default_value=LOCAL_DEFAULT_NUMBER_OF_THREADS, usedefault=True, + desc='Number of threads (default = 1)', argstr='-n %d') + + transform_type = traits.Enum('s', 't', 'r', 'a', 'sr', 'b', 'br', argstr='-t %s', + desc=""" + transform type + t: translation + r: rigid + a: rigid + affine + s: rigid + affine + deformable syn (default) + sr: rigid + deformable syn + b: rigid + affine + deformable b-spline syn + br: rigid + deformable b-spline syn""", + usedefault=True) + + use_histogram_matching = traits.Bool(False, argstr='-j %d', + desc='use histogram matching') + histogram_bins = traits.Int(default_value=32, argstr='-r %d', + desc='histogram bins for mutual information in SyN stage \ + (default = 32)') + spline_distance = traits.Int(default_value=26, argstr='-s %d', + desc='spline distance for deformable B-spline SyN transform \ + (default = 26)') + precision_type = traits.Enum('double', 'float', argstr='-p %s', + desc='precision type (default = double)', usedefault=True) + + +class RegistrationSynQuickOutputSpec(TraitedSpec): + warped_image = File(exists=True, desc="Warped image") + inverse_warped_image = File(exists=True, desc="Inverse warped image") + out_matrix = File(exists=True, desc='Affine matrix') + forward_warp_field = File(exists=True, desc='Forward warp field') + inverse_warp_field = File(exists=True, desc='Inverse warp field') + + +class RegistrationSynQuick(ANTSCommand): + """ + Registration using a symmetric image normalization method (SyN). + You can read more in Avants et al.; Med Image Anal., 2008 + (https://www.ncbi.nlm.nih.gov/pubmed/17659998). + + Examples + -------- + + >>> from nipype.interfaces.ants import RegistrationSynQuick + >>> reg = RegistrationSynQuick() + >>> reg.inputs.fixed_image = 'fixed1.nii' + >>> reg.inputs.moving_image = 'moving1.nii' + >>> reg.inputs.num_threads = 2 + >>> reg.cmdline + 'antsRegistrationSynQuick.sh -d 3 -f fixed1.nii -m moving1.nii -n 2 -o transform -p d -t s' + >>> reg.run() # doctest: +SKIP + + example for multiple images + + >>> from nipype.interfaces.ants import RegistrationSynQuick + >>> reg = RegistrationSynQuick() + >>> reg.inputs.fixed_image = ['fixed1.nii', 'fixed2.nii'] + >>> reg.inputs.moving_image = ['moving1.nii', 'moving2.nii'] + >>> reg.inputs.num_threads = 2 + >>> reg.cmdline + 'antsRegistrationSynQuick.sh -d 3 -f fixed1.nii -f fixed2.nii -m moving1.nii -m moving2.nii -n 2 -o transform -p d -t s' + >>> reg.run() # doctest: +SKIP + """ + + + _cmd = 'antsRegistrationSynQuick.sh' + input_spec = RegistrationSynQuickInputSpec + output_spec = RegistrationSynQuickOutputSpec + + def _num_threads_update(self): + """ + antsRegistrationSynQuick.sh ignores environment variables, + so override environment update frm ANTSCommand class + """ + pass + + def _format_arg(self, name, spec, value): + if name == 'precision_type': + return spec.argstr % value[0] + return super(RegistrationSynQuick, self)._format_arg(name, spec, value) + + def _list_outputs(self): + outputs = self.output_spec().get() + out_base = os.path.abspath(self.inputs.output_prefix) + outputs['warped_image'] = out_base + 'Warped.nii.gz' + outputs['inverse_warped_image'] = out_base + 'InverseWarped.nii.gz' + outputs['out_matrix'] = out_base + '0GenericAffine.mat' + + if self.inputs.transform_type not in ('t', 'r', 'a'): + outputs['forward_warp_field'] = out_base + '1Warp.nii.gz' + outputs['inverse_warp_field'] = out_base + '1InverseWarp.nii.gz' + return outputs diff --git a/nipype/interfaces/ants/tests/test_auto_RegistrationSynQuick.py b/nipype/interfaces/ants/tests/test_auto_RegistrationSynQuick.py new file mode 100644 index 0000000000..d481b810d5 --- /dev/null +++ b/nipype/interfaces/ants/tests/test_auto_RegistrationSynQuick.py @@ -0,0 +1,71 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from __future__ import unicode_literals +from ..registration import RegistrationSynQuick + + +def test_RegistrationSynQuick_inputs(): + input_map = dict( + args=dict(argstr='%s', ), + dimension=dict( + argstr='-d %d', + usedefault=True, + ), + environ=dict( + nohash=True, + usedefault=True, + ), + fixed_image=dict( + argstr='-f %s...', + mandatory=True, + ), + histogram_bins=dict(argstr='-r %d', ), + ignore_exception=dict( + deprecated='1.0.0', + nohash=True, + usedefault=True, + ), + moving_image=dict( + argstr='-m %s...', + mandatory=True, + ), + num_threads=dict( + argstr='-n %d', + usedefault=True, + ), + output_prefix=dict( + argstr='-o %s', + usedefault=True, + ), + precision_type=dict( + argstr='-p %s', + usedefault=True, + ), + spline_distance=dict(argstr='-s %d', ), + terminal_output=dict( + deprecated='1.0.0', + nohash=True, + ), + transform_type=dict( + argstr='-t %s', + usedefault=True, + ), + use_histogram_matching=dict(argstr='-j %d', ), + ) + inputs = RegistrationSynQuick.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_RegistrationSynQuick_outputs(): + output_map = dict( + forward_warp_field=dict(), + inverse_warp_field=dict(), + inverse_warped_image=dict(), + out_matrix=dict(), + warped_image=dict(), + ) + outputs = RegistrationSynQuick.output_spec() + + for key, metadata in list(output_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(outputs.traits()[key], metakey) == value