Repository: nipy/nipype

Issue:
antsRegistrationSyNQuick (continuation of #1392)
continuing #1392 

not sure where to find a good description of RegistrationSyNQuick, [here](https://github.com/ANTsX/ANTs/blob/master/Scripts/antsRegistrationSyNQuick.sh) I can find only a few usage examples.


Discussion:

Resolving patch:
diff --git a/nipype/interfaces/ants/__init__.py b/nipype/interfaces/ants/__init__.py
--- 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
--- 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


Test patch:
diff --git a/nipype/interfaces/ants/tests/test_auto_RegistrationSynQuick.py b/nipype/interfaces/ants/tests/test_auto_RegistrationSynQuick.py
new file mode 100644
--- /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