Skip to content

Commit e4f297d

Browse files
committed
Added EditTransform interface
Now, basic operations (change reference image, and setting interpolator, output pixel type, and/or output image format) are available.
1 parent 92f06a0 commit e4f297d

File tree

5 files changed

+204
-8
lines changed

5 files changed

+204
-8
lines changed

nipype/interfaces/elastix/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
# @Author: oesteban - code@oscaresteban.es
77
# @Date: 2014-06-02 12:06:07
88
# @Last Modified by: oesteban
9-
# @Last Modified time: 2014-06-05 11:55:07
9+
# @Last Modified time: 2014-06-17 10:59:20
1010
"""Top-level namespace for elastix."""
1111

1212
from registration import Registration, ApplyWarp, AnalyzeWarp, PointsWarp
13+
from utils import EditTransform

nipype/interfaces/elastix/base.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
# @Author: oesteban - code@oscaresteban.es
77
# @Date: 2014-06-03 13:42:46
88
# @Last Modified by: oesteban
9-
# @Last Modified time: 2014-06-03 13:43:50
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+
"""
1017

1118
from ..base import (CommandLine, CommandLineInputSpec, isdefined,
1219
TraitedSpec, File, traits, InputMultiPath)

nipype/interfaces/elastix/registration.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
# @Author: oesteban - code@oscaresteban.es
77
# @Date: 2014-06-02 12:06:50
88
# @Last Modified by: oesteban
9-
# @Last Modified time: 2014-06-05 14:41:30
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-
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.
1513
1614
"""
1715

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from nipype.testing import assert_equal
3+
from nipype.interfaces.elastix.utils import EditTransform
4+
5+
def test_EditTransform_inputs():
6+
input_map = dict(ignore_exception=dict(nohash=True,
7+
usedefault=True,
8+
),
9+
interpolation=dict(argstr='FinalBSplineInterpolationOrder',
10+
usedefault=True,
11+
),
12+
output_file=dict(),
13+
output_format=dict(argstr='ResultImageFormat',
14+
),
15+
output_type=dict(argstr='ResultImagePixelType',
16+
),
17+
reference_image=dict(mandatory=False,
18+
),
19+
transform_file=dict(mandatory=True,
20+
),
21+
)
22+
inputs = EditTransform.input_spec()
23+
24+
for key, metadata in input_map.items():
25+
for metakey, value in metadata.items():
26+
yield assert_equal, getattr(inputs.traits()[key], metakey), value
27+
28+
def test_EditTransform_outputs():
29+
output_map = dict(output_file=dict(),
30+
)
31+
outputs = EditTransform.output_spec()
32+
33+
for key, metadata in output_map.items():
34+
for metakey, value in metadata.items():
35+
yield assert_equal, getattr(outputs.traits()[key], metakey), value
36+

