Repository: nipy/nipype

Issue:
antsApplyTransform does not accept identity transform.  Enhancement request.
### Summary

antsApplyTransforms interface does not accept the transform 'identity' unless it is a file.  This is a deviation from the antsApplyTransforms command line function.  This feature is very helpful when two images are in the same space and one needs to be resampled to the the other. 

It would be nice if AntApplyTransform interface would accept the keyword identity as a transform.

### Actual behavior

The following error message is thrown when 'identity' is used as a transform

traits.trait_errors.TraitError: The trait 'transforms' of an ApplyTransformsInputSpec instance is an existing file name, but the path  'identity' does not exist.

### Expected behavior

When identity is set as the antsApplyTransforms the input file is resampled as the output file. It would be nice if the nipype antsApplyTransform interface would mimic the command line behavior. 

Here is a command line example. 

antsApplyTransforms -d 3 -i input.nii.gz -o output.nii.gz  -r reference.nii.gz  -t identity

The transform identity does not exist but is a keyword that allows the input image to be resampled at the same resolution as the reference image. 

### How to replicate the behavior

Just run the script below. 


### Script/Workflow details

from nipype.interfaces.ants import ApplyTransforms
at = ApplyTransforms()
at.inputs.dimension = 3
at.inputs.transforms = ['identity']

### Platform details:

170725-09:39:41,251 workflow DEBUG:
	 networkx 1.4 dev or higher detected
{'nipype_version': '0.13.1', 'pkg_path': '/Applications/anaconda3/lib/python3.5/site-packages/nipype', 'commit_hash': '<not found>', 'networkx_version': '1.11', 'commit_source': '(none found)', 'numpy_version': '1.11.2', 'traits_version': '4.6.0', 'sys_platform': 'darwin', 'sys_executable': '/Applications/anaconda3/bin/python', 'nibabel_version': '2.1.0', 'sys_version': '3.5.2 |Anaconda custom (x86_64)| (default, Jul  2 2016, 17:52:12) \n[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.28)]', 'scipy_version': '0.17.1'}
0.13.1

### Execution environment
- My python environment outside container



Discussion:
@bkraft4257 , is this `'identity'` argument documented somewhere? What is the first version it works?
Nick Tustison told me about it when I was trying to resample one image to another image that were already registered.  It is also documented in the function's help (although rather obscurely).   

> antsApplyTransforms 
...
 -t, --transform transformFileName
           [transformFileName,useInverse]
          Several transform options are supported including all those defined in the ITK
          library in addition to a deformation field transform. The ordering of the
          transformations follows the ordering specified on the command line. **An identity
          transform is pushed onto the transformation stack.** Each new transform
          encountered on the command line is also pushed onto the transformation stack.
          Then, to warp the input object, each point comprising the input object is warped
          first according to the last transform pushed onto the stack followed by the
          second to last transform, etc. until the last transform encountered which is the
          identity transform. Also, it should be noted that the inverse transform can be
          accommodated with the usual caveat that such an inverse must be defined by the
          specified transform class
...

If you run the antsApplyTransform command without a transform (i.e. no -t) the identity transform will be applied.  You will receive a warning message but the image will be resampled. 

antsApplyTransforms -d 3 -i input.nii.gz -o output.nii.gz -r reference.nii.gz 

Using double precision for computations.
Input scalar image: input.nii.gz
Reference image: reference.nii.gz
=============================================================================
The composite transform comprises the following transforms (in order):
=============================================================================
**WARNING: No transforms found, using identify transform**
Default pixel value: 0
Interpolation type: LinearInterpolateImageFunction
Output warped image: out.nii.gz

It is a useful trick which I have used for the last 3-4 years.  I know it is supported in the current version 2.2 

As a workaround I just created an identity matrix text file and used it to perform the resampling. If you leave the transform option empty in the nipype the function will fail. 

ValueError: ApplyTransforms requires a value for input 'transforms'. For a list of required inputs, see ApplyTransforms.help()


Thanks for considering this request.  Nipype is a great product and I am truly grateful for all the work that has been put into it. 

> As a workaround I just created an identity matrix text file and used it to perform the resampling. If you leave the transform option empty in the nipype the function will fail.
Yes, I use this trick too.

I'm doubtful because this is not well documented (if Nick didn't tell you, I don't think a human being can interpret that functionality from the documentation in any possible way). But I agree this is very useful. @satra WDYT?

Resolving patch:
diff --git a/nipype/interfaces/ants/resampling.py b/nipype/interfaces/ants/resampling.py
--- a/nipype/interfaces/ants/resampling.py
+++ b/nipype/interfaces/ants/resampling.py
@@ -243,13 +243,15 @@ class ApplyTransformsInputSpec(ANTSCommandInputSpec):
                                 'Gaussian',
                                 'BSpline',
                                 argstr='%s', usedefault=True)
-    interpolation_parameters = traits.Either(traits.Tuple(traits.Int()),  # BSpline (order)
-                                             traits.Tuple(traits.Float(),  # Gaussian/MultiLabel (sigma, alpha)
-                                                          traits.Float())
-                                            )
-    transforms = InputMultiPath(File(exists=True), argstr='%s', mandatory=True,
-                                desc='transform files: will be applied in reverse order. For '
-                                'example, the last specified transform will be applied first.')
+    interpolation_parameters = traits.Either(
+        traits.Tuple(traits.Int()),  # BSpline (order)
+        traits.Tuple(traits.Float(),  # Gaussian/MultiLabel (sigma, alpha)
+                     traits.Float())
+    )
+    transforms = traits.Either(
+        InputMultiPath(File(exists=True)), 'identity', argstr='%s', mandatory=True,
+        desc='transform files: will be applied in reverse order. For '
+             'example, the last specified transform will be applied first.')
     invert_transform_flags = InputMultiPath(traits.Bool())
     default_value = traits.Float(0.0, argstr='--default-value %g', usedefault=True)
     print_out_composite_warp_file = traits.Bool(False, requires=["output_image"],
@@ -269,6 +271,15 @@ class ApplyTransforms(ANTSCommand):
     --------
 
     >>> from nipype.interfaces.ants import ApplyTransforms
+    >>> at = ApplyTransforms()
+    >>> at.inputs.input_image = 'moving1.nii'
+    >>> at.inputs.reference_image = 'fixed1.nii'
+    >>> at.inputs.transforms = 'identity'
+    >>> at.cmdline # doctest: +ALLOW_UNICODE
+    'antsApplyTransforms --default-value 0 --input moving1.nii \
+--interpolation Linear --output moving1_trans.nii \
+--reference-image fixed1.nii -t identity'
+
     >>> at = ApplyTransforms()
     >>> at.inputs.dimension = 3
     >>> at.inputs.input_image = 'moving1.nii'
@@ -338,6 +349,8 @@ def _format_arg(self, opt, spec, val):
         if opt == "output_image":
             return self._get_output_warped_filename()
         elif opt == "transforms":
+            if val == 'identity':
+                return '-t identity'
             return self._get_transform_filenames()
         elif opt == 'interpolation':
             if self.inputs.interpolation in ['BSpline', 'MultiLabel', 'Gaussian'] and \


Test patch: