Skip to content

Commit 0af4d56

Browse files
authored
Merge pull request #2187 from Gilles86/ants_compose_multitransform
[ENH] Support for multiple initial-moving-transforms for ants.Registration and ComposeMultiTransforms
2 parents 46f0b74 + 1045d2a commit 0af4d56

File tree

6 files changed

+356
-109
lines changed

6 files changed

+356
-109
lines changed

nipype/interfaces/ants/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@
2020

2121
# Utility Programs
2222
from .utils import (AverageAffineTransform, AverageImages, MultiplyImages,
23-
CreateJacobianDeterminantImage, AffineInitializer)
23+
CreateJacobianDeterminantImage, AffineInitializer,
24+
ComposeMultiTransform)

nipype/interfaces/ants/registration.py

Lines changed: 239 additions & 90 deletions
Large diffs are not rendered by default.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from __future__ import unicode_literals
3+
from ..utils import ComposeMultiTransform
4+
5+
6+
def test_ComposeMultiTransform_inputs():
7+
input_map = dict(args=dict(argstr='%s',
8+
),
9+
dimension=dict(argstr='%d',
10+
position=0,
11+
usedefault=True,
12+
),
13+
environ=dict(nohash=True,
14+
usedefault=True,
15+
),
16+
ignore_exception=dict(nohash=True,
17+
usedefault=True,
18+
),
19+
num_threads=dict(nohash=True,
20+
usedefault=True,
21+
),
22+
output_transform=dict(argstr='%s',
23+
keep_ext=True,
24+
name_source=['transforms'],
25+
name_template='%s_composed',
26+
position=1,
27+
),
28+
reference_image=dict(argstr='%s',
29+
position=2,
30+
),
31+
terminal_output=dict(deprecated='1.0.0',
32+
nohash=True,
33+
),
34+
transforms=dict(argstr='%s',
35+
mandatory=True,
36+
position=3,
37+
),
38+
)
39+
inputs = ComposeMultiTransform.input_spec()
40+
41+
for key, metadata in list(input_map.items()):
42+
for metakey, value in list(metadata.items()):
43+
assert getattr(inputs.traits()[key], metakey) == value
44+
45+
46+
def test_ComposeMultiTransform_outputs():
47+
output_map = dict(output_transform=dict(),
48+
)
49+
outputs = ComposeMultiTransform.output_spec()
50+
51+
for key, metadata in list(output_map.items()):
52+
for metakey, value in list(metadata.items()):
53+
assert getattr(outputs.traits()[key], metakey) == value

nipype/interfaces/ants/tests/test_auto_Registration.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def test_Registration_inputs():
3636
usedefault=True,
3737
),
3838
initial_moving_transform=dict(argstr='%s',
39+
exists=True,
3940
xor=['initial_moving_transform_com'],
4041
),
4142
initial_moving_transform_com=dict(argstr='%s',

nipype/interfaces/ants/utils.py

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111

1212
import os
1313

14-
from ...utils.filemanip import split_filename
15-
from ..base import (TraitedSpec, File, traits, isdefined, InputMultiPath,
16-
CommandLine, CommandLineInputSpec)
14+
from ..base import TraitedSpec, File, traits, InputMultiPath
1715
from .base import ANTSCommand, ANTSCommandInputSpec
1816

1917

@@ -59,12 +57,16 @@ def _list_outputs(self):
5957
class AverageImagesInputSpec(ANTSCommandInputSpec):
6058
dimension = traits.Enum(3, 2, argstr='%d', mandatory=True,
6159
position=0, desc='image dimension (2 or 3)')
62-
output_average_image = File("average.nii", argstr='%s', position=1, desc='the name of the resulting image.',
63-
usedefault=True, hash_files=False)
64-
normalize = traits.Bool(argstr="%d", mandatory=True, position=2, desc='Normalize: if true, the 2nd image' +
65-
'is divided by its mean. This will select the largest image to average into.')
66-
images = InputMultiPath(File(exists=True), argstr='%s', mandatory=True, position=3,
67-
desc='image to apply transformation to (generally a coregistered functional)')
60+
output_average_image = File(
61+
"average.nii", argstr='%s', position=1, usedefault=True, hash_files=False,
62+
desc='the name of the resulting image.')
63+
normalize = traits.Bool(
64+
argstr="%d", mandatory=True, position=2,
65+
desc='Normalize: if true, the 2nd image is divided by its mean. '
66+
'This will select the largest image to average into.')
67+
images = InputMultiPath(
68+
File(exists=True), argstr='%s', mandatory=True, position=3,
69+
desc='image to apply transformation to (generally a coregistered functional)')
6870

6971

7072
class AverageImagesOutputSpec(TraitedSpec):
@@ -101,9 +103,11 @@ def _list_outputs(self):
101103
class MultiplyImagesInputSpec(ANTSCommandInputSpec):
102104
dimension = traits.Enum(3, 2, argstr='%d', usedefault=False, mandatory=True, position=0,
103105
desc='image dimension (2 or 3)')
104-
first_input = File(argstr='%s', exists=True, mandatory=True, position=1, desc='image 1')
105-
second_input = traits.Either(File(exists=True), traits.Float, argstr='%s', mandatory=True, position=2,
106-
desc='image 2 or multiplication weight')
106+
first_input = File(argstr='%s', exists=True,
107+
mandatory=True, position=1, desc='image 1')
108+
second_input = traits.Either(
109+
File(exists=True), traits.Float, argstr='%s', mandatory=True, position=2,
110+
desc='image 2 or multiplication weight')
107111
output_product_image = File(argstr='%s', mandatory=True, position=3,
108112
desc='Outputfname.nii.gz: the name of the resulting image.')
109113

@@ -138,22 +142,25 @@ def _list_outputs(self):
138142
self.inputs.output_product_image)
139143
return outputs
140144

