Skip to content

Commit 25a09f3

Browse files
committed
Updated dMRI and fMRI pre-processing
* ENH: modified parameter for parallel imaging, now it is possible to modify the acceleration factor * ENH: created new pipeline for full dMRI-EPI full distortions correction. Includes: motion, eddy currents and susceptibility correction
1 parent 04c568c commit 25a09f3

File tree

1 file changed

+95
-36
lines changed
  • nipype/workflows/dmri/fsl

1 file changed

+95
-36
lines changed

nipype/workflows/dmri/fsl/dti.py

Lines changed: 95 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,86 @@ def transpose(samples_over_fibres):
1212
a = a.reshape(-1,1)
1313
return a.T.tolist()
1414

15-
def create_dmri_preprocessing(name="dMRI_preprocessing"):
15+
def create_dmri_preprocessing(name="dMRI_preprocessing", fieldmap_registration=False):
1616
"""Creates a workflow that chains the necessary pipelines to
17-
correct for motion, eddy currents, and susceptibility
18-
artifacts in EPI dMRI sequences.
17+
correct for motion, eddy currents, and susceptibility
18+
artifacts in EPI dMRI sequences.
1919
2020
Example
2121
-------
2222
2323
>>> nipype_dmri_preprocess = create_dmri_preprocessing("nipype_dmri_prep")
24-
>>> nipype_dmri_preprocess.inputs.inputnode. =
25-
>>> nipype_dmri_preprocess.inputs.inputnode. =
26-
>>> nipype_dmri_preprocess.inputs.inputnode. =
27-
>>> nipype_dmri_preprocess.inputs.inputnode. =
28-
>>> nipype_dmri_preprocess.inputs.inputnode. =
29-
>>> nipype_dmri_preprocess.inputs.inputnode. =
30-
>>> nipype_dmri_preprocess.inputs.inputnode. =
31-
>>> nipype_dmri_preprocess.inputs.inputnode. =
24+
>>> nipype_dmri_preprocess.inputs.inputnode.in_file = 'diffusion.nii'
25+
>>> nipype_dmri_preprocess.inputs.inputnode.in_bvec = 'diffusion.bvec'
26+
>>> nipype_dmri_preprocess.inputs.inputnode.ref_num = 0
27+
>>> nipype_dmri_preprocess.inputs.inputnode.fieldmap_mag = 'magnitude.nii'
28+
>>> nipype_dmri_preprocess.inputs.inputnode.fieldmap_pha = 'phase.nii'
29+
>>> nipype_dmri_preprocess.inputs.inputnode.te_diff = 2.46
30+
>>> nipype_dmri_preprocess.inputs.inputnode.epi_echospacing = 0.77
31+
>>> nipype_dmri_preprocess.inputs.inputnode.epi_rev_encoding = False
32+
>>> nipype_dmri_preprocess.inputs.inputnode.pi_accel_factor = True
3233
>>> nipype_dmri_preprocess.run() # doctest: +SKIP
3334
35+
3436
Inputs::
3537
36-
inputnode.
38+
inputnode.in_file
39+
inputnode.in_bvec
40+
inputnode.ref_num
41+
inputnode.fieldmap_mag
42+
inputnode.fieldmap_pha
43+
inputnode.te_diff
44+
inputnode.epi_echospacing
45+
inputnode.epi_rev_encoding
46+
inputnode.pi_accel_factor
47+
inputnode.vsm_sigma
48+
3749
3850
Outputs::
3951
4052
outputnode.dmri_corrected
53+
outputnode.bvec_rotated
54+
55+
56+
Optional arguments::
57+
58+
fieldmap_registration - True if registration to fieldmap should be done (default False)
59+
4160
4261
"""
4362

