2
2
Subcortical alignment into MNI space
3
3
"""
4
4
5
- from nibabies .interfaces .nibabel import MergeROIs
5
+ from nipype .interfaces import utility as niu , fsl
6
+ from nipype .pipeline import engine as pe
7
+ from niworkflows .engine .workflows import LiterateWorkflow as Workflow
8
+
9
+ from ...interfaces .workbench import VolumeLabelImport
10
+
11
+ from pkg_resources import resource_filename
12
+
13
+
14
+ def init_subcortical_rois_wf (* , name = "subcortical_rois_wf" ):
15
+ """
16
+ Refine segmentations into volumes of expected CIFTI subcortical structures.
17
+
18
+
19
+ Parameters
20
+ ----------
21
+ name : :obj:`str`
22
+ Name of the workflow
23
+
24
+ Inputs
25
+ ------
26
+ MNIInfant_aseg : :obj:`str`
27
+ FreeSurfer's aseg in MNIInfant space
28
+
29
+ Outputs
30
+ -------
31
+ MNIInfant_rois : :obj:`str`
32
+ Subcortical ROIs in MNIInfant space
33
+ MNI152_rois : :obj:`str`
34
+ Subcortical ROIs in `MNI152NLin6Asym` space
35
+ """
36
+ from templateflow .api import get as get_template
37
+
38
+ # TODO: Implement BOLD refinement once InfantFS outputs subj/mri/wmparc.mgz
39
+ # The code is found at
40
+ # https://github.com/DCAN-Labs/dcan-infant-pipeline/blob/
41
+ # 0e9c2fe32fb4a5032d0a2a3e0905ad97fa52b398/PostFreeSurfer/scripts/
42
+ # FreeSurfer2CaretConvertAndRegisterNonlinear.sh
43
+ # Lines 70-78 & 116-127
44
+ # #
45
+ # For now, just use the aseg
46
+
47
+ workflow = Workflow (name = name )
48
+ inputnode = pe .Node (niu .IdentityInterface (fields = ["MNIInfant_aseg" ]), name = 'inputnode' )
49
+ outputnode = pe .Node (
50
+ niu .IdentityInterface (fields = ["MNIInfant_rois" , "MNI152_rois" ]),
51
+ name = 'outputnode' ,
52
+ )
53
+ # Fetch the HCP volumetric template
54
+ tpl_rois = get_template (
55
+ 'MNI152NLin6Asym' , resolution = 2 , atlas = "HCP" , suffix = "dseg" , raise_empty = True
56
+ )
57
+ outputnode .inputs .MNI152_rois = tpl_rois
58
+
59
+ # This will only used for the wmparc in subject space
60
+ # For now, define it and don't run it
61
+ # TODO: Move to TemplateFlow
62
+
63
+ # tpl_avgwmparc = resource_filename(
64
+ # 'nibabies', 'data/tpl-MNI152NLin6Asym_res-01_desc-avgwmparc_dseg.nii.gz'
65
+ # )
66
+ # applywarp_tpl = pe.Node(
67
+ # fsl.ApplyWarp(in_file=tpl_avgwmparc, ref_file=tpl_rois, interp="nn"),
68
+ # name="applywarp_std"
69
+ # )
70
+
71
+ subcortical_labels = resource_filename (
72
+ 'nibabies' , 'data/FreeSurferSubcorticalLabelTableLut.txt'
73
+ )
74
+ refine_bold_rois = pe .Node (
75
+ VolumeLabelImport (label_list_file = subcortical_labels , discard_others = True ),
76
+ name = "refine_bold_rois" ,
77
+ )
78
+
79
+ workflow .connect ([
80
+ (inputnode , refine_bold_rois , [("MNIInfant_aseg" , "in_file" )]),
81
+ # (applywarp_tpl, refine_std_rois, [("out_file", "in_file")]),
82
+ (refine_bold_rois , outputnode , [("out_file" , "MNIInfant_rois" )]),
83
+ ])
84
+ return workflow
6
85
7
86
8
87
def init_subcortical_mni_alignment_wf (* , vol_sigma = 0.8 , name = 'subcortical_mni_alignment_wf' ):
@@ -23,22 +102,22 @@ def init_subcortical_mni_alignment_wf(*, vol_sigma=0.8, name='subcortical_mni_al
23
102
24
103
Inputs
25
104
------
26
- bold_file : :obj:`str`
27
- BOLD file
28
- bold_roi : :obj:`str`
29
- File containing ROIs in BOLD space
30
- atlas_roi : :obj:`str`
31
- File containing ROIs in atlas space
32
- std_xfm : :obj:`str`
33
- File containing transform to the standard (MNI) space
105
+ MNIInfant_bold : :obj:`str`
106
+ BOLD file in MNI Infant space
107
+ MNIInfant_rois : :obj:`str`
108
+ File containing ROIs in MNI Infant space
109
+ MNI152_rois : :obj:`str`
110
+ File containing ROIs in MNI152NLin6Asym space
34
111
35
112
Outputs
36
113
-------
37
- subcortical_file : :obj:`str`
114
+ subcortical_volume : :obj:`str`
38
115
Volume file containing all ROIs individually aligned to standard
116
+ subcortical_labels : :obj:`str`
117
+ Volume file containing all labels
39
118
"""
40
- from nipype . pipeline import engine as pe
41
- from nipype . interfaces import utility as niu , fsl
119
+ from niworkflows . engine . workflows import LiterateWorkflow as Workflow
120
+ from ... interfaces . nibabel import MergeROIs
42
121
from ...interfaces .workbench import (
43
122
CiftiCreateDenseTimeseries ,
44
123
CiftiCreateLabel ,
@@ -49,19 +128,21 @@ def init_subcortical_mni_alignment_wf(*, vol_sigma=0.8, name='subcortical_mni_al
49
128
VolumeAffineResample ,
50
129
VolumeAllLabelsToROIs ,
51
130
VolumeLabelExportTable ,
52
- VolumeLabelImport ,
53
131
)
54
- from niworkflows . engine . workflows import LiterateWorkflow as Workflow
55
-
132
+ # reuse saved atlas to atlas transform
133
+ atlas_xfm = resource_filename ( "nibabies" , "data/MNIInfant_to_MNI1526NLinAsym.mat" )
56
134
inputnode = pe .Node (
57
- niu .IdentityInterface (fields = ["bold_file " , "bold_roi " , "atlas_roi" , "atlas_xfm " ]),
135
+ niu .IdentityInterface (fields = ["MNIInfant_bold " , "MNIInfant_rois " , "MNI152_rois " ]),
58
136
name = "inputnode" ,
59
137
)
60
- outputnode = pe .Node (niu .IdentityInterface (fields = ["subcortical_file" ]), name = 'outputnode' )
138
+ outputnode = pe .Node (
139
+ niu .IdentityInterface (fields = ["subcortical_volume" , "subcortical_labels" ]),
140
+ name = 'outputnode' ,
141
+ )
61
142
62
- applyxfm_atlas = pe .Node (fsl .ApplyXFM (), name = "applyxfm_atlas" )
143
+ applyxfm_atlas = pe .Node (fsl .ApplyXFM (in_matrix_file = atlas_xfm ), name = "applyxfm_atlas" )
63
144
vol_resample = pe .Node (
64
- VolumeAffineResample (method = "ENCLOSING_VOXEL" , flirt = True ),
145
+ VolumeAffineResample (method = "ENCLOSING_VOXEL" , flirt = True , affine = atlas_xfm ),
65
146
name = "vol_resample"
66
147
)
67
148
subj_rois = pe .Node (VolumeAllLabelsToROIs (label_map = 1 ), name = "subj_rois" )
@@ -167,26 +248,24 @@ def init_subcortical_mni_alignment_wf(*, vol_sigma=0.8, name='subcortical_mni_al
167
248
# fmt: off
168
249
workflow .connect ([
169
250
(inputnode , applyxfm_atlas , [
170
- ("bold_file" , "in_file" ),
171
- ("atlas_roi" , "reference" ),
172
- ("atlas_xfm" , "in_matrix_file" )]),
251
+ ("MNIInfant_bold" , "in_file" ),
252
+ ("MNI152_rois" , "reference" )]),
173
253
(inputnode , vol_resample , [
174
- ("bold_roi" , "in_file" ),
175
- ("atlas_xfm" , "affine" ),
176
- ("bold_roi" , "flirt_source_volume" )]),
254
+ ("MNIInfant_rois" , "in_file" ),
255
+ ("MNIInfant_rois" , "flirt_source_volume" )]),
177
256
(applyxfm_atlas , vol_resample , [
178
257
("out_file" , "volume_space" ),
179
258
("out_file" , "flirt_target_volume" )]),
180
- (inputnode , subj_rois , [("bold_roi " , "in_file" )]),
181
- (inputnode , atlas_rois , [("atlas_roi " , "in_file" )]),
259
+ (inputnode , subj_rois , [("MNIInfant_rois " , "in_file" )]),
260
+ (inputnode , atlas_rois , [("MNI152_rois " , "in_file" )]),
182
261
(subj_rois , split_rois , [("out_file" , "in_file" )]),
183
262
(atlas_rois , split_atlas_rois , [("out_file" , "in_file" )]),
184
- (inputnode , atlas_labels , [("atlas_roi " , "in_file" )]),
263
+ (inputnode , atlas_labels , [("MNI152_rois " , "in_file" )]),
185
264
(atlas_labels , parse_labels , [("out_file" , "label_file" )]),
186
265
# for loop across ROIs
187
266
(split_rois , roi2atlas , [("out_files" , "in_file" )]),
188
267
(split_atlas_rois , roi2atlas , [("out_files" , "reference" )]),
189
- (inputnode , applyxfm_roi , [("bold_file " , "in_file" )]),
268
+ (inputnode , applyxfm_roi , [("MNIInfant_bold " , "in_file" )]),
190
269
(split_atlas_rois , applyxfm_roi , [("out_files" , "reference" )]),
191
270
(roi2atlas , applyxfm_roi , [("out_matrix_file" , "in_matrix_file" )]),
192
271
(applyxfm_roi , bold_mask_roi , [("out_file" , "in_file" )]),
@@ -216,7 +295,8 @@ def init_subcortical_mni_alignment_wf(*, vol_sigma=0.8, name='subcortical_mni_al
216
295
("op_files" , "operand_files" ),
217
296
("op_string" , "op_string" )]),
218
297
(separate , merge_rois , [("volume_all_file" , "in_files" )]),
219
- (merge_rois , outputnode , [("out_file" , "subcortical_file" )]),
298
+ (merge_rois , outputnode , [("out_file" , "subcortical_volume" )]),
299
+ (inputnode , outputnode , [("MNI152_rois" , "subcortical_labels" )]),
220
300
])
221
301
# fmt: on
222
302
return workflow
@@ -267,3 +347,29 @@ def format_agg_rois(rois):
267
347
268
348
"""
269
349
return rois [0 ], rois [1 :], ("-add %s " * (len (rois ) - 1 )).strip ()
350
+
351
+
352
+ def drop_labels (in_file ):
353
+ """Drop non-subcortical labels"""
354
+ from pathlib import Path
355
+ import nibabel as nb
356
+ import numpy as np
357
+ from niworkflows .interfaces .cifti import _reorient_image
358
+
359
+ # FreeSurfer LUT values
360
+ expected_labels = {
361
+ 8 , 10 , 11 , 12 , 13 , 16 , 17 , 18 , 26 , 28 , 47 , 49 , 50 , 51 , 52 , 53 , 54 , 58 , 60 ,
362
+ }
363
+ img = _reorient_image (nb .load (in_file ), orientation = "LAS" )
364
+ hdr = img .header
365
+ data = np .asanyarray (img .dataobj ).astype ("int16" )
366
+ hdr .set_data_dtype ("int16" )
367
+ labels = np .unique (data )
368
+
369
+ for label in labels :
370
+ if label not in expected_labels :
371
+ data [data == label ] = 0
372
+
373
+ out_file = str (Path ("ROIs.nii.gz" ).absolute ())
374
+ img .__class__ (data , img .affine , header = hdr ).to_filename (out_file )
375
+ return out_file
0 commit comments