Skip to content

Commit 18d65f7

Browse files
committed
Merge remote-tracking branch 'origin/pr/849'
Conflicts: CHANGES
2 parents 05f0306 + bf0c39a commit 18d65f7

14 files changed

+662
-1
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ before_install:
1212
- sudo rm -rf /dev/shm
1313
- sudo ln -s /run/shm /dev/shm
1414
- bash <(wget -q -O- http://neuro.debian.net/_files/neurodebian-travis.sh)
15-
- travis_retry sudo apt-get install -qq --no-install-recommends fsl afni
15+
- travis_retry sudo apt-get install -qq --no-install-recommends fsl afni elastix
1616
- travis_retry sudo apt-get install -qq fsl-atlases
1717
- source /etc/fsl/fsl.sh
1818

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Next Release
66
``from nipype.interfaces import fsl``).
77
* ENH: New FSL interface: ProbTrackX2
88
* ENH: New misc algorithm: NormalizeProbabilityMapSet
9+
* ENH: Support for elastix via a set of new interfaces: Registration, ApplyWarp,
10+
AnalyzeWarp, PointsWarp, and EditTransform
911
* ENH: New ANTs interface: ApplyTransformsToPoints
1012
* ENH: New metrics group in algorithms. Now Distance, Overlap, and FuzzyOverlap
1113
are found in nipype.algorithms.metrics instead of misc

nipype/interfaces/elastix/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
4+
# vi: set ft=python sts=4 ts=4 sw=4 et:
5+
#
6+
# @Author: oesteban - code@oscaresteban.es
7+
# @Date: 2014-06-02 12:06:07
8+
# @Last Modified by: oesteban
9+
# @Last Modified time: 2014-06-17 10:59:20
10+
"""Top-level namespace for elastix."""
11+
12+
from registration import Registration, ApplyWarp, AnalyzeWarp, PointsWarp
13+
from utils import EditTransform

