1818Import necessary modules from nipype.
1919"""
2020
21- import os # system functions
22- import nipype .interfaces .io as nio # Data i/o
23- import nipype .interfaces .utility as util # utility
24- import nipype .pipeline .engine as pe # pypeline engine
21+ import os # system functions
22+ import nipype .interfaces .io as nio # Data i/o
23+ import nipype .interfaces .utility as util # utility
24+ import nipype .pipeline .engine as pe # pypeline engine
2525import nipype .interfaces .camino as camino
2626import nipype .interfaces .fsl as fsl
2727import nipype .interfaces .camino2trackvis as cam2trk
2828import nipype .algorithms .misc as misc
29-
3029"""
3130We use the following functions to scrape the voxel and data dimensions of the input images. This allows the
3231pipeline to be flexible enough to accept and process images of varying size. The SPM Face tutorial
@@ -62,21 +61,20 @@ def get_affine(volume):
6261 nii = nb .load (volume , mmap = NUMPY_MMAP )
6362 return nii .affine
6463
64+
6565subject_list = ['subj1' ]
6666fsl .FSLCommand .set_default_output_type ('NIFTI' )
67-
68-
6967"""
7068Map field names to individual subject runs
7169"""
7270
73- info = dict (dwi = [['subject_id' , 'data' ]],
74- bvecs = [['subject_id' , 'bvecs' ]],
75- bvals = [['subject_id' , 'bvals' ]])
76-
77- infosource = pe .Node (interface = util .IdentityInterface (fields = ['subject_id' ]),
78- name = "infosource" )
71+ info = dict (
72+ dwi = [['subject_id' , 'data' ]],
73+ bvecs = [['subject_id' , 'bvecs' ]],
74+ bvals = [['subject_id' , 'bvals' ]])
7975
76+ infosource = pe .Node (
77+ interface = util .IdentityInterface (fields = ['subject_id' ]), name = "infosource" )
8078"""Here we set up iteration over all the subjects. The following line
8179is a particular example of the flexibility of the system. The
8280``datasource`` attribute ``iterables`` tells the pipeline engine that
@@ -87,7 +85,6 @@ def get_affine(volume):
8785"""
8886
8987infosource .iterables = ('subject_id' , subject_list )
90-
9188"""
9289Now we create a :class:`nipype.interfaces.io.DataGrabber` object and
9390fill in the information from above about the layout of our data. The
@@ -96,9 +93,10 @@ def get_affine(volume):
9693functionality.
9794"""
9895
99- datasource = pe .Node (interface = nio .DataGrabber (infields = ['subject_id' ],
100- outfields = list (info .keys ())),
101- name = 'datasource' )
96+ datasource = pe .Node (
97+ interface = nio .DataGrabber (
98+ infields = ['subject_id' ], outfields = list (info .keys ())),
99+ name = 'datasource' )
102100
103101datasource .inputs .template = "%s/%s"
104102
@@ -109,13 +107,13 @@ def get_affine(volume):
109107datasource .inputs .field_template = dict (dwi = '%s/%s.nii.gz' )
110108datasource .inputs .template_args = info
111109datasource .inputs .sort_filelist = True
112-
113110"""
114111An inputnode is used to pass the data obtained by the data grabber to the actual processing functions
115112"""
116113
117- inputnode = pe .Node (interface = util .IdentityInterface (fields = ["dwi" , "bvecs" , "bvals" ]), name = "inputnode" )
118-
114+ inputnode = pe .Node (
115+ interface = util .IdentityInterface (fields = ["dwi" , "bvecs" , "bvals" ]),
116+ name = "inputnode" )
119117"""
120118Setup for Diffusion Tensor Computation
121119--------------------------------------
@@ -126,13 +124,11 @@ def get_affine(volume):
126124image2voxel = pe .Node (interface = camino .Image2Voxel (), name = "image2voxel" )
127125fsl2scheme = pe .Node (interface = camino .FSL2Scheme (), name = "fsl2scheme" )
128126fsl2scheme .inputs .usegradmod = True
129-
130127"""
131128Second, diffusion tensors are fit to the voxel-order data.
132129"""
133130
134131dtifit = pe .Node (interface = camino .DTIFit (), name = 'dtifit' )
135-
136132"""
137133Next, a lookup table is generated from the schemefile and the
138134signal-to-noise ratio (SNR) of the unweighted (q=0) data.
@@ -141,7 +137,6 @@ def get_affine(volume):
141137dtlutgen = pe .Node (interface = camino .DTLUTGen (), name = "dtlutgen" )
142138dtlutgen .inputs .snr = 16.0
143139dtlutgen .inputs .inversion = 1
144-
145140"""
146141In this tutorial we implement probabilistic tractography using the PICo algorithm.
147142PICo tractography requires an estimate of the fibre direction and a model of its
@@ -150,29 +145,25 @@ def get_affine(volume):
150145
151146picopdfs = pe .Node (interface = camino .PicoPDFs (), name = "picopdfs" )
152147picopdfs .inputs .inputmodel = 'dt'
153-
154148"""
155149An FSL BET node creates a brain mask is generated from the diffusion image for seeding the PICo tractography.
156150"""
157151
158152bet = pe .Node (interface = fsl .BET (), name = "bet" )
159153bet .inputs .mask = True
160-
161154"""
162155Finally, tractography is performed.
163156First DT streamline tractography.
164157"""
165158
166159trackdt = pe .Node (interface = camino .TrackDT (), name = "trackdt" )
167-
168160"""
169161Now camino's Probablistic Index of connectivity algorithm.
170162In this tutorial, we will use only 1 iteration for time-saving purposes.
171163"""
172164
173165trackpico = pe .Node (interface = camino .TrackPICo (), name = "trackpico" )
174166trackpico .inputs .iterations = 1
175-
176167"""
177168Currently, the best program for visualizing tracts is TrackVis. For this reason, a node is included to
178169convert the raw tract data to .trk format. Solely for testing purposes, another node is added to perform the reverse.
@@ -182,21 +173,20 @@ def get_affine(volume):
182173cam2trk_dt .inputs .min_length = 30
183174cam2trk_dt .inputs .voxel_order = 'LAS'
184175
185- cam2trk_pico = pe .Node (interface = cam2trk .Camino2Trackvis (), name = "cam2trk_pico" )
176+ cam2trk_pico = pe .Node (
177+ interface = cam2trk .Camino2Trackvis (), name = "cam2trk_pico" )
186178cam2trk_pico .inputs .min_length = 30
187179cam2trk_pico .inputs .voxel_order = 'LAS'
188180
189181trk2camino = pe .Node (interface = cam2trk .Trackvis2Camino (), name = "trk2camino" )
190-
191182"""
192183Tracts can also be converted to VTK and OOGL formats, for use in programs such as GeomView and Paraview,
193184using the following two nodes. For VTK use VtkStreamlines.
194185"""
195186
196- procstreamlines = pe .Node (interface = camino .ProcStreamlines (), name = "procstreamlines" )
187+ procstreamlines = pe .Node (
188+ interface = camino .ProcStreamlines (), name = "procstreamlines" )
197189procstreamlines .inputs .outputtracts = 'oogl'
198-
199-
200190"""
201191We can also produce a variety of scalar values from our fitted tensors. The following nodes generate the
202192fractional anisotropy and diffusivity trace maps and their associated headers.
@@ -206,45 +196,39 @@ def get_affine(volume):
206196trace = pe .Node (interface = camino .ComputeTensorTrace (), name = 'trace' )
207197dteig = pe .Node (interface = camino .ComputeEigensystem (), name = 'dteig' )
208198
209- analyzeheader_fa = pe .Node (interface = camino .AnalyzeHeader (), name = "analyzeheader_fa" )
199+ analyzeheader_fa = pe .Node (
200+ interface = camino .AnalyzeHeader (), name = "analyzeheader_fa" )
210201analyzeheader_fa .inputs .datatype = "double"
211202analyzeheader_trace = analyzeheader_fa .clone ('analyzeheader_trace' )
212203
213204fa2nii = pe .Node (interface = misc .CreateNifti (), name = 'fa2nii' )
214205trace2nii = fa2nii .clone ("trace2nii" )
215-
216206"""
217207Since we have now created all our nodes, we can now define our workflow and start making connections.
218208"""
219209
220210tractography = pe .Workflow (name = 'tractography' )
221211
222212tractography .connect ([(inputnode , bet , [("dwi" , "in_file" )])])
223-
224213"""
225214File format conversion
226215"""
227216
228217tractography .connect ([(inputnode , image2voxel , [("dwi" , "in_file" )]),
229218 (inputnode , fsl2scheme , [("bvecs" , "bvec_file" ),
230- ("bvals" , "bval_file" )])
231- ])
232-
219+ ("bvals" , "bval_file" )])])
233220"""
234221Tensor fitting
235222"""
236223
237224tractography .connect ([(image2voxel , dtifit , [['voxel_order' , 'in_file' ]]),
238- (fsl2scheme , dtifit , [['scheme' , 'scheme_file' ]])
239- ])
240-
225+ (fsl2scheme , dtifit , [['scheme' , 'scheme_file' ]])])
241226"""
242227Workflow for applying DT streamline tractogpahy
243228"""
244229
245230tractography .connect ([(bet , trackdt , [("mask_file" , "seed_file" )])])
246231tractography .connect ([(dtifit , trackdt , [("tensor_fitted" , "in_file" )])])
247-
248232"""
249233Workflow for applying PICo
250234"""
@@ -257,8 +241,6 @@ def get_affine(volume):
257241
258242# ProcStreamlines might throw memory errors - comment this line out in such case
259243tractography .connect ([(trackdt , procstreamlines , [("tracked" , "in_file" )])])
260-
261-
262244"""
263245Connecting the Fractional Anisotropy and Trace nodes is simple, as they obtain their input from the
264246tensor fitting.
@@ -270,32 +252,35 @@ def get_affine(volume):
270252
271253tractography .connect ([(dtifit , fa , [("tensor_fitted" , "in_file" )])])
272254tractography .connect ([(fa , analyzeheader_fa , [("fa" , "in_file" )])])
273- tractography .connect ([(inputnode , analyzeheader_fa , [(('dwi' , get_vox_dims ), 'voxel_dims' ),
274- (('dwi' , get_data_dims ), 'data_dims' )])])
255+ tractography .connect ([(inputnode , analyzeheader_fa ,
256+ [(('dwi' , get_vox_dims ), 'voxel_dims' ),
257+ (('dwi' , get_data_dims ), 'data_dims' )])])
275258tractography .connect ([(fa , fa2nii , [('fa' , 'data_file' )])])
276259tractography .connect ([(inputnode , fa2nii , [(('dwi' , get_affine ), 'affine' )])])
277260tractography .connect ([(analyzeheader_fa , fa2nii , [('header' , 'header_file' )])])
278261
279-
280262tractography .connect ([(dtifit , trace , [("tensor_fitted" , "in_file" )])])
281263tractography .connect ([(trace , analyzeheader_trace , [("trace" , "in_file" )])])
282- tractography .connect ([(inputnode , analyzeheader_trace , [(('dwi' , get_vox_dims ), 'voxel_dims' ),
283- (('dwi' , get_data_dims ), 'data_dims' )])])
264+ tractography .connect ([(inputnode , analyzeheader_trace ,
265+ [(('dwi' , get_vox_dims ), 'voxel_dims' ),
266+ (('dwi' , get_data_dims ), 'data_dims' )])])
284267tractography .connect ([(trace , trace2nii , [('trace' , 'data_file' )])])
285- tractography .connect ([(inputnode , trace2nii , [(('dwi' , get_affine ), 'affine' )])])
286- tractography .connect ([(analyzeheader_trace , trace2nii , [('header' , 'header_file' )])])
268+ tractography .connect ([(inputnode , trace2nii , [(('dwi' , get_affine ),
269+ 'affine' )])])
270+ tractography .connect ([(analyzeheader_trace , trace2nii , [('header' ,
271+ 'header_file' )])])
287272
288273tractography .connect ([(dtifit , dteig , [("tensor_fitted" , "in_file" )])])
289274
290275tractography .connect ([(trackpico , cam2trk_pico , [('tracked' , 'in_file' )])])
291276tractography .connect ([(trackdt , cam2trk_dt , [('tracked' , 'in_file' )])])
292- tractography .connect ([(inputnode , cam2trk_pico , [(('dwi' , get_vox_dims ), 'voxel_dims' ),
293- (('dwi' , get_data_dims ), 'data_dims' )])])
294-
295- tractography .connect ([(inputnode , cam2trk_dt , [(('dwi' , get_vox_dims ), 'voxel_dims' ),
296- (('dwi' , get_data_dims ), 'data_dims' )])])
297-
277+ tractography .connect ([(inputnode , cam2trk_pico ,
278+ [(('dwi' , get_vox_dims ), 'voxel_dims' ),
279+ (('dwi' , get_data_dims ), 'data_dims' )])])
298280
281+ tractography .connect ([(inputnode , cam2trk_dt ,
282+ [(('dwi' , get_vox_dims ), 'voxel_dims' ),
283+ (('dwi' , get_data_dims ), 'data_dims' )])])
299284"""
300285Finally, we create another higher-level workflow to connect our tractography workflow with the info and datagrabbing nodes
301286declared at the beginning. Our tutorial can is now extensible to any arbitrary number of subjects by simply adding
@@ -305,19 +290,16 @@ def get_affine(volume):
305290workflow = pe .Workflow (name = "workflow" )
306291workflow .base_dir = os .path .abspath ('camino_dti_tutorial' )
307292workflow .connect ([(infosource , datasource , [('subject_id' , 'subject_id' )]),
308- (datasource , tractography , [('dwi' , 'inputnode.dwi' ),
309- ('bvals' , 'inputnode.bvals' ),
310- ('bvecs' , 'inputnode.bvecs' )
311- ])
312- ])
293+ (datasource , tractography ,
294+ [('dwi' , 'inputnode.dwi' ), ('bvals' , 'inputnode.bvals' ),
295+ ('bvecs' , 'inputnode.bvecs' )])])
313296"""
314297The following functions run the whole workflow and produce a .dot and .png graph of the processing pipeline.
315298"""
316299
317300if __name__ == '__main__' :
318301 workflow .run ()
319302 workflow .write_graph ()
320-
321303"""
322304You can choose the format of the experted graph with the ``format`` option. For example ``workflow.write_graph(format='eps')``
323305
0 commit comments