4463
pipeline = pe.Workflow(name=name)
64+
65+
inputnode = pe.Node(interface = util.IdentityInterface(
66+
fields=['in_file', 'in_bvec','ref_num','fieldmap_mag',
67+
'fieldmap_pha','te_diff','epi_echospacing',
68+
'epi_rev_encoding','pi_accel_factor','vsm_sigma']),
69+
name='inputnode')
70+
71+
outputnode= pe.Node(interface = util.IdentityInterface(
72+
fields=['dmri_corrected','bvec_rotated']),
73+
name='outputnode')
74+
75+
motion = create_motion_correct_pipeline()
76+
eddy = create_eddy_correct_pipeline()
77+
susceptibility = create_susceptibility_correct_pipeline(fieldmap_registration=fieldmap_registration)
78+
79+
pipeline.connect([
80+
(inputnode, motion, [('in_file','inputnode.in_file'),('in_bvec','inputnode.in_bvec'),('ref_num','inputnode.ref_num')])
81+
,(inputnode, eddy, [('ref_num','inputnode.ref_num')])
82+
,(motion, eddy, [('outputnode.motion_corrected','inputnode.in_file')])
83+
,(eddy, susceptibility, [('outputnode.eddy_corrected','inputnode.in_file')])
84+
,(inputnode, susceptibility, [('ref_num','inputnode.ref_num')
85+
,('fieldmap_mag','inputnode.fieldmap_mag')
86+
,('fieldmap_pha','inputnode.fieldmap_pha')
87+
,('te_diff','inputnode.te_diff')
88+
,('epi_echospacing','inputnode.epi_echospacing')
89+
,('epi_rev_encoding','inputnode.epi_rev_encoding')
90+
,('pi_accel_factor','inputnode.pi_accel_factor')
91+
,('vsm_sigma','inputnode.vsm_sigma') ])
92+
,(motion, outputnode, [('outputnode.out_bvec', 'bvec_rotated')])
93+
,(susceptibility, outputnode, [('outputnode.epi_corrected','dmri_corrected')])
94+
])
4595

4696
return pipeline
4797

@@ -206,7 +256,8 @@ def create_bedpostx_pipeline(name="bedpostx"):
206256
def create_motion_correct_pipeline(name="motion_correct"):
207257
"""Creates a pipeline that corrects for motion artifact in dMRI sequences.
208258
It takes a series of diffusion weighted images and rigidly corregisters
209-
them to one reference image. Finally, the b-matrix is rotated accordingly,
259+
them to one reference image. Finally, the b-matrix is rotated accordingly
260+
(Leemans et al. 2009 - http://www.ncbi.nlm.nih.gov/pubmed/19319973),
210261
making use of the rotation matrix obtained by FLIRT.
211262
212263
Example
@@ -227,6 +278,8 @@ def create_motion_correct_pipeline(name="motion_correct"):
227278
Outputs::
228279
229280
outputnode.motion_corrected
281+
outputnode.out_bvec
282+
230283
"""
231284

