Skip to content

Commit f7df203

Browse files
committed
Merge branch 'johnsonhj/enh/ExpandedAntsCapabilities'
2 parents e265bfa + 9c5f82a commit f7df203

25 files changed

+2008
-453
lines changed

CHANGES

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
Next release
22
============
33

4-
*ENH: New interfaces: ICC, Meshfix
4+
*ENH: New interfaces: ICC, Meshfix, ants.Register
5+
*ENH: New workflows: ants template building (both using 'ANTS' and the new 'antsRegistration')
6+
*ENH: New examples: how to use ANTS template building workflows (smri_ants_build_tmeplate),
7+
how to set SGE specific options (smri_ants_build_template_new)
58
*ENH: added no_flatten option to Merge
69

710
*FIX: fixed dynamic traits bug

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_registration.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
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 ANTS for registration
7+
==================================
8+
9+
In this simple tutorial we will use the Registration interface from ANTS to
10+
coregister two T1 volumes.
11+
12+
1. Tell python where to find the appropriate functions.
13+
"""
14+
15+
import os
16+
import urllib2
17+
from nipype.interfaces.ants import Registration
18+
19+
"""
20+
2. Download T1 volumes into home directory
21+
"""
22+
23+
homeDir=os.getenv("HOME")
24+
requestedPath=os.path.join(homeDir,'nipypeTestPath')
25+
mydatadir=os.path.realpath(requestedPath)
26+
if not os.path.exists(mydatadir):
27+
os.makedirs(mydatadir)
28+
print mydatadir
29+
30+
MyFileURLs=[
31+
('http://slicer.kitware.com/midas3/download?bitstream=13121','01_T1_half.nii.gz'),
32+
('http://slicer.kitware.com/midas3/download?bitstream=13122','02_T1_half.nii.gz'),
33+
]
34+
for tt in MyFileURLs:
35+
myURL=tt[0]
36+
localFilename=os.path.join(mydatadir,tt[1])
37+
if not os.path.exists(localFilename):
38+
remotefile = urllib2.urlopen(myURL)
39+
40+
localFile = open(localFilename, 'wb')
41+
localFile.write(remotefile.read())
42+
localFile.close()
43+
print("Downloaded file: {0}".format(localFilename))
44+
else:
45+
print("File previously downloaded {0}".format(localFilename))
46+
47+
input_images=[
48+
os.path.join(mydatadir,'01_T1_half.nii.gz'),
49+
os.path.join(mydatadir,'02_T1_half.nii.gz'),
50+
]
51+
52+
"""
53+
3. Define the parameters of the registration
54+
"""
55+
56+
reg = Registration()
57+
reg.inputs.fixed_image = [input_images[0], input_images[0] ]
58+
reg.inputs.moving_image = [input_images[1], input_images[1] ]
59+
reg.inputs.transforms = ['Affine', 'SyN']
60+
reg.inputs.transform_parameters = [(2.0,), (0.25, 3.0, 0.0)]
61+
reg.inputs.number_of_iterations = [[1500, 200], [100, 50, 30]]
62+
reg.inputs.dimension = 3
63+
reg.inputs.write_composite_transform = True
64+
reg.inputs.metric = ['Mattes']*2
65+
reg.inputs.metric_weight = [1]*2 # Default (value ignored currently by ANTs)
66+
reg.inputs.radius_or_number_of_bins = [32]*2
67+
reg.inputs.sampling_strategy = ['Random', None]
68+
reg.inputs.sampling_percentage = [0.05, None]
69+
reg.inputs.convergence_threshold = [1.e-8, 1.e-9]
70+
reg.inputs.convergence_window_size = [20]*2
71+
reg.inputs.smoothing_sigmas = [[1,0], [2,1,0]]
72+
reg.inputs.shrink_factors = [[2,1], [3,2,1]]
73+
reg.inputs.use_estimate_learning_rate_once = [True, True]
74+
reg.inputs.use_histogram_matching = [True, True] # This is the default
75+
reg.inputs.output_transform_prefix = 'thisTransform'
76+
reg.inputs.output_warped_image = 'INTERNAL_WARPED.nii.gz'
77+
reg.cmdline
78+
79+
80+
"""
81+
3. Run the registration
82+
"""
83+
84+
reg.run()
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
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 (ITK4)
7+
======================================================
8+
9+
In this tutorial we will use ANTS (new ITK4 version aka "antsRegistration") based workflow to
10+
create a template out of multiple T1 volumes. We will also showcase how to fine tune SGE jobs requirements.
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 antsRegistrationTemplateBuildSingleIterationWF
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+
57+
"""
58+
ListOfImagesDictionaries - a list of dictionaries where each dictionary is
59+
for one scan session, and the mappings in the dictionary are for all the
60+
co-aligned images for that one scan session
61+
"""
62+
ListOfImagesDictionaries=[
63+
{'T1':os.path.join(mydatadir,'01_T1_half.nii.gz'),'INV_T1':os.path.join(mydatadir,'01_T1_inv_half.nii.gz'),'LABEL_MAP':os.path.join(mydatadir,'01_T1_inv_half.nii.gz')},
64+
{'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')},
65+
{'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')}
66+
]
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+
]
72+
73+
"""
74+
registrationImageTypes - A list of the image types to be used actively during
75+
the estimation process of registration, any image type not in this list
76+
will be passively resampled with the estimated transforms.
77+
['T1','T2']
78+
"""
79+
registrationImageTypes=['T1']
80+
81+
"""
82+
interpolationMap - A map of image types to interpolation modes. If an
83+
image type is not listed, it will be linearly interpolated.
84+
{ 'labelmap':'NearestNeighbor', 'FLAIR':'WindowedSinc' }
85+
"""
86+
interpolationMapping={'INV_T1':'LanczosWindowedSinc','LABEL_MAP':'NearestNeighbor','T1':'Linear'}
87+
88+
"""
89+
3. Define the workflow and its working directory
90+
"""
91+
tbuilder=pe.Workflow(name="antsRegistrationTemplateBuilder")
92+
tbuilder.base_dir=requestedPath
93+
94+
"""
95+
4. Define data sources. In real life these would be replace by DataGrabbers
96+
"""
97+
InitialTemplateInputs=[ mdict['T1'] for mdict in ListOfImagesDictionaries ]
98+
99+
datasource = pe.Node(interface=util.IdentityInterface(fields=
100+
['InitialTemplateInputs', 'ListOfImagesDictionaries',
101+
'registrationImageTypes','interpolationMapping']),
102+
run_without_submitting=True,
103+
name='InputImages' )
104+
datasource.inputs.InitialTemplateInputs=InitialTemplateInputs
105+
datasource.inputs.ListOfImagesDictionaries=ListOfImagesDictionaries
106+
datasource.inputs.registrationImageTypes=registrationImageTypes
107+
datasource.inputs.interpolationMapping=interpolationMapping
108+
109+
"""
110+
5. Template is initialized by a simple average in this simple example,
111+
any reference image could be used (i.e. a previously created template)
112+
"""
113+
initAvg = pe.Node(interface=ants.AverageImages(), name ='initAvg')
114+
initAvg.inputs.dimension = 3
115+
initAvg.inputs.normalize = True
116+
117+
tbuilder.connect(datasource, "InitialTemplateInputs", initAvg, "images")
118+
119+
"""
120+
6. Define the first iteration of template building
121+
"""
122+
123+
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+
130+
tbuilder.connect(initAvg, 'output_average_image', buildTemplateIteration1, 'inputspec.fixed_image')
131+
tbuilder.connect(datasource, 'ListOfImagesDictionaries', buildTemplateIteration1, 'inputspec.ListOfImagesDictionaries')
132+
tbuilder.connect(datasource, 'registrationImageTypes', buildTemplateIteration1, 'inputspec.registrationImageTypes')
133+
tbuilder.connect(datasource, 'interpolationMapping', buildTemplateIteration1, 'inputspec.interpolationMapping')
134+
"""
135+
7. Define the second iteration of template building
136+
"""
137+
138+
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}
141+
tbuilder.connect(buildTemplateIteration1, 'outputspec.template', buildTemplateIteration2, 'inputspec.fixed_image')
142+
tbuilder.connect(datasource, 'ListOfImagesDictionaries', buildTemplateIteration2, 'inputspec.ListOfImagesDictionaries')
143+
tbuilder.connect(datasource, 'registrationImageTypes', buildTemplateIteration2, 'inputspec.registrationImageTypes')
144+
tbuilder.connect(datasource, 'interpolationMapping', buildTemplateIteration2, 'inputspec.interpolationMapping')
145+
146+
"""
147+
8. Move selected files to a designated results folder
148+
"""
149+
150+
datasink = pe.Node(io.DataSink(), name="datasink")
151+
datasink.inputs.base_directory = os.path.join(requestedPath, "results")
152+
153+
tbuilder.connect(buildTemplateIteration2, 'outputspec.template',datasink,'PrimaryTemplate')
154+
tbuilder.connect(buildTemplateIteration2, 'outputspec.passive_deformed_templates',datasink,'PassiveTemplate')
155+
tbuilder.connect(initAvg, 'output_average_image', datasink,'PreRegisterAverage')
156+
157+
"""
158+
8. Run the workflow
159+
"""
160+
161+
tbuilder.run(plugin="SGE")

0 commit comments

Comments
 (0)