Skip to content

Commit 414568f

Browse files
committed
Merge branch 'johnsonhj/enh/ExpandedAntsCapabilities' of
https://github.com/nipy/nipype.git into johnsonhj/enh/ExpandedAntsCapabilities Conflicts: examples/smri_ants_build_template_new.py nipype/workflows/smri/ants/antsRegistrationBuildTemplate.py
2 parents 7f70d95 + 4a2385f commit 414568f

File tree

6 files changed

+188
-74
lines changed

6 files changed

+188
-74
lines changed

examples/smri_ants_build_template.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/usr/bin/env python
2+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
"""
5+
===============================================
6+
sMRI: Using new ANTS for creating a T1 template
7+
===============================================
8+
9+
In this tutorial we will use ANTS (old version aka "ANTS") based workflow to
10+
create a template out of multiple T1 volumes.
11+
12+
1. Tell python where to find the appropriate functions.
13+
"""
14+
15+
import os
16+
import nipype.interfaces.utility as util
17+
import nipype.interfaces.ants as ants
18+
import nipype.interfaces.io as io
19+
import nipype.pipeline.engine as pe # pypeline engine
20+
21+
from nipype.workflows.smri.ants import ANTSTemplateBuildSingleIterationWF
22+
23+
"""
24+
2. Download T1 volumes into home directory
25+
"""
26+
27+
import urllib2
28+
homeDir=os.getenv("HOME")
29+
requestedPath=os.path.join(homeDir,'nipypeTestPath')
30+
mydatadir=os.path.realpath(requestedPath)
31+
if not os.path.exists(mydatadir):
32+
os.makedirs(mydatadir)
33+
print mydatadir
34+
35+
MyFileURLs=[
36+
('http://slicer.kitware.com/midas3/download?bitstream=13121','01_T1_half.nii.gz'),
37+
('http://slicer.kitware.com/midas3/download?bitstream=13122','02_T1_half.nii.gz'),
38+
('http://slicer.kitware.com/midas3/download?bitstream=13124','03_T1_half.nii.gz'),
39+
('http://slicer.kitware.com/midas3/download?bitstream=13128','01_T1_inv_half.nii.gz'),
40+
('http://slicer.kitware.com/midas3/download?bitstream=13123','02_T1_inv_half.nii.gz'),
41+
('http://slicer.kitware.com/midas3/download?bitstream=13125','03_T1_inv_half.nii.gz'),
42+
]
43+
for tt in MyFileURLs:
44+
myURL=tt[0]
45+
localFilename=os.path.join(mydatadir,tt[1])
46+
if not os.path.exists(localFilename):
47+
remotefile = urllib2.urlopen(myURL)
48+
49+
localFile = open(localFilename, 'wb')
50+
localFile.write(remotefile.read())
51+
localFile.close()
52+
print("Downloaded file: {0}".format(localFilename))
53+
else:
54+
print("File previously downloaded {0}".format(localFilename))
55+
56+
input_images=[
57+
os.path.join(mydatadir,'01_T1_half.nii.gz'),
58+
os.path.join(mydatadir,'02_T1_half.nii.gz'),
59+
os.path.join(mydatadir,'03_T1_half.nii.gz')
60+
]
61+
input_passive_images=[
62+
{'INV_T1':os.path.join(mydatadir,'01_T1_inv_half.nii.gz')},
63+
{'INV_T1':os.path.join(mydatadir,'02_T1_inv_half.nii.gz')},
64+
{'INV_T1':os.path.join(mydatadir,'03_T1_inv_half.nii.gz')}
65+
]
66+
67+
68+
"""
69+
3. Define the workflow and its working directory
70+
"""
71+
tbuilder=pe.Workflow(name="ANTSTemplateBuilder")
72+
tbuilder.base_dir=requestedPath
73+
74+
"""
75+
4. Define data sources. In real life these would be replace by DataGrabbers
76+
"""
77+
datasource = pe.Node(interface=util.IdentityInterface(fields=
78+
['imageList', 'passiveImagesDictionariesList']),
79+
run_without_submitting=True,
80+
name='InputImages' )
81+
datasource.inputs.imageList=input_images
82+
datasource.inputs.passiveImagesDictionariesList=input_passive_images
83+
84+
"""
85+
5. Template is initialized by a simple average
86+
"""
87+
initAvg = pe.Node(interface=ants.AverageImages(), name ='initAvg')
88+
initAvg.inputs.dimension = 3
89+
initAvg.inputs.normalize = True
90+
91+
tbuilder.connect(datasource, "imageList", initAvg, "images")
92+
93+
"""
94+
6. Define the first iteration of template building
95+
"""
96+
97+
buildTemplateIteration1=ANTSTemplateBuildSingleIterationWF('iteration01')
98+
tbuilder.connect(initAvg, 'output_average_image', buildTemplateIteration1, 'inputspec.fixed_image')
99+
tbuilder.connect(datasource, 'imageList', buildTemplateIteration1, 'inputspec.images')
100+
tbuilder.connect(datasource, 'passiveImagesDictionariesList', buildTemplateIteration1, 'inputspec.ListOfPassiveImagesDictionaries')
101+
102+
"""
103+
7. Define the second iteration of template building
104+
"""
105+
106+
buildTemplateIteration2 = ANTSTemplateBuildSingleIterationWF('iteration02')
107+
tbuilder.connect(buildTemplateIteration1, 'outputspec.template', buildTemplateIteration2, 'inputspec.fixed_image')
108+
tbuilder.connect(datasource, 'imageList', buildTemplateIteration2, 'inputspec.images')
109+
tbuilder.connect(datasource, 'passiveImagesDictionariesList', buildTemplateIteration2, 'inputspec.ListOfPassiveImagesDictionaries')
110+
111+
"""
112+
8. Move selected files to a designated results folder
113+
"""
114+
115+
datasink = pe.Node(io.DataSink(), name="datasink")
116+
datasink.inputs.base_directory = os.path.join(requestedPath, "results")
117+
118+
tbuilder.connect(buildTemplateIteration2, 'outputspec.template',datasink,'PrimaryTemplate')
119+
tbuilder.connect(buildTemplateIteration2, 'outputspec.passive_deformed_templates',datasink,'PassiveTemplate')
120+
tbuilder.connect(initAvg, 'output_average_image', datasink,'PreRegisterAverage')
121+
122+
"""
123+
8. Run the workflow
124+
"""
125+
126+
tbuilder.run()

