Skip to content

Commit aea5ee8

Browse files
committed
enh:new fmb_sdc workflow
1 parent 576feff commit aea5ee8

File tree

2 files changed

+84
-34
lines changed

2 files changed

+84
-34
lines changed

nipype/workflows/dmri/preprocess/epi.py

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ def hmc_pipeline(name='motion_correct'):
7676
rot_bvec = pe.Node(niu.Function(input_names=['in_bvec', 'in_matrix'],
7777
output_names=['out_file'], function=rotate_bvecs),
7878
name='Rotate_Bvec')
79+
thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'],
80+
name='RemoveNegative')
7981
merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')
8082
outputnode = pe.Node(niu.IdentityInterface(fields=['out_file',
8183
'out_bvec', 'out_xfms']),
@@ -91,7 +93,8 @@ def hmc_pipeline(name='motion_correct'):
9193
,(inputnode, rot_bvec, [('in_bvec', 'in_bvec')])
9294
,(flirt, rot_bvec, [('out_matrix_file', 'in_matrix')])
9395
,(pick_ref, flirt, [('out', 'reference')])
94-
,(flirt, merge, [('out_file', 'in_files')])
96+
,(flirt, thres, [('out_file', 'in_file')])
97+
,(thres, merge, [('out_file', 'in_files')])
9598
,(merge, outputnode, [('merged_file', 'out_file')])
9699
,(rot_bvec, outputnode, [('out_file', 'out_bvec')])
97100
,(flirt, outputnode, [('out_matrix_file', 'out_xfms')])
@@ -207,9 +210,11 @@ def ecc_pipeline(name='eddy_correct'):
207210
return wf
208211

209212
def sdc_fmb(name='fmb_correction',
210-
fugue_params=dict(smooth3d=2.0, despike_2dfilter=True),
213+
fugue_params=dict(smooth3d=2.0),
211214
bmap_params=dict(delta_te=2.46e-3),
212-
epi_params=dict()):
215+
epi_params=dict(echospacing=0.77e-3,
216+
acc_factor=3,
217+
enc_dir='y-')):
213218
"""
214219
SDC stands for susceptibility distortion correction. FMB stands for fieldmap-based.
215220
@@ -233,6 +238,8 @@ def sdc_fmb(name='fmb_correction',
233238
inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bval', 'in_mask',
234239
'bmap_pha', 'bmap_mag']),
235240
name='inputnode')
241+
outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_vsm']),
242+
name='outputnode')
236243

237244

238245
firstmag = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name='GetFirst')
@@ -265,37 +272,58 @@ def sdc_fmb(name='fmb_correction',
265272

266273
cleanup = cleanup_edge_pipeline()
267274

275+
addvol = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_file'],
276+
function=add_empty_vol), name='AddEmptyVol')
277+
278+
vsm = pe.Node(fsl.FUGUE(save_shift=True, **fugue_params),
279+
name="ComputeVSM")
280+
vsm.inputs.asym_se_time = bmap_params['delta_te']
281+
vsm.inputs.dwell_time = epi_params['echospacing'] / (1.0 * epi_params['acc_factor'])
282+
283+
split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
284+
merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')
285+
unwarp = pe.MapNode(fsl.FUGUE(icorr=True, forward_warping=False),
286+
iterfield=['in_file'], name='UnwarpDWIs')
287+
unwarp.inputs.unwarp_direction=epi_params['enc_dir']
288+
thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'],
289+
name='RemoveNegative')
290+
268291
wf = pe.Workflow(name=name)
269292
wf.connect([
270-
(inputnode, pha2rads, [('bmap_pha', 'in_file')])
271-
,(inputnode, firstmag, [('bmap_mag', 'in_file')])
272-
,(inputnode, avg_b0, [('in_file', 'in_dwi'),
293+
(inputnode, pha2rads, [('bmap_pha', 'in_file')])
294+
,(inputnode, firstmag, [('bmap_mag', 'in_file')])
295+
,(inputnode, avg_b0, [('in_file', 'in_dwi'),
273296
('in_bval', 'in_bval')])
274-
,(firstmag, n4, [('roi_file', 'input_image')])
275-
,(n4, bet, [('output_image', 'in_file')])
276-
,(bet, dilate, [('mask_file', 'in_file')])
277-
,(pha2rads, prelude, [('out_file', 'phase_file')])
278-
,(n4, prelude, [('output_image', 'magnitude_file')])
279-
,(dilate, prelude, [('out_file', 'mask_file')])
280-
,(prelude, rad2rsec, [('unwrapped_phase_file', 'in_file')])
281-
282-
,(avg_b0, flirt, [('out_file', 'reference')])
283-
,(inputnode, flirt, [('in_mask', 'ref_weight')])
284-
,(n4, flirt, [('output_image', 'in_file')])
285-
,(dilate, flirt, [('out_file', 'in_weight')])
286-
287-
,(avg_b0, applyxfm, [('out_file', 'reference')])
288-
,(rad2rsec, applyxfm, [('out_file', 'in_file')])
289-
,(flirt, applyxfm, [('out_matrix_file', 'in_matrix_file')])
290-
291-
,(applyxfm, pre_fugue, [('out_file', 'fmap_in_file')])
292-
,(inputnode, pre_fugue, [('in_mask', 'mask_file')])
293-
294-
,(pre_fugue, demean, [('fmap_out_file', 'in_file')])
295-
,(inputnode, demean, [('in_mask', 'in_mask')])
296-
297-
,(demean, cleanup, [('out_file', 'inputnode.in_file')])
298-
,(inputnode, cleanup, [('in_mask', 'inputnode.in_mask')])
297+
,(firstmag, n4, [('roi_file', 'input_image')])
298+
,(n4, bet, [('output_image', 'in_file')])
299+
,(bet, dilate, [('mask_file', 'in_file')])
300+
,(pha2rads, prelude, [('out_file', 'phase_file')])
301+
,(n4, prelude, [('output_image', 'magnitude_file')])
302+
,(dilate, prelude, [('out_file', 'mask_file')])
303+
,(prelude, rad2rsec, [('unwrapped_phase_file', 'in_file')])
304+
,(avg_b0, flirt, [('out_file', 'reference')])
305+
,(inputnode, flirt, [('in_mask', 'ref_weight')])
306+
,(n4, flirt, [('output_image', 'in_file')])
307+
,(dilate, flirt, [('out_file', 'in_weight')])
308+
,(avg_b0, applyxfm, [('out_file', 'reference')])
309+
,(rad2rsec, applyxfm, [('out_file', 'in_file')])
310+
,(flirt, applyxfm, [('out_matrix_file', 'in_matrix_file')])
311+
,(applyxfm, pre_fugue, [('out_file', 'fmap_in_file')])
312+
,(inputnode, pre_fugue, [('in_mask', 'mask_file')])
313+
,(pre_fugue, demean, [('fmap_out_file', 'in_file')])
314+
,(inputnode, demean, [('in_mask', 'in_mask')])
315+
,(demean, cleanup, [('out_file', 'inputnode.in_file')])
316+
,(inputnode, cleanup, [('in_mask', 'inputnode.in_mask')])
317+
,(cleanup, addvol, [('outputnode.out_file', 'in_file')])
318+
,(inputnode, vsm, [('in_mask', 'mask_file')])
319+
,(addvol, vsm, [('out_file', 'fmap_in_file')])
320+
,(inputnode, split, [('in_file', 'in_file')])
321+
,(split, unwarp, [('out_files', 'in_file')])
322+
,(vsm, unwarp, [('shift_out_file', 'shift_in_file')])
323+
,(unwarp, thres, [('unwarped_file', 'in_file')])
324+
,(thres, merge, [('out_file', 'in_files')])
325+
,(merge, outputnode, [('merged_file', 'out_file')])
326+
,(vsm, outputnode, [('shift_out_file', 'out_vsm')])
299327
])
300328
return wf
301329

nipype/workflows/dmri/preprocess/utils.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# @Author: oesteban
66
# @Date: 2014-08-30 10:53:13
77
# @Last Modified by: oesteban
8-
# @Last Modified time: 2014-08-30 16:06:15
8+
# @Last Modified time: 2014-08-30 18:54:43
99

1010
def cleanup_edge_pipeline(name='Cleanup'):
1111
"""
@@ -190,9 +190,9 @@ def siemens2rads(in_file, out_file=None):
190190
hdr = im.get_header().copy()
191191

