1
+ def get_flirt_motion_parameters (eddy_params ):
2
+ import nipype .interfaces .fsl .utils as fsl
3
+ import os
4
+ import numpy as np
5
+
6
+ data = np .genfromtxt (eddy_params )
7
+ translations = data [:,:3 ]
8
+ rotations = data [:,3 :6 ]
9
+ rigid = np .hstack ((rotations , translations ))
10
+
11
+ motion_params = os .path .abspath ('motion_parameters.par' )
12
+ np .savetxt (motion_params , rigid )
13
+
14
+ return motion_params
15
+
16
+
17
+ def run_preAFQ (dwi_file , dwi_file_AP , dwi_file_PA , bvec_file , bval_file , subjects_dir , working_dir , sink_dir ):
18
+ """
19
+ This is for HBN diffusion data
20
+ Assuming phase-encode direction is AP/PA for topup
21
+ """
22
+ import nipype .interfaces .freesurfer as fs
23
+ import nipype .interfaces .fsl as fsl
24
+ from nipype .interfaces .fsl .utils import AvScale
25
+ import nipype .pipeline .engine as pe
26
+ import nipype .interfaces .utility as niu
27
+ import nipype .interfaces .io as nio
28
+ from nipype .workflows .dmri .fsl .epi import create_dmri_preprocessing
29
+ from nipype .interfaces .dipy import DTI
30
+ from nipype .utils .filemanip import fname_presuffix
31
+ import os
32
+ from nipype .interfaces .dipy import DTI
33
+ from nipype .interfaces .c3 import C3dAffineTool
34
+ from nipype .workflows .dmri .fsl .artifacts import all_fsl_pipeline , remove_bias
35
+
36
+ # some bookkeeping (getting the filename, gettings the BIDS subject name)
37
+ dwi_filename = os .path .split (dwi_file )[1 ].split (".nii.gz" )[0 ]
38
+ bids_subject_name = dwi_filename .split ("_" )[0 ]
39
+ assert bids_subject_name .startswith ("sub-" )
40
+
41
+ # Grab the preprocessing all_fsl_pipeline
42
+ # AK: watch out, other datasets might be encoded LR
43
+ epi_AP = {'echospacing' : 66.5e-3 , 'enc_dir' : 'y-' }
44
+ epi_PA = {'echospacing' : 66.5e-3 , 'enc_dir' : 'y' }
45
+ prep = all_fsl_pipeline (epi_params = epi_AP , altepi_params = epi_PA )
46
+ prep_inputspec = prep .get_node ('inputnode' )
47
+ prep_outputspec = prep .get_node ('outputnode' )
48
+ #print(prep_inputspec, prep_outputspec)
49
+
50
+ # initialize an overall workflow
51
+ wf = pe .Workflow (name = "preAFQ" )
52
+ wf .base_dir = os .path .abspath (working_dir )
53
+ # wf.connect([(infosource, datasource, [('subject_id', 'subject_id')]),
54
+ # (datasource, prep,
55
+ # [('dwi', 'inputnode.in_file'), ('dwi_rev', 'inputnode.alt_file'),
56
+ # ('bvals', 'inputnode.in_bval'), ('bvecs', 'inputnode.in_bvec')]),
57
+ # (prep, bias, [('outputnode.out_file', 'inputnode.in_file'),
58
+ # ('outputnode.out_mask', 'inputnode.in_mask')]),
59
+ # (datasource, bias, [('bvals', 'inputnode.in_bval')])])
60
+
61
+ # wf = create_dmri_preprocessing(name='preAFQ',
62
+ # use_fieldmap=False,
63
+ # fieldmap_registration=False)
64
+
65
+ prep .inputs .inputnode .in_file = dwi_file
66
+ #prep.inputs.inputnode.alt_file = dwi_file_PA
67
+ prep .inputs .inputnode .in_bvec = bvec_file
68
+ prep .inputs .inputnode .in_bval = bval_file
69
+ #print(prep.inputs)
70
+
71
+ merge = pe .Node (fsl .Merge (dimension = 't' ), name = "mergeAPPA" )
72
+ merge .inputs .in_files = [dwi_file_AP , dwi_file_PA ]
73
+ wf .connect (merge , 'merged_file' , prep , 'inputnode.alt_file' )
74
+
75
+
76
+ fslroi = pe .Node (fsl .ExtractROI (t_min = 0 , t_size = 1 ), name = "fslroi" )
77
+ wf .connect (prep , "outputnode.out_file" , fslroi , "in_file" )
78
+
79
+ bbreg = pe .Node (fs .BBRegister (contrast_type = "t2" , init = "fsl" , out_fsl_file = True ,
80
+ subjects_dir = subjects_dir ,
81
+ epi_mask = True ),
82
+ name = "bbreg" )
83
+ bbreg .inputs .subject_id = 'freesurfer' #bids_subject_name
84
+ wf .connect (fslroi ,"roi_file" , bbreg , "source_file" )
85
+
86
+ get_tensor = pe .Node (DTI (), name = "dipy_tensor" )
87
+ wf .connect (prep , "outputnode.out_file" , get_tensor , "in_file" )
88
+ get_tensor .inputs .in_bval = bval_file
89
+ wf .connect (prep , "outputnode.out_bvec" , get_tensor , "in_bvec" )
90
+
91
+ scale_tensor = pe .Node (name = 'scale_tensor' , interface = fsl .BinaryMaths ())
92
+ scale_tensor .inputs .operation = 'mul'
93
+ scale_tensor .inputs .operand_value = 1000
94
+ wf .connect (get_tensor , 'out_file' , scale_tensor , 'in_file' )
95
+
96
+ voltransform = pe .Node (fs .ApplyVolTransform (inverse = True ),
97
+ iterfield = ['source_file' , 'reg_file' ],
98
+ name = 'transform' )
99
+ voltransform .inputs .subjects_dir = subjects_dir
100
+
101
+ vt2 = voltransform .clone ("transform_aparcaseg" )
102
+ vt2 .inputs .interp = "nearest"
103
+
104
+ vt3 = voltransform .clone ("transform_orig" )
105
+
106
+
107
+ def binarize_aparc (aparc_aseg ):
108
+ import nibabel as nib
109
+ from nipype .utils .filemanip import fname_presuffix
110
+ import os
111
+ img = nib .load (aparc_aseg )
112
+ data , aff = img .get_data (), img .affine
113
+ outfile = fname_presuffix (aparc_aseg , suffix = "bin.nii.gz" , newpath = os .path .abspath ("." ), use_ext = False )
114
+ nib .Nifti1Image ((data > 0 ).astype (float ), aff ).to_filename (outfile )
115
+ return outfile
116
+
117
+ create_mask = pe .Node (niu .Function (input_names = ["aparc_aseg" ],
118
+ output_names = ["outfile" ],
119
+ function = binarize_aparc ),
120
+ name = "bin_aparc" )
121
+
122
+ def get_aparc_aseg (subjects_dir , sub ):
123
+ return os .path .join (subjects_dir , sub , "mri" , "aparc+aseg.mgz" )
124
+
125
+ def get_orig (subjects_dir , sub ):
126
+ return os .path .join (subjects_dir , sub , "mri" , "orig.mgz" )
127
+
128
+ create_mask .inputs .aparc_aseg = get_aparc_aseg (subjects_dir , 'freesurfer' )
129
+ wf .connect (create_mask , "outfile" , voltransform , "target_file" )
130
+
131
+ wf .connect (fslroi , "roi_file" , voltransform , "source_file" )
132
+ wf .connect (bbreg , "out_reg_file" , voltransform , "reg_file" )
133
+
134
+ vt2 .inputs .target_file = get_aparc_aseg (subjects_dir , 'freesurfer' )
135
+ wf .connect (fslroi , "roi_file" , vt2 , "source_file" )
136
+ wf .connect (bbreg , "out_reg_file" , vt2 , "reg_file" )
137
+
138
+ vt3 .inputs .target_file = get_orig (subjects_dir , 'freesurfer' )
139
+ wf .connect (fslroi , "roi_file" , vt3 , "source_file" )
140
+ wf .connect (bbreg , "out_reg_file" , vt3 , "reg_file" )
141
+
142
+ # AK (2017): THIS NODE MIGHT NOT BE NECESSARY
143
+ # AK (2018) doesn't know why she said that above..
144
+ threshold2 = pe .Node (fs .Binarize (min = 0.5 , out_type = 'nii.gz' , dilate = 1 ),
145
+ iterfield = ['in_file' ],
146
+ name = 'threshold2' )
147
+ wf .connect (voltransform , "transformed_file" , threshold2 , "in_file" )
148
+
149
+ # art detect stuff
150
+
151
+ motion = pe .Node (niu .Function (input_names = ['eddy_params' ],
152
+ output_names = ['motion_file' ],
153
+ function = get_flirt_motion_parameters ),
154
+ name = "reformat_motion" )
155
+
156
+ wf .connect (prep , "fsl_eddy.out_parameter" , motion , "eddy_params" )
157
+
158
+ from nipype .algorithms .rapidart import ArtifactDetect
159
+
160
+ art = pe .Node (interface = ArtifactDetect (), name = "art" )
161
+ art .inputs .use_differences = [True , True ]
162
+ art .inputs .save_plot = False
163
+ art .inputs .use_norm = True
164
+ art .inputs .norm_threshold = 3
165
+ art .inputs .zintensity_threshold = 9
166
+ art .inputs .mask_type = 'spm_global'
167
+ art .inputs .parameter_source = 'FSL'
168
+
169
+ wf .connect (motion , "motion_file" , art , "realignment_parameters" )
170
+ wf .connect (prep , "outputnode.out_file" , art , "realigned_files" )
171
+
172
+ datasink = pe .Node (nio .DataSink (),name = "sinker" )
173
+ datasink .inputs .base_directory = sink_dir
174
+ datasink .inputs .substitutions = [("vol0000_flirt_merged.nii.gz" , dwi_filename + '.nii.gz' ),
175
+ ("stats.vol0000_flirt_merged.txt" , dwi_filename + ".art.json" ),
176
+ ("motion_parameters.par" , dwi_filename + ".motion.txt" ),
177
+ ("_rotated.bvec" , ".bvec" ),
178
+ ("art.vol0000_flirt_merged_outliers.txt" , dwi_filename + ".outliers.txt" ),
179
+ ("vol0000_flirt_merged" , dwi_filename ),
180
+ ("_roi_bbreg_freesurfer" , "_register" ),
181
+ ("dwi/eddy_corrected" , "dwi/%s" % dwi_filename ),
182
+ ("dti/eddy_corrected" , "dti/%s" % dwi_filename .replace ("_dwi" , "" )),
183
+ ("reg/eddy_corrected" , "reg/%s" % dwi_filename .replace ("_dwi" , "" )),
184
+ ("aparc+asegbin_warped_thresh" , dwi_filename .replace ("_dwi" , "_mask" )),
185
+ ("aparc+aseg_warped_out" , dwi_filename .replace ("_dwi" , "_aparc+aseg" )),
186
+ ("art.eddy_corrected_outliers" , dwi_filename .replace ("dwi" , "outliers" )),
187
+ ("color_fa" , "colorfa" ),
188
+ ("orig_warped_out" , dwi_filename .replace ("_dwi" , "_T1w" )),
189
+ #("eddy_corrected_", dwi_filename.replace("dwi", "")),
190
+ ("stats.eddy_corrected" , dwi_filename .replace ("dwi" , "artStats" )),
191
+ ("eddy_corrected.eddy_parameters" , dwi_filename + ".eddy_parameters" ),
192
+ ("derivatives/preafq" , "derivatives/{}/preafq" .format (bids_subject_name ))]
193
+
194
+
195
+ wf .connect (art , "statistic_files" , datasink , "preafq.qc.@artstat" )
196
+ wf .connect (art , "outlier_files" , datasink , "preafq.qc.@artoutlier" )
197
+
198
+ wf .connect (prep , "outputnode.out_file" , datasink , "preafq.dwi.@corrected" )
199
+ wf .connect (prep , "outputnode.out_bvec" , datasink , "preafq.dwi.@rotated" )
200
+ wf .connect (prep , "fsl_eddy.out_parameter" , datasink , "preafq.qc.@eddyparams" )
201
+
202
+ wf .connect (get_tensor , "out_file" , datasink , "preafq.dti.@tensor" )
203
+ wf .connect (get_tensor , "fa_file" , datasink , "preafq.dti.@fa" )
204
+ wf .connect (get_tensor , "md_file" , datasink , "preafq.dti.@md" )
205
+ wf .connect (get_tensor , "ad_file" , datasink , "preafq.dti.@ad" )
206
+ wf .connect (get_tensor , "rd_file" , datasink , "preafq.dti.@rd" )
207
+ wf .connect (get_tensor , "color_fa_file" , datasink , "preafq.dti.@colorfa" )
208
+ wf .connect (get_tensor , "out_file" , datasink , "preafq.dti.@scaled_tensor" )
209
+
210
+ wf .connect (bbreg , "min_cost_file" , datasink , "preafq.reg.@mincost" )
211
+ wf .connect (bbreg ,"out_fsl_file" , datasink , "preafq.reg.@fslfile" )
212
+ wf .connect (bbreg , "out_reg_file" , datasink , "preafq.reg.@reg" )
213
+ wf .connect (threshold2 , "binary_file" , datasink , "preafq.anat.@mask" )
214
+
215
+ convert = pe .Node (fs .MRIConvert (out_type = "niigz" ), name = "convert2nii" )
216
+ wf .connect (vt2 , "transformed_file" , convert , "in_file" )
217
+ wf .connect (convert , "out_file" , datasink , "preafq.anat.@aparc_aseg" )
218
+
219
+ convert1 = convert .clone ("convertorig2nii" )
220
+ wf .connect (vt3 , "transformed_file" , convert1 , "in_file" )
221
+ wf .connect (convert1 , "out_file" , datasink , "preafq.anat.@anat" )
222
+
223
+ #wf.base_dir = working_dir
224
+ #wf.write_graph()
225
+ wf .run ()
226
+
227
+ from glob import glob
228
+ import os
229
+ from shutil import copyfile
230
+
231
+ copyfile (bval_file , os .path .join (sink_dir , bids_subject_name , "preafq" , "dwi" , os .path .split (bval_file )[1 ]))
232
+
233
+ # dmri_corrected = glob(os.path.join(sink_dir, '*/preafq/dwi', '*.nii.gz'))[0]
234
+ # bvec_rotated = glob(os.path.join(sink_dir, '*/preafq/dwi', '*.bvec'))[0]
235
+ # bval_file = glob(os.path.join(sink_dir, '*/preafq/dwi', '*.bval'))[0]
236
+ # # art_file = glob(os.path.join(sink_dir, '*/preafq/art', '*.art.json'))[0]
237
+ # # motion_file = glob(os.path.join(sink_dir, '*/preafq/art', '*.motion.txt'))[0]
238
+ # # outlier_file = glob(os.path.join(sink_dir, '*/preafq/art', '*.outliers.txt'))[0]
239
+ # return dmri_corrected, bvec_rotated, #art_file, motion_file, outlier_file
0 commit comments