232285
inputnode = pe.Node(interface = util.IdentityInterface(fields=["in_file", "ref_num","in_bvec"]),
@@ -260,8 +313,9 @@ def create_motion_correct_pipeline(name="motion_correct"):
260313

261314
def create_eddy_correct_pipeline(name="eddy_correct"):
262315
"""Creates a pipeline that replaces eddy_correct script in FSL. It takes a
263-
series of diffusion weighted images and linearly corregisters them to one
264-
reference image.
316+
series of diffusion weighted images and linearly co-registers them to one
317+
reference image. No rotation of the B-matrix is performed, so this pipeline
318+
should be executed after the motion correction pipeline.
265319
266320
Example
267321
-------
@@ -288,7 +342,7 @@ def create_eddy_correct_pipeline(name="eddy_correct"):
288342

289343
split = pe.Node(fsl.Split(dimension='t'), name="split")
290344
pick_ref = pe.Node(util.Select(), name="pick_ref")
291-
coregistration = pe.MapNode(fsl.FLIRT(no_search=True, padding_size=1 ), name = "coregistration", iterfield=["in_file"])
345+
coregistration = pe.MapNode(fsl.FLIRT(no_search=True, padding_size=1, dof=12 ), name = "coregistration", iterfield=["in_file"])
292346
merge = pe.Node(fsl.Merge(dimension="t"), name="merge")
293347
outputnode = pe.Node(interface = util.IdentityInterface(fields=["eddy_corrected"]),
294348
name="outputnode")
@@ -304,23 +358,24 @@ def create_eddy_correct_pipeline(name="eddy_correct"):
304358
])
305359
return pipeline
306360

307-
def create_susceptibility_correct_pipeline(name="susceptibility_correct", register_to_ref=False ):
361+
def create_susceptibility_correct_pipeline(name="susceptibility_correct", fieldmap_registration=False ):
308362
""" Replaces the epidewarp.fsl script (http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl)
309-
for susceptibility distortion correction in EPI sequences with the fieldmap information in
310-
dMRI and fMRI (Jezzard et al., MRM 1995 ) using FSL's FUGUE.
363+
for susceptibility distortion correction of dMRI & fMRI acquired with EPI sequences and the fieldmap
364+
information (Jezzard et al., 1995) using FSL's FUGUE. The registration to the (warped) fieldmap
365+
(strictly following the original script) is available using fieldmap_registration=True.
311366
312367
Example
313368
-------
314369
315-
>>> nipype_epicorrect = create_epi_correct_pipeline("nipype_epicorrect")
316-
>>> nipype_epicorrect.inputs.inputnode.in_file = 'epi_data.nii'
370+
>>> nipype_epicorrect = create_susceptibility_correct_pipeline("nipype_epicorrect", fieldmap_registration=False)
371+
>>> nipype_epicorrect.inputs.inputnode.in_file = 'diffusion.nii'
317372
>>> nipype_epicorrect.inputs.inputnode.fieldmap_mag = 'magnitude.nii'
318373
>>> nipype_epicorrect.inputs.inputnode.fieldmap_pha = 'phase.nii'
319374
>>> nipype_epicorrect.inputs.inputnode.te_diff = 2.46
320-
>>> nipype_epicorrect.inputs.inputnode.epi_echospacing = 0.51
375+
>>> nipype_epicorrect.inputs.inputnode.epi_echospacing = 0.77
321376
>>> nipype_epicorrect.inputs.inputnode.epi_rev_encoding = False
322-
>>> nipype_epicorrect.inputs.inputnode.ref_volume = 0
323-
>>> nipype_epicorrect.inputs.inputnode.epi_parallel = True
377+
>>> nipype_epicorrect.inputs.inputnode.ref_num = 0
378+
>>> nipype_epicorrect.inputs.inputnode.pi_accel_factor = 1.0
324379
>>> nipype_epicorrect.run() # doctest: +SKIP
325380
326381
Inputs::
@@ -332,14 +387,20 @@ def create_susceptibility_correct_pipeline(name="susceptibility_correct", regist
332387
inputnode.epi_echospacing - The echo spacing (aka dwell time) in the EPI sequence
333388
inputnode.epi_ph_encoding_dir - The phase encoding direction in EPI acquisition (default y)
334389
inputnode.epi_rev_encoding - True if it is acquired with reverse encoding
335-
inputnode.epi_parallel - True if EPI was acquired in a parallel imaging scheme
390+
inputnode.pi_accel_factor - Acceleration factor used for EPI parallel imaging (GRAPPA)
336391
inputnode.vsm_sigma - Sigma value of the gaussian smoothing filter applied to the vsm (voxel shift map)
337-
inputnode.ref_volume - The reference volume (B=0 in dMRI or a central frame in fMRI)
392+
inputnode.ref_num - The reference volume (B=0 in dMRI or a central frame in fMRI)
338393
339394
340395
Outputs::
341396
342397
outputnode.epi_corrected
398+
399+
400+
Optional arguments::
401+
402+
fieldmap_registration - True if registration to fieldmap should be done (default False)
403+
343404
"""
344405

345406
inputnode = pe.Node(interface = util.IdentityInterface(fields=["in_file",
@@ -349,9 +410,9 @@ def create_susceptibility_correct_pipeline(name="susceptibility_correct", regist
349410
"epi_echospacing",
350411
"epi_ph_encoding_dir",
351412
"epi_rev_encoding",
352-
"epi_parallel",
413+
"pi_accel_factor",
353414
"vsm_sigma",
354-
"ref_volume",
415+
"ref_num",
355416
"unwarp_direction"
356417
]), name="inputnode")
357418

@@ -365,7 +426,7 @@ def create_susceptibility_correct_pipeline(name="susceptibility_correct", regist
365426
mask_mag_dil = pe.Node( interface=util.Function( input_names=["in_file"], output_names=["out_file"], function=_dilate_mask), name='mask_dilate' )
366427

367428
# Compute dwell time
368-
dwell_time = pe.Node( interface=util.Function( input_names=["dwell_time","is_parallel","is_reverse_encoding"], output_names=["dwell_time"], function=_compute_dwelltime), name='dwell_time')
429+
dwell_time = pe.Node( interface=util.Function( input_names=["dwell_time","pi_factor","is_reverse_encoding"], output_names=["dwell_time"], function=_compute_dwelltime), name='dwell_time')
369430

370431
# Normalize phase diff to be [-pi, pi)
371432
norm_pha = pe.Node( interface=util.Function( input_names=["in_file"], output_names=["out_file"], function=_prepare_phasediff ), name='normalize_phasediff')
@@ -392,7 +453,7 @@ def create_susceptibility_correct_pipeline(name="susceptibility_correct", regist
392453

393454

394455
pipeline.connect([
395-
(inputnode, dwell_time, [('epi_echospacing','dwell_time'), ('epi_parallel','is_parallel'),('epi_rev_encoding','is_reverse_encoding') ])
456+
(inputnode, dwell_time, [('epi_echospacing','dwell_time'), ('pi_accel_factor','pi_factor'),('epi_rev_encoding','is_reverse_encoding') ])
396457
,(inputnode, select_mag, [('fieldmap_mag','in_file')] )
397458
,(inputnode, norm_pha, [('fieldmap_pha','in_file')] )
398459
,(select_mag, mask_mag, [('roi_file', 'in_file')] )
@@ -414,8 +475,7 @@ def create_susceptibility_correct_pipeline(name="susceptibility_correct", regist
414475
,(dwi_merge, outputnode, [('merged_file','epi_corrected')])
415476
])
416477

417-
if register_to_ref:
418-
# register to ref volume
478+
if fieldmap_registration:
419479
""" Register magfw to example epi. There are some parameters here that may need to be tweaked. Should probably strip the mag
420480
Pre-condition: forward warp the mag in order to reg with func. What does mask do here?
421481
"""
@@ -431,7 +491,7 @@ def create_susceptibility_correct_pipeline(name="susceptibility_correct", regist
431491
msk_applyxfm = pe.Node( interface=fsl.ApplyXfm(), name='msk_apply_xfm')
432492

433493
pipeline.connect([
434-
(inputnode, select_epi, [('in_file','in_file'), ('ref_volume','t_min')] )
494+
(inputnode, select_epi, [('in_file','in_file'), ('ref_num','t_min')] )
435495
,(select_epi, vsm_reg, [('roi_file','reference')])
436496
,(vsm, vsm_fwd, [('shift_out_file','shift_in_file')])
437497
,(mask_mag_dil, vsm_fwd, [('out_file','mask_file')] )
@@ -488,9 +548,8 @@ def _cat_logs( in_files ):
488548
totallog.write(line)
489549
return out_file
490550

491-
def _compute_dwelltime( dwell_time=0.68, is_parallel=False, is_reverse_encoding=False ):
492-
if is_parallel:
493-
dwell_time*=0.5
551+
def _compute_dwelltime( dwell_time=0.68, pi_factor=1.0, is_reverse_encoding=False ):
552+
dwell_time*=(1.0/pi_factor)
494553

495554
if is_reverse_encoding:
496555
dwell_time*=-1.0

0 commit comments

Comments
 (0)