nipype/interfaces/elastix/base.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
4+
# vi: set ft=python sts=4 ts=4 sw=4 et:
5+
#
6+
# @Author: oesteban - code@oscaresteban.es
7+
# @Date: 2014-06-03 13:42:46
8+
# @Last Modified by: oesteban
9+
# @Last Modified time: 2014-06-17 10:17:43
10+
"""The :py:mod:`nipype.interfaces.elastix` provides the interface to
11+
the elastix registration software.
12+
13+
.. note:: http://elastix.isi.uu.nl/
14+
15+
16+
"""
17+
18+
from ..base import (CommandLine, CommandLineInputSpec, isdefined,
19+
TraitedSpec, File, traits, InputMultiPath)
20+
from ... import logging
21+
logger = logging.getLogger('interface')
22+
23+
24+
class ElastixBaseInputSpec(CommandLineInputSpec):
25+
output_path = traits.Directory('./', exists=True, mandatory=True, usedefault=True,
26+
argstr='-out %s', desc='output directory')
27+
num_threads = traits.Int(1, argstr='-threads %01d',
28+
desc='set the maximum number of threads of elastix')
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
4+
# vi: set ft=python sts=4 ts=4 sw=4 et:
5+
#
6+
# @Author: oesteban - code@oscaresteban.es
7+
# @Date: 2014-06-02 12:06:50
8+
# @Last Modified by: oesteban
9+
# @Last Modified time: 2014-06-17 10:19:23
10+
"""
11+
Interfaces to perform image registrations and to apply the resulting
12+
displacement maps to images and points.
13+
14+
"""
15+
16+
import os.path as op
17+
import re
18+
19+
from ..base import (CommandLine, CommandLineInputSpec, isdefined,
20+
TraitedSpec, File, traits, InputMultiPath)
21+
22+
23+
from base import ElastixBaseInputSpec
24+
25+
from ... import logging
26+
logger = logging.getLogger('interface')
27+
28+
29+
class RegistrationInputSpec(ElastixBaseInputSpec):
30+
fixed_image = File(exists=True, mandatory=True, argstr='-f %s',
31+
desc='fixed image')
32+
moving_image = File(exists=True, mandatory=True, argstr='-m %s',
33+
desc='moving image')
34+
35+
parameters = InputMultiPath(File(exists=True), mandatory=True, argstr='-p %s...',
36+
desc='parameter file, elastix handles 1 or more -p')
37+
38+
fixed_mask = File(exists=True, argstr='-fMask %s', desc='mask for fixed image')
39+
moving_mask = File(exists=True, argstr='-mMask %s', desc='mask for moving image')
40+
initial_transform = File(exists=True, argstr='-t0 %s',
41+
desc='parameter file for initial transform')
42+
43+
44+
class RegistrationOutputSpec(TraitedSpec):
45+
transform = InputMultiPath(File(exists=True), desc='output transform')
46+
warped_file = File(desc='input moving image warped to fixed image')
47+
warped_files = InputMultiPath(File(exists=False),
48+
desc=('input moving image warped to fixed image at each level'))
49+
warped_files_flags = traits.List(traits.Bool(False),
50+
desc='flag indicating if warped image was generated')
51+
52+
53+
class Registration(CommandLine):
54+
"""Elastix nonlinear registration interface
55+
56+
Example
57+
-------
58+
59+
>>> from nipype.interfaces.elastix import Registration
60+
>>> reg = Registration()
61+
>>> reg.inputs.fixed_image = 'fixed1.nii'
62+
>>> reg.inputs.moving_image = 'moving1.nii'
63+
>>> reg.inputs.parameters = ['elastix.txt']
64+
>>> reg.cmdline
65+
'elastix -f fixed1.nii -m moving1.nii -out ./ -p elastix.txt'
66+
"""
67+
68+
_cmd = 'elastix'
69+
input_spec = RegistrationInputSpec
70+
output_spec = RegistrationOutputSpec
71+
72+
def _list_outputs(self):
73+
outputs = self._outputs().get()
74+
75+
out_dir = op.abspath(self.inputs.output_path)
76+
77+
opts = [ 'WriteResultImage', 'ResultImageFormat' ]
78+
regex = re.compile(r'^\((\w+)\s(.+)\)$')
79+
80+
outputs['transform'] = []
81+
outputs['warped_files'] = []
82+
outputs['warped_files_flags'] = []
83+
84+
for i,params in enumerate(self.inputs.parameters):
85+
config = {}
86+
87+
with open(params, 'r') as f:
88+
for line in f.readlines():
89+
line = line.strip()
90+
if not line.startswith('//') and line:
91+
m = regex.search(line)
92+
if m:
93+
value = self._cast(m.group(2).strip())
94+
config[m.group(1).strip()] = value
95+
96+
outputs['transform'].append(op.join(out_dir,
97+
'TransformParameters.%01d.txt' % i ))
98+
99+
warped_file = None
100+
if config['WriteResultImage']:
101+
warped_file = op.join(out_dir,
102+
'result.%01d.%s' %(i,config['ResultImageFormat']))
103+
104+
outputs['warped_files'].append(warped_file)
105+
outputs['warped_files_flags'].append(config['WriteResultImage'])
106+
107+
if outputs['warped_files_flags'][-1]:
108+
outputs['warped_file'] = outputs['warped_files'][-1]
109+
110+
return outputs
111+
112+
113+
def _cast(self,val):
114+
if val.startswith('"') and val.endswith('"'):
115+
if val == '"true"':
116+
return True
117+
elif val == '"false"':
118+
return False
119+
else:
120+
return val[1:-1]
121+
122+
try:
123+
return int(val)
124+
except ValueError:
125+
try:
126+
return float(val)
127+
except ValueError:
128+
return val
129+
130+
class ApplyWarpInputSpec(ElastixBaseInputSpec):
131+
transform_file = File(exists=True, mandatory=True, argstr='-tp %s',
132+
desc='transform-parameter file, only 1')
133+
134+
moving_image = File(exists=True, argstr='-in %s', mandatory=True,
135+
desc='input image to deform')
136+
137+
138+
139+
class ApplyWarpOutputSpec(TraitedSpec):
140+
warped_file = File(desc='input moving image warped to fixed image')
141+
142+
class ApplyWarp(CommandLine):
143+
"""Use `transformix` to apply a transform on an input image.
144+
The transform is specified in the transform-parameter file.
145+
146+
Example::
147+
148+
>>> from nipype.interfaces.elastix import ApplyWarp
149+
>>> reg = ApplyWarp()
150+
>>> reg.inputs.moving_image = 'moving1.nii'
151+
>>> reg.inputs.transform_file = 'TransformParameters.0.txt'
152+
>>> reg.cmdline
153+
'transformix -in moving1.nii -out ./ -tp TransformParameters.0.txt'
154+
"""
155+
156+
_cmd = 'transformix'
157+
input_spec = ApplyWarpInputSpec
158+
output_spec = ApplyWarpOutputSpec
159+
160+
def _list_outputs(self):
161+
outputs = self._outputs().get()
162+
out_dir = op.abspath(self.inputs.output_path)
163+
outputs['warped_file'] = op.join(out_dir,'result.nii.gz')
164+
return outputs
165+
166+
167+
class AnalyzeWarpInputSpec(ElastixBaseInputSpec):
168+
transform_file = File(exists=True, mandatory=True, argstr='-tp %s',
169+
desc='transform-parameter file, only 1')
170+
171+
172+
class AnalyzeWarpOutputSpec(TraitedSpec):
173+
disp_field = File(exists=True, desc='displacements field')
174+
jacdet_map = File(exists=True, desc='det(Jacobian) map')
175+
jacmat_map = File(exists=True, desc='Jacobian matrix map')
176+
177+
class AnalyzeWarp(CommandLine):
178+
"""Use `transformix` to get details from the input transform (generate
179+
the corresponding deformation field, generate the determinant of the
180+
Jacobian map or the Jacobian map itself)
181+
182+
Example::
183+
184+
>>> from nipype.interfaces.elastix import AnalyzeWarp
185+
>>> reg = AnalyzeWarp()
186+
>>> reg.inputs.transform_file = 'TransformParameters.0.txt'
187+
>>> reg.cmdline
188+
'transformix -def all -jac all -jacmat all -out ./ -tp TransformParameters.0.txt'
189+
"""
190+
191+
_cmd = 'transformix -def all -jac all -jacmat all'
192+
input_spec = AnalyzeWarpInputSpec
193+
output_spec = AnalyzeWarpOutputSpec
194+
195+
def _list_outputs(self):
196+
outputs = self._outputs().get()
197+
out_dir = op.abspath(self.inputs.output_path)
198+
outputs['disp_field'] = op.join(out_dir,'deformationField.nii.gz')
199+
outputs['jacdet_map'] = op.join(out_dir,'spatialJacobian.nii.gz')
200+
outputs['jacmat_map'] = op.join(out_dir,'fullSpatialJacobian.nii.gz')
201+
return outputs
202+
203+
204+
class PointsWarpInputSpec(ElastixBaseInputSpec):
205+
points_file = File(exists=True, argstr='-def %s', mandatory=True,
206+
desc='input points (accepts .vtk triangular meshes).')
207+
transform_file = File(exists=True, mandatory=True, argstr='-tp %s',
208+
desc='transform-parameter file, only 1')
209+
210+
211+
212+
class PointsWarpOutputSpec(TraitedSpec):
213+
warped_file = File(desc='input points displaced in fixed image domain')
214+
215+
class PointsWarp(CommandLine):
216+
"""Use `transformix` to apply a transform on an input point set.
217+
The transform is specified in the transform-parameter file.
218+
219+
Example::
220+
221+
>>> from nipype.interfaces.elastix import PointsWarp
222+
>>> reg = PointsWarp()
223+
>>> reg.inputs.points_file = 'surf1.vtk'
224+
>>> reg.inputs.transform_file = 'TransformParameters.0.txt'
225+
>>> reg.cmdline
226+
'transformix -out ./ -def surf1.vtk -tp TransformParameters.0.txt'
227+
"""
228+
229+
_cmd = 'transformix'
230+
input_spec = PointsWarpInputSpec
231+
output_spec = PointsWarpOutputSpec
232+
233+
def _list_outputs(self):
234+
outputs = self._outputs().get()
235+
out_dir = op.abspath(self.inputs.output_path)
236+
237+
fname, ext = op.splitext(op.basename(self.inputs.points_file))
238+
239+
outputs['warped_file'] = op.join(out_dir,'outputpoints%s' % ext)
240+
return outputs
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from nipype.testing import assert_equal
3+
from nipype.interfaces.elastix.registration import AnalyzeWarp
4+
5+
def test_AnalyzeWarp_inputs():
6+
input_map = dict(args=dict(argstr='%s',
7+
),
8+
environ=dict(nohash=True,
9+
usedefault=True,
10+
),
11+
ignore_exception=dict(nohash=True,
12+
usedefault=True,
13+
),
14+
num_threads=dict(argstr='-threads %01d',
15+
),
16+
output_path=dict(argstr='-out %s',
17+
mandatory=True,
18+
usedefault=True,
19+
),
20+
terminal_output=dict(mandatory=True,
21+
nohash=True,
22+
),
23+
transform_file=dict(argstr='-tp %s',
24+
mandatory=True,
25+
),
26+
)
27+
inputs = AnalyzeWarp.input_spec()
28+
29+
for key, metadata in input_map.items():
30+
for metakey, value in metadata.items():
31+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
32+
33+
def test_AnalyzeWarp_outputs():
34+
output_map = dict(disp_field=dict(),
35+
jacdet_map=dict(),
36+
jacmat_map=dict(),
37+
)
38+
outputs = AnalyzeWarp.output_spec()
39+
40+
for key, metadata in output_map.items():
41+
for metakey, value in metadata.items():
42+
yield assert_equal, getattr(outputs.traits()[key], metakey), value
43+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from nipype.testing import assert_equal
3+
from nipype.interfaces.elastix.registration import ApplyWarp
4+
5+
def test_ApplyWarp_inputs():
6+
input_map = dict(args=dict(argstr='%s',
7+
),
8+
environ=dict(nohash=True,
9+
usedefault=True,
10+
),
11+
ignore_exception=dict(nohash=True,
12+
usedefault=True,
13+
),
14+
moving_image=dict(argstr='-in %s',
15+
mandatory=True,
16+
),
17+
num_threads=dict(argstr='-threads %01d',
18+
),
19+
output_path=dict(argstr='-out %s',
20+
mandatory=True,
21+
usedefault=True,
22+
),
23+
terminal_output=dict(mandatory=True,
24+
nohash=True,
25+
),
26+
transform_file=dict(argstr='-tp %s',
27+
mandatory=True,
28+
),
29+
)
30+
inputs = ApplyWarp.input_spec()
31+
32+
for key, metadata in input_map.items():
33+
for metakey, value in metadata.items():
34+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
35+
36+
def test_ApplyWarp_outputs():
37+
output_map = dict(warped_file=dict(),
38+
)
39+
outputs = ApplyWarp.output_spec()
40+
41+
for key, metadata in output_map.items():
42+
for metakey, value in metadata.items():
43+
yield assert_equal, getattr(outputs.traits()[key], metakey), value
44+

0 commit comments

Comments
 (0)