examples/smri_ants_build_template_new.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
======================================================
88
99
In this tutorial we will use ANTS (new ITK4 version aka "antsRegistration") based workflow to
10-
create a template out of multiple T1 volumes.
10+
create a template out of multiple T1 volumes. We will also showcase how to fine tune SGE jobs requirements.
1111
1212
1. Tell python where to find the appropriate functions.
1313
"""
@@ -64,6 +64,11 @@
6464
{'T1':os.path.join(mydatadir,'02_T1_half.nii.gz'),'INV_T1':os.path.join(mydatadir,'02_T1_inv_half.nii.gz'),'LABEL_MAP':os.path.join(mydatadir,'02_T1_inv_half.nii.gz')},
6565
{'T1':os.path.join(mydatadir,'03_T1_half.nii.gz'),'INV_T1':os.path.join(mydatadir,'03_T1_inv_half.nii.gz'),'LABEL_MAP':os.path.join(mydatadir,'03_T1_inv_half.nii.gz')}
6666
]
67+
input_passive_images=[
68+
{'INV_T1':os.path.join(mydatadir,'01_T1_inv_half.nii.gz')},
69+
{'INV_T1':os.path.join(mydatadir,'02_T1_inv_half.nii.gz')},
70+
{'INV_T1':os.path.join(mydatadir,'03_T1_inv_half.nii.gz')}
71+
]
6772

6873
"""
6974
registrationImageTypes - A list of the image types to be used actively during
@@ -116,15 +121,23 @@
116121
"""
117122

118123
buildTemplateIteration1=antsRegistrationTemplateBuildSingleIterationWF('iteration01')
124+
"""
125+
Here we are fine tuning parameters of the SGE job (memory limit, numebr of cores etc.)
126+
"""
127+
BeginANTS = buildTemplateIteration1.get_node("BeginANTS")
128+
BeginANTS.plugin_args={'qsub_args': '-S /bin/bash -pe smp1 8-12 -l mem_free=6000M -o /dev/null -e /dev/null queue_name', 'overwrite': True}
129+
119130
tbuilder.connect(initAvg, 'output_average_image', buildTemplateIteration1, 'InputSpec.fixed_image')
120131
tbuilder.connect(datasource, 'ListOfImagesDictionaries', buildTemplateIteration1, 'InputSpec.ListOfImagesDictionaries')
121132
tbuilder.connect(datasource, 'registrationImageTypes', buildTemplateIteration1, 'InputSpec.registrationImageTypes')
122133
tbuilder.connect(datasource, 'interpolationMapping', buildTemplateIteration1, 'InputSpec.interpolationMapping')
123-
124134
"""
125135
7. Define the second iteration of template building
126136
"""
137+
127138
buildTemplateIteration2 = antsRegistrationTemplateBuildSingleIterationWF('iteration02')
139+
BeginANTS = buildTemplateIteration2.get_node("BeginANTS")
140+
BeginANTS.plugin_args={'qsub_args': '-S /bin/bash -pe smp1 8-12 -l mem_free=6000M -o /dev/null -e /dev/null queue_name', 'overwrite': True}
128141
tbuilder.connect(buildTemplateIteration1, 'OutputSpec.template', buildTemplateIteration2, 'InputSpec.fixed_image')
129142
tbuilder.connect(datasource, 'ListOfImagesDictionaries', buildTemplateIteration2, 'InputSpec.ListOfImagesDictionaries')
130143
tbuilder.connect(datasource, 'registrationImageTypes', buildTemplateIteration2, 'InputSpec.registrationImageTypes')
@@ -133,15 +146,16 @@
133146
"""
134147
8. Move selected files to a designated results folder
135148
"""
149+
136150
datasink = pe.Node(io.DataSink(), name="datasink")
137151
datasink.inputs.base_directory = os.path.join(requestedPath, "results")
138152

139-
tbuilder.connect(buildTemplateIteration2, 'OutputSpec.template',datasink,'PrimaryTemplate')
140-
tbuilder.connect(buildTemplateIteration2, 'OutputSpec.passive_deformed_templates',datasink,'PassiveTemplate')
153+
tbuilder.connect(buildTemplateIteration2, 'outputspec.template',datasink,'PrimaryTemplate')
154+
tbuilder.connect(buildTemplateIteration2, 'outputspec.passive_deformed_templates',datasink,'PassiveTemplate')
141155
tbuilder.connect(initAvg, 'output_average_image', datasink,'PreRegisterAverage')
142156

143157
"""
144158
8. Run the workflow
145159
"""
146160

147-
tbuilder.run()
161+
tbuilder.run(plugin="SGE")

nipype/interfaces/ants/registration.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,6 @@ class RegistrationInputSpec(ANTSCommandInputSpec):
193193

194194
use_estimate_learning_rate_once = traits.List(traits.Bool(), desc='')
195195
use_histogram_matching = traits.List(traits.Bool(argstr='%s'), default=True, usedefault=True)
196-
# Interpolation flag
197-
interpolation = traits.Enum('Linear',
198-
'NearestNeighbor',
199-
'CosineWindowedSinc',
200-
'WelchWindowedSinc',
201-
'HammingWindowedSinc',
202-
'LanczosWindowedSinc',
203-
# 'MultiLabel',
204-
# 'Gaussian',
205-
# 'BSpline',
206-
argstr='%s', usedefault = True)
207196
# Transform flags
208197
write_composite_transform = traits.Bool(argstr='--write-composite-transform %d', default=False, usedefault=True, desc='')
209198
transforms = traits.List(traits.Enum('Rigid', 'Affine', 'CompositeAffine',
@@ -335,9 +324,6 @@ def _format_arg(self, opt, spec, val):
335324
return '--initial-moving-transform [ %s, 1 ]' % self.inputs.initial_moving_transform
336325
else:
337326
return '--initial-moving-transform [ %s, 0 ]' % self.inputs.initial_moving_transform
338-
elif opt == 'interpolation':
339-
# TODO: handle multilabel, gaussian, and bspline options
340-
return '--interpolation %s' % self.inputs.interpolation
341327
elif opt == 'output_transform_prefix':
342328
if isdefined(self.inputs.output_inverse_warped_image) and self.inputs.output_inverse_warped_image:
343329
return '--output [ %s, %s, %s ]' % (self.inputs.output_transform_prefix, self.inputs.output_warped_image, self.inputs.output_inverse_warped_image )

nipype/workflows/smri/ants/ANTSBuildTemplate.py

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,30 @@ def FlattenTransformAndImagesList(ListOfPassiveImagesDictionaries,transformation
9191
print("HACK: flattened nametypes {0}\n".format(flattened_image_nametypes))
9292
print("HACK: flattened txfms {0}\n".format(flattened_transforms))
9393
return flattened_images,flattened_transforms,flattened_image_nametypes
94-
##
95-
## NOTE: The modes can be either 'SINGLE_IMAGE' or 'MULTI'
96-
## 'SINGLE_IMAGE' is quick shorthand when you are building an atlas with a single subject, then registration can
97-
## be short-circuted
98-
## any other string indicates the normal mode that you would expect and replicates the shell script build_template_parallel.sh
99-
def ANTSTemplateBuildSingleIterationWF(iterationPhasePrefix='',CLUSTER_QUEUE='',mode='MULTI'):
94+
95+
def ANTSTemplateBuildSingleIterationWF(iterationPhasePrefix=''):
96+
"""
97+
98+
Inputs::
99+
100+
inputspec.images :
101+
inputspec.fixed_image :
102+
inputspec.ListOfPassiveImagesDictionaries :
103+
104+
Outputs::
105+
106+
outputspec.template :
107+
outputspec.transforms_list :
108+
outputspec.passive_deformed_templates :
109+
"""
110+
100111

101112
TemplateBuildSingleIterationWF = pe.Workflow(name = 'ANTSTemplateBuildSingleIterationWF_'+str(str(iterationPhasePrefix)) )
102113

103114
inputSpec = pe.Node(interface=util.IdentityInterface(fields=['images', 'fixed_image',
104115
'ListOfPassiveImagesDictionaries']),
105116
run_without_submitting=True,
106-
name='InputSpec')
117+
name='inputspec')
107118
## HACK: TODO: Need to move all local functions to a common untility file, or at the top of the file so that
108119
## they do not change due to re-indenting. Otherwise re-indenting for flow control will trigger
109120
## their hash to change.
@@ -112,40 +123,19 @@ def ANTSTemplateBuildSingleIterationWF(iterationPhasePrefix='',CLUSTER_QUEUE='',
112123
outputSpec = pe.Node(interface=util.IdentityInterface(fields=['template','transforms_list',
113124
'passive_deformed_templates']),
114125
run_without_submitting=True,
115-
name='OutputSpec')
116-
117-
if mode == 'SINGLE_IMAGEXX':
118-
### HACK: A more general utility that is reused should be created.
119-
print "HACK: DOING SINGLE_IMAGE ", mode
120-
TemplateBuildSingleIterationWF.connect( [ (inputSpec, outputSpec, [(('images', GetFirstListElement ), 'template')] ), ])
121-
##HACK THIS DOES NOT WORK BECAUSE FILE NAMES ARE WRONG.
122-
TemplateBuildSingleIterationWF.connect( [ (inputSpec, outputSpec, [(('ListOfPassiveImagesDictionaries', GetFirstListElement ), 'passive_deformed_templates')] ), ])
123-
return TemplateBuildSingleIterationWF
124-
125-
print "HACK: DOING MULTI_IMAGE ", mode
126-
##import sys
127-
##sys.exit(-1)
128-
129-
126+
name='outputspec')
130127

131128
### NOTE MAP NODE! warp each of the original images to the provided fixed_image as the template
132129
BeginANTS=pe.MapNode(interface=ANTS(), name = 'BeginANTS', iterfield=['moving_image'])
133-
many_cpu_BeginANTS_options_dictionary={'qsub_args': '-S /bin/bash -pe smp1 8-12 -l mem_free=6000M -o /dev/null -e /dev/null '+CLUSTER_QUEUE, 'overwrite': True}
134-
BeginANTS.plugin_args=many_cpu_BeginANTS_options_dictionary
135130
BeginANTS.inputs.dimension = 3
136131
BeginANTS.inputs.output_transform_prefix = str(iterationPhasePrefix)+'_tfm'
137132
BeginANTS.inputs.metric = ['CC']
138133
BeginANTS.inputs.metric_weight = [1.0]
139134
BeginANTS.inputs.radius = [5]
140135
BeginANTS.inputs.transformation_model = 'SyN'
141136
BeginANTS.inputs.gradient_step_length = 0.25
142-
if mode == 'SINGLE_IMAGE_IMAGE':
143-
## HACK: Just short circuit time consuming step if only registering a single image.
144-
BeginANTS.inputs.number_of_iterations = [1]
145-
BeginANTS.inputs.number_of_affine_iterations = [1]
146-
else:
147-
BeginANTS.inputs.number_of_iterations = [50, 35, 15]
148-
BeginANTS.inputs.number_of_affine_iterations = [10000,10000,10000,10000,10000]
137+
BeginANTS.inputs.number_of_iterations = [50, 35, 15]
138+
BeginANTS.inputs.number_of_affine_iterations = [10000,10000,10000,10000,10000]
149139
BeginANTS.inputs.use_histogram_matching = True
150140
BeginANTS.inputs.mi_option = [32, 16000]
151141
BeginANTS.inputs.regularization = 'Gauss'

nipype/workflows/smri/ants/antsRegistrationBuildTemplate.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,33 @@ def GetPassiveImages(ListOfImagesDictionaries,registrationImageTypes):
145145
return passive_images
146146

147147
##
148-
def antsRegistrationTemplateBuildSingleIterationWF(iterationPhasePrefix='',CLUSTER_QUEUE=''):
148+
## NOTE: The modes can be either 'SINGLE_IMAGE' or 'MULTI'
149+
## 'SINGLE_IMAGE' is quick shorthand when you are building an atlas with a single subject, then registration can
150+
## be short-circuted
151+
## any other string indicates the normal mode that you would expect and replicates the shell script build_template_parallel.sh
152+
def antsRegistrationTemplateBuildSingleIterationWF(iterationPhasePrefix=''):
153+
"""
154+
155+
Inputs::
156+
157+
inputspec.images :
158+
inputspec.fixed_image :
159+
inputspec.ListOfPassiveImagesDictionaries :
160+
inputspec.interpolationMapping :
149161
162+
Outputs::
163+
164+
outputspec.template :
165+
outputspec.transforms_list :
166+
outputspec.passive_deformed_templates :
167+
"""
150168
TemplateBuildSingleIterationWF = pe.Workflow(name = 'antsRegistrationTemplateBuildSingleIterationWF_'+str(iterationPhasePrefix) )
151169

152170
inputSpec = pe.Node(interface=util.IdentityInterface(fields=[
153171
'ListOfImagesDictionaries', 'registrationImageTypes',
154172
'interpolationMapping','fixed_image']),
155173
run_without_submitting=True,
156-
name='InputSpec')
174+
name='inputspec')
157175
## HACK: TODO: Need to move all local functions to a common untility file, or at the top of the file so that
158176
## they do not change due to re-indenting. Otherwise re-indenting for flow control will trigger
159177
## their hash to change.
@@ -162,12 +180,11 @@ def antsRegistrationTemplateBuildSingleIterationWF(iterationPhasePrefix='',CLUST
162180
outputSpec = pe.Node(interface=util.IdentityInterface(fields=['template','transforms_list',
163181
'passive_deformed_templates']),
164182
run_without_submitting=True,
165-
name='OutputSpec')
183+
name='outputspec')
184+
166185

167186
### NOTE MAP NODE! warp each of the original images to the provided fixed_image as the template
168187
BeginANTS=pe.MapNode(interface=Registration(), name = 'BeginANTS', iterfield=['moving_image'])
169-
many_cpu_BeginANTS_options_dictionary={'qsub_args': '-S /bin/bash -pe smp1 8-12 -l mem_free=6000M -o /dev/null -e /dev/null '+CLUSTER_QUEUE, 'overwrite': True}
170-
BeginANTS.plugin_args=many_cpu_BeginANTS_options_dictionary
171188
BeginANTS.inputs.dimension = 3
172189
BeginANTS.inputs.output_transform_prefix = str(iterationPhasePrefix)+'_tfm'
173190
BeginANTS.inputs.transforms = ["Affine", "SyN"]

nipype/workflows/smri/ants/antsSimpleAverageWF.py

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)