2
2
Subcortical alignment into MNI space
3
3
"""
4
4
5
- from nipype .interfaces .fsl .maths import MultiImageMaths
6
5
from nipype .pipeline import engine as pe
7
6
from nipype .interfaces import utility as niu , fsl
8
7
from nipype .interfaces .workbench .cifti import CiftiSmooth
@@ -25,7 +24,8 @@ def gen_subcortical_alignment_wf(repetition_time, name='subcortical_alignment_wf
25
24
Align individual subcortical structures into MNI space.
26
25
27
26
This is a nipype workflow port of the DCAN infant pipeline.
28
- https://github.com/DCAN-Labs/dcan-infant-pipeline/blob/247e19e5441cc814cea2f23720caeeb6c6aeadf8/fMRISurface/scripts/SubcorticalAlign_ROIs.sh
27
+ https://github.com/DCAN-Labs/dcan-infant-pipeline/blob/247e19/fMRISurface/scripts/SubcorticalAlign_ROIs.sh
28
+
29
29
30
30
Parameters
31
31
----------
@@ -47,77 +47,38 @@ def gen_subcortical_alignment_wf(repetition_time, name='subcortical_alignment_wf
47
47
48
48
Outputs
49
49
-------
50
-
50
+ subcortical_file : :obj:`str`
51
+ The BOLD file in atlas space with each ROI individually aligned.
51
52
"""
52
53
from niworkflows .engine .workflows import LiterateWorkflow as Workflow
53
54
54
-
55
55
# inputs
56
+ # ${VolumefMRI}.nii.gz
56
57
# ${ROIFolder}/Atlas_ROIs.${GrayordinatesResolution}.nii.gz
57
58
# ${ROIFolder}/ROIs.${GrayordinatesResolution}.nii.gz
58
59
# $HCPPIPEDIR_Templates/InfMNI_2AdultMNI_Step2.mat
59
60
inputnode = pe .Node (
60
- niu .IdentityInterface (fields = ["bold_roi" , "atlas_roi" , "atlas_xfm" ]),
61
+ niu .IdentityInterface (fields = ["bold_file" , " bold_roi" , "atlas_roi" , "atlas_xfm" ]),
61
62
name = "inputnode" ,
62
63
)
63
- outputnode = pe .Node (niu .IdentityInterface (fields = []), name = 'outputnode' )
64
+ outputnode = pe .Node (niu .IdentityInterface (fields = ["subcortical_file" ]), name = 'outputnode' )
64
65
65
66
66
- #generate altas-roi space fMRI cifti for subcortical data
67
- # flirt -in ${VolumefMRI}.nii.gz -ref ${ROIFolder}/Atlas_ROIs.${GrayordinatesResolution}.nii.gz -applyxfm -init $HCPPIPEDIR_Templates/InfMNI_2AdultMNI_Step2.mat -out ${VolumefMRI}_2MNI.nii.gz
68
67
applyxfm_atlas = pe .Node (fsl .FLIRT (), name = "applyxfm_atlas" )
69
- # output: ${VolumefMRI}_2MNI.nii.gz
70
-
71
- # ${CARET7DIR}/wb_command -volume-affine-resample ${ROIFolder}/ROIs.${GrayordinatesResolution}.nii.gz $HCPPIPEDIR_Templates/InfMNI_2AdultMNI_Step2.mat ${VolumefMRI}_2MNI.nii.gz ENCLOSING_VOXEL ${ResultsFolder}/ROIs.${GrayordinatesResolution}.nii.gz -flirt ${ROIFolder}/ROIs.${GrayordinatesResolution}.nii.gz ${VolumefMRI}_2MNI.nii.gz
72
68
vol_resample = pe .Node (VolumeAffineResample (method = "ENCLOSING_VOXEL" ), name = "vol_resample" )
73
- # output: ${ResultsFolder}/ROIs.${GrayordinatesResolution}.nii.gz
74
-
75
- # ${CARET7DIR}/wb_command -cifti-create-dense-timeseries ${WD}/${NameOffMRI}_temp_orig_atlas.dtseries.nii -volume ${VolumefMRI}_2MNI.nii.gz ${ROIFolder}/Atlas_ROIs.${GrayordinatesResolution}.nii.gz
76
69
create_dense = pe .Node (CiftiCreateDenseTimeseries (), name = "create_dense" )
77
- # output: ${WD}/${NameOffMRI}_temp_orig_atlas.dtseries.nii
78
-
79
- # #splitting atlas and subject volume label files into individual ROI files for registration
80
- # ${CARET7DIR}/wb_command -volume-all-labels-to-rois ${ROIFolder}/ROIs.${GrayordinatesResolution}.nii.gz 1 ${WD}/sub_allroi.nii.gz
81
70
subj_rois = pe .Node (VolumeAllLabelsToROIs (label_map = 1 ), name = "subj_rois" )
82
- # output: ${WD}/sub_allroi.nii.gz
83
-
84
- # fslsplit ${WD}/sub_allroi.nii.gz sub_ROI -t
85
71
split_rois = pe .Node (fsl .Split (dimension = "t" ), name = "split_rois" )
86
- # output: sub_ROI* list
87
-
88
- # ${CARET7DIR}/wb_command -volume-all-labels-to-rois ${ROIFolder}/Atlas_ROIs.${GrayordinatesResolution}.nii.gz 1 ${WD}/atl_allroi.nii.gz
89
72
atlas_rois = pe .Node (VolumeAllLabelsToROIs (label_map = 1 ), name = "atlas_rois" )
90
- # output: ${WD}/atl_allroi.nii.gz
91
-
92
- # fslsplit ${WD}/atl_allroi.nii.gz atl_ROI -t
93
73
split_atlas_rois = pe .Node (fsl .Split (dimension = "t" ), name = "split_atlas_rois" )
94
- # output: atl_ROI* list
95
-
96
- # #exporting table to generate independent label files
97
- # ${CARET7DIR}/wb_command -volume-label-export-table ${ROIFolder}/Atlas_ROIs.${GrayordinatesResolution}.nii.gz 1 ${WD}/labelfile.txt
98
74
atlas_labels = pe .Node (VolumeLabelExportTable (label_map = 1 ), name = "atlas_labels" )
99
- # output: ${WD}/labelfile.txt
100
-
101
- # #extract information from label file (values on even numbered line preceded by label on odd)
102
75
parse_labels = pe .Node (
103
76
niu .Function (function = parse_roi_labels , output_names = ["structures" , "label_id" ]),
104
77
name = "parse_labels" ,
105
78
)
106
- # output: structures / label_ids
107
-
108
- # #initialize workbench command for creating dense time series.
109
- # DTSCommand="${CARET7DIR}/wb_command -cifti-create-dense-from-template ${WD}/${NameOffMRI}_temp_orig_atlas.dtseries.nii ${WD}/${NameOffMRI}_temp_atlas.dtseries.nii -series ${TR} 0.0 "
110
- # #initialize command to make sub2atl_label_ROI.2.nii.gz
111
- # Sub2AtlCmd=""
112
-
113
-
114
79
115
80
### The following is wrapped in a for-loop, iterating across each roi
116
- ## sub_{ROIname} is the roi
117
-
118
-
119
- #perform linear mapping from subject to atlas ROI
120
- # flirt -in ${WD}/sub_${ROIname} -ref ${WD}/atl_${ROIname} -searchrx -20 20 -searchry -20 20 -searchrz -20 20 -o sub2atl_${ROIname} -interp nearestneighbour -omat ${WD}/sub2atl_${ROInum}.mat
81
+ ### Instead, we will use MapNodes and iter across the varying inputs
121
82
roi2atlas = pe .MapNode (
122
83
fsl .FLIRT (
123
84
searchr_x = [- 20 , 20 ],
@@ -128,89 +89,51 @@ def gen_subcortical_alignment_wf(repetition_time, name='subcortical_alignment_wf
128
89
name = "roi2atlas" ,
129
90
iterfield = ["in_file" , "reference" ],
130
91
)
131
- # output: sub2atl_${ROIname} ${WD}/sub2atl_${ROInum}.mat
132
-
133
- # flirt -in ${VolumefMRI} -ref ${WD}/atl_${ROIname} -applyxfm -init ${WD}/sub2atl_${ROInum}.mat -o sub2atl_vol_${ROIname} -interp spline
134
92
applyxfm_roi = pe .MapNode (
135
93
fsl .ApplyXFM (interp = "spline" ),
136
94
iterfield = ["reference" ],
137
95
name = 'applyxfm_roi' ,
138
96
)
139
- # output: sub2atl_vol_${ROIname}
140
-
141
- # #masking BOLD volumetric data to ROI only
142
- # fslmaths sub2atl_vol_${ROIname} -mas sub2atl_${ROIname} sub2atl_vol_masked_${ROIname}
143
97
bold_mask_roi = pe .MapNode (
144
98
fsl .ApplyMask (),
145
99
iterfield = ["in_file" , "operand_file" ],
146
100
name = 'bold_mask_roi' ,
147
101
)
148
- # output: sub2atl_vol_masked_${ROIname}
149
-
150
- # #multiply ROI volume by value -- needed for creating a volume label file
151
- # fslmaths ${WD}/sub2atl_${ROIname} -mul $roi_value ${WD}/sub2atl_label_${ROIname}
152
102
mul_roi = pe .MapNode (
153
103
fsl .BinaryMaths (operation = "mul" ),
154
104
iterfield = ["in_file" , "operand_file" ],
155
105
name = 'mul_roi' ,
156
106
)
157
- # output: ${WD}/sub2atl_label_${ROIname}
158
-
159
- # fslmaths ${WD}/atl_${ROIname} -mul $roi_value ${WD}/atl_label_${ROIname}
160
107
mul_atlas_roi = pe .MapNode (
161
108
fsl .BinaryMaths (operation = "mul" ),
162
109
iterfield = ["in_file" , "operand_file" ],
163
110
name = 'mul_atlas_roi' ,
164
111
)
165
- # output: ${WD}/atl_label_${ROIname}
166
-
167
- # #use wb_command to create the volume label file, needed for creating the individual dtseries
168
- # ${CARET7DIR}/wb_command -volume-label-import ${WD}/sub2atl_label_${ROIname} ${WD}/labelfile.txt sub2atl_vol_label_${ROIname} -drop-unused-labels
169
112
vol_label = pe .MapNode (
170
113
VolumeLabelImport (drop_unused_labels = True ),
171
114
iterfield = ["in_file" ],
172
115
name = 'vol_label' ,
173
116
)
174
- # output: sub2atl_vol_label_${ROIname}
175
-
176
- # ${CARET7DIR}/wb_command -volume-label-import ${WD}/atl_label_${ROIname} ${WD}/labelfile.txt atl_vol_label_${ROIname} -drop-unused-labels
177
117
vol_atlas_label = pe .MapNode (
178
118
VolumeLabelImport (drop_unused_labels = True ),
179
119
iterfield = ["in_file" ],
180
120
name = 'vol_atlas_label' ,
181
121
)
182
- # output: atl_vol_label_${ROIname}
183
-
184
- # #create the individual dtseries
185
- # ${CARET7DIR}/wb_command -cifti-create-dense-timeseries ${WD}/${NameOffMRI}_temp_subject_${ROInum}.dtseries.nii -volume sub2atl_vol_masked_${ROIname} ${WD}/sub2atl_vol_label_${ROIname}
186
- # # Maybe here, too.
187
122
create_dtseries = pe .MapNode (
188
123
CiftiCreateDenseTimeseries (),
189
124
iterfield = ["volume_data" , "volume_structure_labels" ],
190
125
name = 'create_dtseries'
191
126
)
192
- # output: ${WD}/${NameOffMRI}_temp_subject_${ROInum}.dtseries.nii
193
-
194
- # #create the cifti label file from the volume label file (why?????)
195
- # ${CARET7DIR}/wb_command -cifti-create-label ${WD}/atl_${NameOffMRI}_temp_template_${ROInum}.dlabel.nii -volume ${WD}/atl_vol_label_${ROIname} ${WD}/atl_vol_label_${ROIname}
196
127
create_label = pe .MapNode (
197
128
CiftiCreateLabel (),
198
129
iterfield = ["volume_label" , "structure_label_volume" ],
199
130
name = 'create_label' ,
200
131
)
201
- # output: ${WD}/sub_${NameOffMRI}_temp_template_${ROInum}.dlabel.nii
202
-
203
- # #dilate the timeseries
204
- # ${CARET7DIR}/wb_command -cifti-dilate ${WD}/${NameOffMRI}_temp_subject_${ROInum}.dtseries.nii COLUMN 0 10 ${WD}/${NameOffMRI}_temp_subject_${ROInum}_dilate.dtseries.nii
205
132
dilate = pe .MapNode (
206
133
CiftiDilate (direction = "COLUMN" , surface_distance = 0 , volume_distance = 10 ),
207
134
iterfield = ["in_file" ],
208
135
name = "dilate"
209
136
)
210
- # output: ${WD}/${NameOffMRI}_temp_subject_${ROInum}_dilate.dtseries.nii
211
-
212
- # #perform resampling - resample into Atlas space, not subject space.
213
- # ${CARET7DIR}/wb_command -cifti-resample ${WD}/${NameOffMRI}_temp_subject_${ROInum}_dilate.dtseries.nii COLUMN ${WD}/atl_${NameOffMRI}_temp_template_${ROInum}.dlabel.nii COLUMN ADAP_BARY_AREA CUBIC ${WD}/${NameOffMRI}_temp_atlas_${ROInum}.dtseries.nii -volume-predilate 10
214
137
resample = pe .MapNode (
215
138
CiftiResample (
216
139
direction = "COLUMN" ,
@@ -222,42 +145,34 @@ def gen_subcortical_alignment_wf(repetition_time, name='subcortical_alignment_wf
222
145
iterfield = ["in_file" , "template" ],
223
146
name = 'resample' ,
224
147
)
225
- # output: ${WD}/${NameOffMRI}_temp_atlas_${ROInum}.dtseries.nii
226
-
227
- # #perform smoothing
228
- # ${CARET7DIR}/wb_command -cifti-smoothing ${WD}/${NameOffMRI}_temp_atlas_${ROInum}.dtseries.nii 0 ${Sigma} COLUMN ${WD}/${NameOffMRI}_temp_subject_dilate_resample_smooth_${ROInum}.dtseries.nii -fix-zeros-volume
229
148
smooth = pe .MapNode (
230
149
CiftiSmooth (direction = "COLUMN" , fix_zeros_vol = True ),
231
150
iterfield = ["in_file" ],
232
151
name = "smooth"
233
152
)
234
- # output: ${WD}/${NameOffMRI}_temp_subject_dilate_resample_smooth_${ROInum}.dtseries.nii
235
-
236
- # #split back into a volumetric timeseries file
237
- # ${CARET7DIR}/wb_command -cifti-separate ${WD}/${NameOffMRI}_temp_subject_dilate_resample_smooth_${ROInum}.dtseries.nii COLUMN -volume-all ${ResultsFolder}/${NameOffMRI}_${ROInum}.nii.gz
238
153
separate = pe .MapNode (
239
154
CiftiSeparate (direction = "COLUMN" , volume_all = True ),
240
155
iterfield = ["in_file" ],
241
156
name = "separate"
242
157
)
243
- # output: ${ResultsFolder}/${NameOffMRI}_${ROInum}.nii.gz
244
158
245
159
fmt_vols = pe .Node (niu .Function (function = format_volume_rois ), name = 'fmt_vols' )
246
- # #add input to wb_command to grow iteratively
247
- # DTSCommand="${CARET7DIR}/wb_command -cifti-create-dense-from-template ${WD}/${NameOffMRI}_temp_orig_atlas.dtseries.nii ${WD}/${NameOffMRI}_temp_atlas.dtseries.nii -series ${TR} 0.0"
248
- # DTSCommand="${DTSCommand} -volume ${roi_name} ${ResultsFolder}/${NameOffMRI}_${ROInum}.nii.gz"
249
160
create_dtseries = pe .Node (
250
161
CiftiCreateDenseFromTemplate (series = True , series_step = repetition_time , series_start = 0 ),
251
162
name = 'create_dtseries' ,
252
163
)
253
- # output: ${WD}/${NameOffMRI}_temp_atlas.dtseries.nii
254
-
255
- # fslmaths <file> -add <sub2atl_label_
256
- # Sub2AtlCmd="${Sub2AtlCmd}-add ${WD}/sub2atl_label_${ROIname} "
257
- operations = "-add %s " * len (rois ) - 1
258
- agg_rois = pe .MapNode (fsl .MultiImageMaths (op_string = operations .strip ()), name = 'agg_rois' )
164
+ fmt_agg_rois = pe .Node (
165
+ niu .Function (
166
+ function = format_agg_rois ,
167
+ output_names = ["first_image" , "op_files" , "op_string" ],
168
+ ),
169
+ name = 'fmt_agg_rois' ,
170
+ )
171
+ agg_rois = pe .MapNode (fsl .MultiImageMaths (), name = 'agg_rois' )
172
+ final_vol = pe .Node (CiftiSeparate (direction = "COLUMN" , volume_all = True ), name = "final_vol" )
259
173
260
174
workflow = Workflow (name = name )
175
+ # fmt: off
261
176
workflow .connect ([
262
177
(inputnode , applyxfm_atlas , [
263
178
("bold_file" , "in_file" ),
@@ -272,7 +187,6 @@ def gen_subcortical_alignment_wf(repetition_time, name='subcortical_alignment_wf
272
187
(atlas_rois , split_atlas_rois , [("out_file" , "in_file" )]),
273
188
(inputnode , atlas_labels , [("atlas_roi" , "in_file" )]),
274
189
(atlas_labels , parse_labels , [("out_file" , "label_file" )]),
275
-
276
190
# for loop across ROIs
277
191
(split_rois , roi2atlas , [("out_files" , "in_file" )]),
278
192
(inputnode , applyxfm_roi , [("bold_file" , "in_file" )]),
@@ -297,13 +211,21 @@ def gen_subcortical_alignment_wf(repetition_time, name='subcortical_alignment_wf
297
211
(create_label , resample , [("out_file" , "template" )]),
298
212
(resample , smooth , [("out_file" , "in_file" )]),
299
213
(smooth , separate , [("out_file" , "in_file" )]),
300
-
214
+ # end loop
301
215
(parse_labels , fmt_vols , [("structures" , "structs" )]),
302
216
(separate , fmt_vols , [("volume_all_file" , "rois" )]),
303
217
(create_dense , create_dtseries , [("out_file" , "in_file" )]),
304
218
(fmt_vols , create_dtseries , [("out" , "volume" )]),
305
-
219
+ (mul_roi , fmt_agg_rois , [("out_file" , "rois" )]),
220
+ (fmt_agg_rois , agg_rois , [
221
+ ("first_image" , "in_file" ),
222
+ ("op_files" , "operand_files" ),
223
+ ("op_string" , "op_string" )]),
224
+ (create_dtseries , final_vol , [("out_file" , "in_file" )]),
225
+ (final_vol , outputnode , [("out_file" , "subcortical_file" )]),
306
226
])
227
+ # fmt: on
228
+
307
229
308
230
def parse_roi_labels (label_file ):
309
231
"""
@@ -338,10 +260,23 @@ def parse_roi_labels(label_file):
338
260
339
261
def format_volume_rois (structs , rois ):
340
262
"""Format volume arguments for CiftiCreateDenseFromTemplate."""
341
-
342
263
return [(struct , roi ) for struct , roi in zip (structs , rois )]
343
264
344
265
345
266
def format_agg_rois (rois ):
346
- """Separate list of ROIs into first ROI and string of add commands"""
347
- return rois [0 ], "-add %s " * len (rois ) - 1
267
+ """
268
+ Helper function to format MultiImageMaths command.
269
+
270
+ Parameters
271
+ ----------
272
+ rois : `list` of `str`s
273
+ List of files
274
+
275
+ Returns
276
+ -------
277
+ first_image
278
+ op_files
279
+ op_string
280
+
281
+ """
282
+ return rois [0 ], rois [1 :], "-add %s " * (len (rois ) - 1 ).strip ()
0 commit comments