192192
if len(in_file) == 2:
193-
data = data - nb.load(in_file[1]).get_data().astype(np.float32)
193+
data = nb.load(in_file[1]).get_data().astype(np.float32) - data
194194
elif (data.ndim == 4) and (data.shape[-1] == 2):
195-
data = np.squeeze(data[...,0] - data[...,1])
195+
data = np.squeeze(data[...,1] - data[...,0])
196196
hdr.set_data_shape(data.shape[:3])
197197

198198
imin = data.min()
@@ -253,3 +253,25 @@ def demean_image(in_file, in_mask=None, out_file=None):
253253
data[msk==1] = data[msk==1] - mean
254254
nb.Nifti1Image(data, im.get_affine(), im.get_header()).to_filename(out_file)
255255
return out_file
256+
257+
258+
def add_empty_vol(in_file, out_file=None):
259+
"""
260+
Adds an empty vol to the phase difference image
261+
"""
262+
import nibabel as nb
263+
import os.path as op
264+
import numpy as np
265+
import math
266+
267+
if out_file is None:
268+
fname, fext = op.splitext(op.basename(in_file))
269+
if fext == '.gz':
270+
fname, _ = op.splitext(fname)
271+
out_file = op.abspath('./%s_4D.nii.gz' % fname)
272+
273+
im = nb.load(in_file)
274+
zim = nb.Nifti1Image(np.zeros_like(im.get_data()), im.get_affine(),
275+
im.get_header())
276+
nb.funcs.concat_images([im, zim]).to_filename(out_file)
277+
return out_file

0 commit comments

Comments
 (0)