@@ -70,10 +70,12 @@ def all_fmb_pipeline(name='hmc_sdc_ecc'):
70
70
def all_peb_pipeline (name = 'hmc_sdc_ecc' ,
71
71
epi_params = dict (echospacing = 0.77e-3 ,
72
72
acc_factor = 3 ,
73
- enc_dir = 'y-' ),
73
+ enc_dir = 'y-' ,
74
+ epi_factor = 1 ),
74
75
altepi_params = dict (echospacing = 0.77e-3 ,
75
76
acc_factor = 3 ,
76
- enc_dir = 'y' )):
77
+ enc_dir = 'y' ,
78
+ epi_factor = 1 )):
77
79
"""
78
80
Builds a pipeline including three artifact corrections: head-motion correction (HMC),
79
81
susceptibility-derived distortion correction (SDC), and Eddy currents-derived distortion
@@ -96,6 +98,10 @@ def all_peb_pipeline(name='hmc_sdc_ecc',
96
98
sdc = sdc_peb (epi_params = epi_params , altepi_params = altepi_params )
97
99
ecc = ecc_pipeline ()
98
100
101
+ rot_bvec = pe .Node (niu .Function (input_names = ['in_bvec' , 'eddy_params' ],
102
+ output_names = ['out_file' ], function = eddy_rotate_bvecs ),
103
+ name = 'Rotate_Bvec' )
104
+
99
105
regrid = pe .Node (fs .MRIConvert (vox_size = (2.0 , 2.0 , 2.0 ), out_orientation = 'RAS' ),
100
106
name = 'Reslice' )
101
107
@@ -120,6 +126,76 @@ def all_peb_pipeline(name='hmc_sdc_ecc',
120
126
,(regrid , avg_b0_1 , [('out_file' , 'in_dwi' )])
121
127
,(inputnode , avg_b0_1 , [('in_bval' , 'in_bval' )])
122
128
,(avg_b0_1 , bet_dwi1 , [('out_file' ,'in_file' )])
129
+ ,(inputnode , rot_bvec , [('in_bvec' , 'in_bvec' )])
130
+ ,(ecc , rot_bvec , [('out_parameter' , 'eddy_params' )])
131
+ ,(bet_dwi1 , outputnode , [('mask_file' , 'out_mask' )])
132
+ ,(rot_bvec , outputnode , [('out_file' , 'out_bvec' )])
133
+ ])
134
+ return wf
135
+
136
+
137
+ def all_fsl_pipeline (name = 'fsl_all_correct' ,
138
+ epi_params = dict (echospacing = 0.77e-3 ,
139
+ acc_factor = 3 ,
140
+ enc_dir = 'y-' ),
141
+ altepi_params = dict (echospacing = 0.77e-3 ,
142
+ acc_factor = 3 ,
143
+ enc_dir = 'y' )):
144
+ """
145
+ Workflow that integrates FSL ``topup`` and ``eddy``.
146
+ """
147
+
148
+ inputnode = pe .Node (niu .IdentityInterface (fields = ['in_file' , 'in_bvec' , 'in_bval' ,
149
+ 'alt_file' ]), name = 'inputnode' )
150
+
151
+ outputnode = pe .Node (niu .IdentityInterface (fields = ['out_file' , 'out_mask' ,
152
+ 'out_bvec' ]), name = 'outputnode' )
153
+
154
+ def _gen_index (in_file ):
155
+ import numpy as np
156
+ import nibabel as nb
157
+ import os
158
+ out_file = os .path .abspath ('index.txt' )
159
+ vols = nb .load (in_file ).get_data ().shape [- 1 ]
160
+ np .savetxt (out_file , np .ones ((vols ,)).T )
161
+ return out_file
162
+
163
+ avg_b0_0 = pe .Node (niu .Function (input_names = ['in_dwi' , 'in_bval' ],
164
+ output_names = ['out_file' ], function = b0_average ), name = 'b0_avg_pre' )
165
+ bet_dwi0 = pe .Node (fsl .BET (frac = 0.3 , mask = True , robust = True ), name = 'bet_dwi_pre' )
166
+
167
+ sdc = sdc_peb (epi_params = epi_params , altepi_params = altepi_params )
168
+ ecc = pe .Node (fsl .Eddy (method = 'jac' ), name = 'fsl_eddy' )
169
+
170
+ regrid = pe .Node (fs .MRIConvert (vox_size = (2.0 , 2.0 , 2.0 ), out_orientation = 'RAS' ),
171
+ name = 'Reslice' )
172
+ avg_b0_1 = pe .Node (niu .Function (input_names = ['in_dwi' , 'in_bval' ],
173
+ output_names = ['out_file' ], function = b0_average ), name = 'b0_avg_post' )
174
+ bet_dwi1 = pe .Node (fsl .BET (frac = 0.3 , mask = True , robust = True ), name = 'bet_dwi_post' )
175
+
176
+ wf = pe .Workflow ('dMRI_Artifacts_FSL' )
177
+ wf .connect ([
178
+ (inputnode , avg_b0_0 , [('in_file' , 'in_dwi' ),
179
+ ('in_bval' , 'in_bval' )])
180
+ ,(avg_b0_0 , bet_dwi0 , [('out_file' ,'in_file' )])
181
+ ,(bet_dwi0 , sdc , [('mask_file' , 'inputnode.in_mask' )])
182
+ ,(inputnode , sdc , [('in_file' , 'inputnode.in_file' ),
183
+ ('alt_file' , 'inputnode.alt_file' ),
184
+ ('in_bval' , 'inputnode.in_bval' )])
185
+
186
+ ,(sdc , ecc , [('topup.out_enc_file' , 'in_acqp' ),
187
+ ('topup.out_fieldcoef' , 'in_topup_fieldcoef' ),
188
+ ('topup.out_movpar' , 'in_topup_movpar' )])
189
+ ,(bet_dwi0 , ecc , [('mask_file' , 'in_mask' )])
190
+ ,(inputnode , ecc , [('in_file' , 'in_file' ),
191
+ (('in_file' , _gen_index ), 'in_index' ),
192
+ ('in_bval' , 'in_bval' ),
193
+ ('in_bvec' , 'in_bvec' )])
194
+ ,(ecc , regrid , [('out_corrected' , 'in_file' )])
195
+ ,(regrid , outputnode , [('out_file' , 'out_file' )])
196
+ ,(regrid , avg_b0_1 , [('out_file' , 'in_dwi' )])
197
+ ,(inputnode , avg_b0_1 , [('in_bval' , 'in_bval' )])
198
+ ,(avg_b0_1 , bet_dwi1 , [('out_file' ,'in_file' )])
123
199
,(bet_dwi1 , outputnode , [('mask_file' , 'out_mask' )])
124
200
])
125
201
return wf
@@ -218,6 +294,7 @@ def hmc_pipeline(name='motion_correct'):
218
294
])
219
295
return wf
220
296
297
+
221
298
def ecc_pipeline (name = 'eddy_correct' ):
222
299
"""
223
300
ECC stands for Eddy currents correction.
@@ -326,6 +403,7 @@ def ecc_pipeline(name='eddy_correct'):
326
403
])
327
404
return wf
328
405
406
+
329
407
def sdc_fmb (name = 'fmb_correction' ,
330
408
fugue_params = dict (smooth3d = 2.0 ),
331
409
bmap_params = dict (delta_te = 2.46e-3 ),
@@ -462,10 +540,12 @@ def sdc_fmb(name='fmb_correction',
462
540
def sdc_peb (name = 'peb_correction' ,
463
541
epi_params = dict (echospacing = 0.77e-3 ,
464
542
acc_factor = 3 ,
465
- enc_dir = 'y-' ),
543
+ enc_dir = 'y-' ,
544
+ epi_factor = 1 ),
466
545
altepi_params = dict (echospacing = 0.77e-3 ,
467
546
acc_factor = 3 ,
468
- enc_dir = 'y' )):
547
+ enc_dir = 'y' ,
548
+ epi_factor = 1 )):
469
549
"""
470
550
SDC stands for susceptibility distortion correction. PEB stands for phase-encoding-based.
471
551
@@ -517,25 +597,72 @@ def sdc_peb(name='peb_correction',
517
597
518
598
topup = pe .Node (fsl .TOPUP (), name = 'topup' )
519
599
topup .inputs .encoding_direction = [epi_params ['enc_dir' ], altepi_params ['enc_dir' ]]
520
- topup .inputs .readout_times = [epi_params ['echospacing' ]/ (1.0 * epi_params ['acc_factor' ]),
521
- altepi_params ['echospacing' ]/ (1.0 * altepi_params ['acc_factor' ])]
600
+ topup .inputs .readout_times = [compute_readout (epi_params ),
601
+ compute_readout (altepi_params )]
602
+
522
603
unwarp = pe .Node (fsl .ApplyTOPUP (in_index = [1 ], method = 'jac' ), name = 'unwarp' )
523
604
524
605
wf = pe .Workflow (name = name )
525
606
wf .connect ([
526
- (inputnode , b0_ref , [('in_file' ,'in_file' ),
527
- (('ref_num' , _checkrnum ),'t_min' )])
528
- ,(inputnode , b0_alt , [('alt_file' ,'in_file' ),
529
- (('ref_num' , _checkrnum ),'t_min' )])
530
- ,(b0_ref , b0_comb , [('roi_file' ,'in1' )])
531
- ,(b0_alt , b0_comb , [('roi_file' ,'in2' )])
607
+ (inputnode , b0_ref , [('in_file' , 'in_file' ),
608
+ (('ref_num' , _checkrnum ), 't_min' )])
609
+ ,(inputnode , b0_alt , [('alt_file' , 'in_file' ),
610
+ (('ref_num' , _checkrnum ), 't_min' )])
611
+ ,(b0_ref , b0_comb , [('roi_file' , 'in1' )])
612
+ ,(b0_alt , b0_comb , [('roi_file' , 'in2' )])
532
613
,(b0_comb , b0_merge , [('out' , 'in_files' )])
533
- ,(b0_merge , topup , [('merged_file' ,'in_file' )])
534
- ,(topup , unwarp , [('out_fieldcoef' ,'in_topup_fieldcoef' ),
535
- ('out_movpar' ,'in_topup_movpar' ),
536
- ('out_enc_file' ,'encoding_file' )])
537
- ,(inputnode , unwarp , [('in_file' ,'in_files' )])
538
- ,(unwarp , outputnode , [('out_corrected' ,'out_file' )])
614
+ ,(b0_merge , topup , [('merged_file' , 'in_file' )])
615
+ ,(topup , unwarp , [('out_fieldcoef' , 'in_topup_fieldcoef' ),
616
+ ('out_movpar' , 'in_topup_movpar' ),
617
+ ('out_enc_file' , 'encoding_file' )])
618
+ ,(inputnode , unwarp , [('in_file' , 'in_files' )])
619
+ ,(unwarp , outputnode , [('out_corrected' , 'out_file' )])
620
+ ])
621
+ return wf
622
+
623
+
624
+ def remove_bias (name = 'bias_correct' ):
625
+ """
626
+ This workflow estimates a single multiplicative bias field from the averaged *b0*
627
+ image, as suggested in [Jeurissen2014]_.
628
+
629
+ .. admonition:: References
630
+
631
+ .. [Jeurissen2014] Jeurissen B. et al., `Multi-tissue constrained spherical deconvolution
632
+ for improved analysis of multi-shell diffusion MRI data
633
+ <http://dx.doi.org/10.1016/j.neuroimage.2014.07.061>`_. NeuroImage (2014).
634
+ doi: 10.1016/j.neuroimage.2014.07.061
635
+
636
+ """
637
+ inputnode = pe .Node (niu .IdentityInterface (fields = ['in_file' , 'in_bval' ,
638
+ 'in_mask' ]), name = 'inputnode' )
639
+
640
+ outputnode = pe .Node (niu .IdentityInterface (fields = ['out_file' ]),
641
+ name = 'outputnode' )
642
+
643
+ avg_b0 = pe .Node (niu .Function (input_names = ['in_dwi' , 'in_bval' ],
644
+ output_names = ['out_file' ], function = b0_average ),
645
+ name = 'b0_avg' )
646
+ n4 = pe .Node (ants .N4BiasFieldCorrection (dimension = 3 ,
647
+ save_bias = True , bspline_fitting_distance = 600 ), name = 'Bias_b0' )
648
+ split = pe .Node (fsl .Split (dimension = 't' ), name = 'SplitDWIs' )
649
+ mult = pe .MapNode (fsl .MultiImageMaths (op_string = '-div %s' ),
650
+ iterfield = ['in_file' ], name = 'RemoveBiasOfDWIs' )
651
+ thres = pe .MapNode (fsl .Threshold (thresh = 0.0 ), iterfield = ['in_file' ],
652
+ name = 'RemoveNegative' )
653
+ merge = pe .Node (fsl .utils .Merge (dimension = 't' ), name = 'MergeDWIs' )
654
+
655
+ wf = pe .Workflow (name = name )
656
+ wf .connect ([
657
+ (inputnode , avg_b0 , [('in_file' , 'in_dwi' ),
658
+ ('in_bval' , 'in_bval' )])
659
+ ,(avg_b0 , n4 , [('out_file' , 'input_image' )])
660
+ ,(inputnode , n4 , [('in_mask' , 'mask_image' )])
661
+ ,(inputnode , split , [('in_file' , 'in_file' )])
662
+ ,(n4 , mult , [('bias_image' , 'operand_files' )])
663
+ ,(split , mult , [('out_files' , 'in_file' )])
664
+ ,(mult , thres , [('out_file' , 'in_file' )])
665
+ ,(thres , merge , [('out_file' , 'in_files' )])
539
666
])
540
667
return wf
541
668
@@ -546,12 +673,13 @@ def _checkrnum(ref_num):
546
673
return 0
547
674
return ref_num
548
675
676
+
549
677
def _checkinitxfm (in_bval , in_xfms = None ):
550
678
from nipype .interfaces .base import isdefined
551
679
import numpy as np
552
680
import os .path as op
553
681
bvals = np .loadtxt (in_bval )
554
- non_b0 = np .where (bvals != 0 )[0 ].tolist ()
682
+ non_b0 = np .where (bvals != 0 )[0 ].tolist ()
555
683
556
684
init_xfms = []
557
685
if (in_xfms is None ) or (not isdefined (in_xfms )) or (len (in_xfms )!= len (bvals )):
0 commit comments