nipype/interfaces/elastix/utils.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
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-17 10:17:07
8+
# @Last Modified by: oesteban
9+
# @Last Modified time: 2014-06-17 13:15:54
10+
"""
11+
Generic interfaces to manipulate registration parameters files, including
12+
transform files (to configure warpings)
13+
14+
"""
15+
16+
import os.path as op
17+
import re
18+
19+
from nipype.interfaces.base import (BaseInterface, BaseInterfaceInputSpec, isdefined,
20+
TraitedSpec, File, traits, InputMultiPath)
21+
22+
23+
from nipype import logging
24+
logger = logging.getLogger('interface')
25+
26+
27+
class EditTransformInputSpec(BaseInterfaceInputSpec):
28+
transform_file = File(exists=True, mandatory=True,
29+
desc='transform-parameter file, only 1')
30+
reference_image = File(exists=True, mandatory=False,
31+
desc='set a new reference image to change the target coordinate system.')
32+
interpolation = traits.Enum('cubic','linear','nearest', usedefault=True,
33+
argstr='FinalBSplineInterpolationOrder',
34+
desc='set a new interpolator for transformation')
35+
36+
output_type = traits.Enum('float', 'unsigned char', 'unsigned short','short',
37+
'unsigned long','long','double',
38+
argstr='ResultImagePixelType',
39+
desc='set a new output pixel type for resampled images')
40+
output_format = traits.Enum('nii.gz', 'nii', 'mhd', 'hdr', 'vtk',
41+
argstr='ResultImageFormat',
42+
desc='set a new image format for resampled images')
43+
output_file = File(desc='the filename for the resulting transform file')
44+
45+
class EditTransformOutputSpec(TraitedSpec):
46+
output_file = File(exists=True, desc='output transform file')
47+
48+
49+
class EditTransform(BaseInterface):
50+
"""
51+
Manipulates an existing transform file generated with elastix
52+
53+
Example::
54+
55+
>>> from nipype.interfaces.elastix import EditTransform
56+
>>> tfm = EditTransform()
57+
>>> tfm.inputs.transform_file = 'TransformParameters.0.txt'
58+
>>> tfm.inputs.reference_image = 'fixed1.nii'
59+
>>> tfm.inputs.output_type = 'unsigned char'
60+
>>> tfm.run() # doctest: +SKIP
61+
"""
62+
63+
input_spec = EditTransformInputSpec
64+
output_spec = EditTransformOutputSpec
65+
_out_file = ''
66+
_pattern = '\((?P<entry>%s\s\"?)([-\.\s\w]+)(\"?\))'
67+
68+
_interp = { 'nearest': 0, 'linear': 1, 'cubic': 3 }
69+
70+
def _run_interface(self, runtime):
71+
import re
72+
import nibabel as nb
73+
import numpy as np
74+
75+
contents = ''
76+
77+
with open(self.inputs.transform_file, 'r') as f:
78+
contents = f.read()
79+
80+
if isdefined(self.inputs.output_type):
81+
p = re.compile((self._pattern % 'ResultImagePixelType').decode('string-escape'))
82+
rep = '(\g<entry>%s\g<3>' % self.inputs.output_type
83+
contents = p.sub(rep, contents)
84+
85+
if isdefined(self.inputs.output_format):
86+
p = re.compile((self._pattern % 'ResultImageFormat').decode('string-escape'))
87+
rep = '(\g<entry>%s\g<3>' % self.inputs.output_format
88+
contents = p.sub(rep, contents)
89+
90+
if isdefined(self.inputs.interpolation):
91+
p = re.compile((self._pattern % 'FinalBSplineInterpolationOrder').decode('string-escape'))
92+
rep = '(\g<entry>%s\g<3>' % self._interp[self.inputs.interpolation]
93+
contents = p.sub(rep, contents)
94+
95+
if isdefined(self.inputs.reference_image):
96+
im = nb.load(self.inputs.reference_image)
97+
98+
if len(im.get_header().get_zooms()) == 4:
99+
im = nb.func.four_to_three(im)[0]
100+
101+
size = ' '.join(["%01d" % s for s in im.get_shape() ])
102+
p = re.compile((self._pattern % 'Size').decode('string-escape'))
103+
rep = '(\g<entry>%s\g<3>' % size
104+
contents = p.sub(rep, contents)
105+
106+
index = ' '.join(["0" for s in im.get_shape() ])
107+
p = re.compile((self._pattern % 'Index').decode('string-escape'))
108+
rep = '(\g<entry>%s\g<3>' % index
109+
contents = p.sub(rep, contents)
110+
111+
spacing = ' '.join(["%0.4f" % f for f in im.get_header().get_zooms()])
112+
p = re.compile((self._pattern % 'Spacing').decode('string-escape'))
113+
rep = '(\g<entry>%s\g<3>' % spacing
114+
contents = p.sub(rep, contents)
115+
116+
itkmat = np.eye(4)
117+
itkmat[0,0] = -1
118+
itkmat[1,1] = -1
119+
120+
affine = np.dot( itkmat, im.get_affine() )
121+
dirs = ' '.join(['%0.4f' % f for f in affine[0:3,0:3].reshape(-1)])
122+
orig = ' '.join(['%0.4f' % f for f in affine[0:3,3].reshape(-1)])
123+
124+
p = re.compile((self._pattern % 'Direction').decode('string-escape'))
125+
rep = '(\g<entry>%s\g<3>' % dirs
126+
contents = p.sub(rep, contents)
127+
128+
p = re.compile((self._pattern % 'Origin').decode('string-escape'))
129+
rep = '(\g<entry>%s\g<3>' % orig
130+
contents = p.sub(rep, contents)
131+
132+
133+
with open(self._get_outfile(), 'w') as of:
134+
of.write(contents)
135+
136+
return runtime
137+
138+
def _list_outputs(self):
139+
outputs = self.output_spec().get()
140+
outputs['output_file'] = getattr(self, '_out_file')
141+
return outputs
142+
143+
def _get_outfile(self):
144+
val = getattr(self,'_out_file')
145+
if not val is None and not val=='':
146+
return val
147+
148+
if isdefined(self.inputs.output_file):
149+
setattr(self,'_out_file',self.inputs.output_file)
150+
return self.inputs.output_file
151+
152+
out_file = op.abspath(op.basename(self.inputs.transform_file))
153+
setattr(self, '_out_file', out_file)
154+
return out_file

0 commit comments

Comments
 (0)