145+
141146
class CreateJacobianDeterminantImageInputSpec(ANTSCommandInputSpec):
142147
imageDimension = traits.Enum(3, 2, argstr='%d', usedefault=False, mandatory=True,
143-
position=0, desc='image dimension (2 or 3)')
148+
position=0, desc='image dimension (2 or 3)')
144149
deformationField = File(argstr='%s', exists=True, mandatory=True,
145-
position=1, desc='deformation transformation file')
150+
position=1, desc='deformation transformation file')
146151
outputImage = File(argstr='%s', mandatory=True,
147-
position=2,
148-
desc='output filename')
152+
position=2,
153+
desc='output filename')
149154
doLogJacobian = traits.Enum(0, 1, argstr='%d', position=3,
150-
desc='return the log jacobian')
155+
desc='return the log jacobian')
151156
useGeometric = traits.Enum(0, 1, argstr='%d', position=4,
152-
desc='return the geometric jacobian')
157+
desc='return the geometric jacobian')
158+
153159

154160
class CreateJacobianDeterminantImageOutputSpec(TraitedSpec):
155161
jacobian_image = File(exists=True, desc='jacobian image')
156162

163+
157164
class CreateJacobianDeterminantImage(ANTSCommand):
158165
"""
159166
Examples
@@ -203,6 +210,7 @@ class AffineInitializerInputSpec(ANTSCommandInputSpec):
203210
desc=' determines if a local optimization is run at each search point for the set '
204211
'number of iterations')
205212

213+
206214
class AffineInitializerOutputSpec(TraitedSpec):
207215
out_file = File(desc='output transform file')
208216

@@ -225,3 +233,38 @@ class AffineInitializer(ANTSCommand):
225233

226234
def _list_outputs(self):
227235
return {'out_file': os.path.abspath(self.inputs.out_file)}
236+
237+
238+
class ComposeMultiTransformInputSpec(ANTSCommandInputSpec):
239+
dimension = traits.Enum(3, 2, argstr='%d', usedefault=True, position=0,
240+
desc='image dimension (2 or 3)')
241+
output_transform = File(argstr='%s', position=1, name_source=['transforms'],
242+
name_template='%s_composed', keep_ext=True,
243+
desc='the name of the resulting transform.')
244+
reference_image = File(argstr='%s', position=2,
245+
desc='Reference image (only necessary when output is warpfield)')
246+
transforms = InputMultiPath(File(exists=True), argstr='%s', mandatory=True,
247+
position=3, desc='transforms to average')
248+
249+
250+
class ComposeMultiTransformOutputSpec(TraitedSpec):
251+
output_transform = File(exists=True, desc='Composed transform file')
252+
253+
254+
class ComposeMultiTransform(ANTSCommand):
255+
"""
256+
Take a set of transformations and convert them to a single transformation matrix/warpfield.
257+
258+
Examples
259+
--------
260+
>>> from nipype.interfaces.ants import ComposeMultiTransform
261+
>>> compose_transform = ComposeMultiTransform()
262+
>>> compose_transform.inputs.dimension = 3
263+
>>> compose_transform.inputs.transforms = ['struct_to_template.mat', 'func_to_struct.mat']
264+
>>> compose_transform.cmdline # doctest: +ALLOW_UNICODE
265+
'ComposeMultiTransform 3 struct_to_template_composed struct_to_template.mat func_to_struct.mat'
266+
267+
"""
268+
_cmd = 'ComposeMultiTransform'
269+
input_spec = ComposeMultiTransformInputSpec
270+
output_spec = ComposeMultiTransformOutputSpec

nipype/testing/data/struct_to_template.mat

Whitespace-only changes.

0 commit comments

Comments
 (0)