Skip to content

Commit 1c84a70

Browse files
authored
Merge pull request #3222 from effigies/restore_ants_legacy
ENH: Restore ants.legacy interfaces
2 parents 4c48a18 + 81e8f9e commit 1c84a70

File tree

4 files changed

+503
-0
lines changed

4 files changed

+503
-0
lines changed

nipype/interfaces/ants/legacy.py

Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
# -*- coding: utf-8 -*-
2+
"""ANTS Legacy Interfaces
3+
4+
These interfaces are for programs that have been deprecated by ANTs, but
5+
are preserved for backwards compatibility.
6+
"""
7+
8+
from builtins import range
9+
10+
import os
11+
from glob import glob
12+
13+
from .base import ANTSCommand, ANTSCommandInputSpec
14+
from ..base import TraitedSpec, File, traits, isdefined, OutputMultiPath
15+
from ...utils.filemanip import split_filename
16+
17+
18+
class antsIntroductionInputSpec(ANTSCommandInputSpec):
19+
dimension = traits.Enum(
20+
3,
21+
2,
22+
argstr="-d %d",
23+
usedefault=True,
24+
desc="image dimension (2 or 3)",
25+
position=1,
26+
)
27+
reference_image = File(
28+
exists=True,
29+
argstr="-r %s",
30+
desc="template file to warp to",
31+
mandatory=True,
32+
copyfile=True,
33+
)
34+
input_image = File(
35+
exists=True,
36+
argstr="-i %s",
37+
desc="input image to warp to template",
38+
mandatory=True,
39+
copyfile=False,
40+
)
41+
force_proceed = traits.Bool(
42+
argstr="-f 1",
43+
desc=("force script to proceed even if headers " "may be incompatible"),
44+
)
45+
inverse_warp_template_labels = traits.Bool(
46+
argstr="-l",
47+
desc=(
48+
"Applies inverse warp to the template labels "
49+
"to estimate label positions in target space (use "
50+
"for template-based segmentation)"
51+
),
52+
)
53+
max_iterations = traits.List(
54+
traits.Int,
55+
argstr="-m %s",
56+
sep="x",
57+
desc=(
58+
"maximum number of iterations (must be "
59+
"list of integers in the form [J,K,L...]: "
60+
"J = coarsest resolution iterations, K = "
61+
"middle resolution interations, L = fine "
62+
"resolution iterations"
63+
),
64+
)
65+
bias_field_correction = traits.Bool(
66+
argstr="-n 1", desc=("Applies bias field correction to moving " "image")
67+
)
68+
similarity_metric = traits.Enum(
69+
"PR",
70+
"CC",
71+
"MI",
72+
"MSQ",
73+
argstr="-s %s",
74+
desc=(
75+
"Type of similartiy metric used for registration "
76+
"(CC = cross correlation, MI = mutual information, "
77+
"PR = probability mapping, MSQ = mean square difference)"
78+
),
79+
)
80+
transformation_model = traits.Enum(
81+
"GR",
82+
"EL",
83+
"SY",
84+
"S2",
85+
"EX",
86+
"DD",
87+
"RI",
88+
"RA",
89+
argstr="-t %s",
90+
usedefault=True,
91+
desc=(
92+
"Type of transofmration model used for registration "
93+
"(EL = elastic transformation model, SY = SyN with time, "
94+
"arbitrary number of time points, S2 = SyN with time "
95+
"optimized for 2 time points, GR = greedy SyN, EX = "
96+
"exponential, DD = diffeomorphic demons style exponential "
97+
"mapping, RI = purely rigid, RA = affine rigid"
98+
),
99+
)
100+
out_prefix = traits.Str(
101+
"ants_",
102+
argstr="-o %s",
103+
usedefault=True,
104+
desc=("Prefix that is prepended to all output " "files (default = ants_)"),
105+
)
106+
quality_check = traits.Bool(
107+
argstr="-q 1", desc="Perform a quality check of the result"
108+
)
109+
110+
111+
class antsIntroductionOutputSpec(TraitedSpec):
112+
affine_transformation = File(exists=True, desc="affine (prefix_Affine.txt)")
113+
warp_field = File(exists=True, desc="warp field (prefix_Warp.nii)")
114+
inverse_warp_field = File(
115+
exists=True, desc="inverse warp field (prefix_InverseWarp.nii)"
116+
)
117+
input_file = File(exists=True, desc="input image (prefix_repaired.nii)")
118+
output_file = File(exists=True, desc="output image (prefix_deformed.nii)")
119+
120+
121+
class antsIntroduction(ANTSCommand):
122+
"""Uses ANTS to generate matrices to warp data from one space to another.
123+
124+
Examples
125+
--------
126+
127+
>>> from nipype.interfaces.ants.legacy import antsIntroduction
128+
>>> warp = antsIntroduction()
129+
>>> warp.inputs.reference_image = 'Template_6.nii'
130+
>>> warp.inputs.input_image = 'structural.nii'
131+
>>> warp.inputs.max_iterations = [30,90,20]
132+
>>> warp.cmdline
133+
'antsIntroduction.sh -d 3 -i structural.nii -m 30x90x20 -o ants_ -r Template_6.nii -t GR'
134+
135+
"""
136+
137+
_cmd = "antsIntroduction.sh"
138+
input_spec = antsIntroductionInputSpec
139+
output_spec = antsIntroductionOutputSpec
140+
141+
def _list_outputs(self):
142+
outputs = self._outputs().get()
143+
transmodel = self.inputs.transformation_model
144+
145+
# When transform is set as 'RI'/'RA', wrap fields should not be expected
146+
# The default transformation is GR, which outputs the wrap fields
147+
if not isdefined(transmodel) or (
148+
isdefined(transmodel) and transmodel not in ["RI", "RA"]
149+
):
150+
outputs["warp_field"] = os.path.join(
151+
os.getcwd(), self.inputs.out_prefix + "Warp.nii.gz"
152+
)
153+
outputs["inverse_warp_field"] = os.path.join(
154+
os.getcwd(), self.inputs.out_prefix + "InverseWarp.nii.gz"
155+
)
156+
157+
outputs["affine_transformation"] = os.path.join(
158+
os.getcwd(), self.inputs.out_prefix + "Affine.txt"
159+
)
160+
outputs["input_file"] = os.path.join(
161+
os.getcwd(), self.inputs.out_prefix + "repaired.nii.gz"
162+
)
163+
outputs["output_file"] = os.path.join(
164+
os.getcwd(), self.inputs.out_prefix + "deformed.nii.gz"
165+
)
166+
167+
return outputs
168+
169+
170+
# How do we make a pass through so that GenWarpFields is just an alias for antsIntroduction ?
171+
172+
173+
class GenWarpFields(antsIntroduction):
174+
pass
175+
176+
177+
class buildtemplateparallelInputSpec(ANTSCommandInputSpec):
178+
dimension = traits.Enum(
179+
3,
180+
2,
181+
4,
182+
argstr="-d %d",
183+
usedefault=True,
184+
desc="image dimension (2, 3 or 4)",
185+
position=1,
186+
)
187+
out_prefix = traits.Str(
188+
"antsTMPL_",
189+
argstr="-o %s",
190+
usedefault=True,
191+
desc=("Prefix that is prepended to all output " "files (default = antsTMPL_)"),
192+
)
193+
in_files = traits.List(
194+
File(exists=True),
195+
mandatory=True,
196+
desc="list of images to generate template from",
197+
argstr="%s",
198+
position=-1,
199+
)
200+
parallelization = traits.Enum(
201+
0,
202+
1,
203+
2,
204+
argstr="-c %d",
205+
usedefault=True,
206+
desc=(
207+
"control for parallel processing (0 = "
208+
"serial, 1 = use PBS, 2 = use PEXEC, 3 = "
209+
"use Apple XGrid"
210+
),
211+
)
212+
gradient_step_size = traits.Float(
213+
argstr="-g %f",
214+
desc=("smaller magnitude results in " "more cautious steps (default = " ".25)"),
215+
)
216+
iteration_limit = traits.Int(
217+
4, argstr="-i %d", usedefault=True, desc="iterations of template construction"
218+
)
219+
num_cores = traits.Int(
220+
argstr="-j %d",
221+
requires=["parallelization"],
222+
desc=(
223+
"Requires parallelization = 2 (PEXEC). " "Sets number of cpu cores to use"
224+
),
225+
)
226+
max_iterations = traits.List(
227+
traits.Int,
228+
argstr="-m %s",
229+
sep="x",
230+
desc=(
231+
"maximum number of iterations (must be "
232+
"list of integers in the form [J,K,L...]: "
233+
"J = coarsest resolution iterations, K = "
234+
"middle resolution interations, L = fine "
235+
"resolution iterations"
236+
),
237+
)
238+
bias_field_correction = traits.Bool(
239+
argstr="-n 1", desc=("Applies bias field correction to moving " "image")
240+
)
241+
rigid_body_registration = traits.Bool(
242+
argstr="-r 1",
243+
desc=(
244+
"registers inputs before creating template "
245+
"(useful if no initial template available)"
246+
),
247+
)
248+
similarity_metric = traits.Enum(
249+
"PR",
250+
"CC",
251+
"MI",
252+
"MSQ",
253+
argstr="-s %s",
254+
desc=(
255+
"Type of similartiy metric used for registration "
256+
"(CC = cross correlation, MI = mutual information, "
257+
"PR = probability mapping, MSQ = mean square difference)"
258+
),
259+
)
260+
transformation_model = traits.Enum(
261+
"GR",
262+
"EL",
263+
"SY",
264+
"S2",
265+
"EX",
266+
"DD",
267+
argstr="-t %s",
268+
usedefault=True,
269+
desc=(
270+
"Type of transofmration model used for registration "
271+
"(EL = elastic transformation model, SY = SyN with time, "
272+
"arbitrary number of time points, S2 = SyN with time "
273+
"optimized for 2 time points, GR = greedy SyN, EX = "
274+
"exponential, DD = diffeomorphic demons style exponential "
275+
"mapping"
276+
),
277+
)
278+
use_first_as_target = traits.Bool(
279+
desc=(
280+
"uses first volume as target of "
281+
"all inputs. When not used, an "
282+
"unbiased average image is used "
283+
"to start."
284+
)
285+
)
286+
287+
288+
class buildtemplateparallelOutputSpec(TraitedSpec):
289+
final_template_file = File(exists=True, desc="final ANTS template")
290+
template_files = OutputMultiPath(
291+
File(exists=True), desc="Templates from different stages of iteration"
292+
)
293+
subject_outfiles = OutputMultiPath(
294+
File(exists=True),
295+
desc=(
296+
"Outputs for each input image. Includes warp "
297+
"field, inverse warp, Affine, original image "
298+
"(repaired) and warped image (deformed)"
299+
),
300+
)
301+
302+
303+
class buildtemplateparallel(ANTSCommand):
304+
"""Generate a optimal average template
305+
306+
.. warning::
307+
308+
This can take a VERY long time to complete
309+
310+
Examples
311+
--------
312+
313+
>>> from nipype.interfaces.ants.legacy import buildtemplateparallel
314+
>>> tmpl = buildtemplateparallel()
315+
>>> tmpl.inputs.in_files = ['T1.nii', 'structural.nii']
316+
>>> tmpl.inputs.max_iterations = [30, 90, 20]
317+
>>> tmpl.cmdline
318+
'buildtemplateparallel.sh -d 3 -i 4 -m 30x90x20 -o antsTMPL_ -c 0 -t GR T1.nii structural.nii'
319+
320+
"""
321+
322+
_cmd = "buildtemplateparallel.sh"
323+
input_spec = buildtemplateparallelInputSpec
324+
output_spec = buildtemplateparallelOutputSpec
325+
326+
def _format_arg(self, opt, spec, val):
327+
if opt == "num_cores":
328+
if self.inputs.parallelization == 2:
329+
return "-j " + str(val)
330+
else:
331+
return ""
332+
if opt == "in_files":
333+
if self.inputs.use_first_as_target:
334+
start = "-z "
335+
else:
336+
start = ""
337+
return start + " ".join(name for name in val)
338+
return super(buildtemplateparallel, self)._format_arg(opt, spec, val)
339+
340+
def _list_outputs(self):
341+
outputs = self._outputs().get()
342+
outputs["template_files"] = []
343+
for i in range(len(glob(os.path.realpath("*iteration*")))):
344+
temp = os.path.realpath(
345+
"%s_iteration_%d/%stemplate.nii.gz"
346+
% (self.inputs.transformation_model, i, self.inputs.out_prefix)
347+
)
348+
os.rename(
349+
temp,
350+
os.path.realpath(
351+
"%s_iteration_%d/%stemplate_i%d.nii.gz"
352+
% (self.inputs.transformation_model, i, self.inputs.out_prefix, i)
353+
),
354+
)
355+
file_ = "%s_iteration_%d/%stemplate_i%d.nii.gz" % (
356+
self.inputs.transformation_model,
357+
i,
358+
self.inputs.out_prefix,
359+
i,
360+
)
361+
362+
outputs["template_files"].append(os.path.realpath(file_))
363+
outputs["final_template_file"] = os.path.realpath(
364+
"%stemplate.nii.gz" % self.inputs.out_prefix
365+
)
366+
outputs["subject_outfiles"] = []
367+
for filename in self.inputs.in_files:
368+
_, base, _ = split_filename(filename)
369+
temp = glob(os.path.realpath("%s%s*" % (self.inputs.out_prefix, base)))
370+
for file_ in temp:
371+
outputs["subject_outfiles"].append(file_)
372+
return outputs

0 commit comments

Comments
 (0)