Skip to content

Commit fc0d9bb

Browse files
committed
Let sdc_fmb suitable for both (d/f)MRI data
1 parent dc36fc9 commit fc0d9bb

File tree

2 files changed

+72
-21
lines changed

2 files changed

+72
-21
lines changed

nipype/workflows/dmri/fsl/artifacts.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,17 @@ def all_fmb_pipeline(name='hmc_sdc_ecc', fugue_params=dict(smooth3d=2.0)):
4646
outputnode = pe.Node(niu.IdentityInterface(
4747
fields=['out_file', 'out_mask', 'out_bvec']), name='outputnode')
4848

49+
list_b0 = pe.Node(niu.Function(
50+
input_names=['in_bval'], output_names=['out_idx'],
51+
function=b0_indices), name='B0indices')
52+
4953
avg_b0_0 = pe.Node(niu.Function(
50-
input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
51-
function=b0_average), name='b0_avg_pre')
54+
input_names=['in_file', 'index'], output_names=['out_file'],
55+
function=time_avg), name='b0_avg_pre')
5256
avg_b0_1 = pe.Node(niu.Function(
53-
input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
54-
function=b0_average), name='b0_avg_post')
57+
input_names=['in_file', 'index'], output_names=['out_file'],
58+
function=time_avg), name='b0_avg_post')
59+
5560
bet_dwi0 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
5661
name='bet_dwi_pre')
5762
bet_dwi1 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
@@ -67,24 +72,25 @@ def all_fmb_pipeline(name='hmc_sdc_ecc', fugue_params=dict(smooth3d=2.0)):
6772
(inputnode, hmc, [('in_file', 'inputnode.in_file'),
6873
('in_bvec', 'inputnode.in_bvec'),
6974
('in_bval', 'inputnode.in_bval')]),
70-
(inputnode, avg_b0_0, [('in_file', 'in_dwi'),
71-
('in_bval', 'in_bval')]),
75+
(inputnode, list_b0, [('in_bval', 'in_bval')]),
76+
(inputnode, avg_b0_0, [('in_file', 'in_file')]),
77+
(list_b0, avg_b0_0, [('out_idx', 'index')]),
7278
(avg_b0_0, bet_dwi0, [('out_file', 'in_file')]),
7379
(bet_dwi0, hmc, [('mask_file', 'inputnode.in_mask')]),
7480
(hmc, sdc, [
7581
('outputnode.out_file', 'inputnode.in_file')]),
7682
(bet_dwi0, sdc, [('mask_file', 'inputnode.in_mask')]),
77-
(inputnode, sdc, [('in_bval', 'inputnode.in_bval'),
78-
('bmap_pha', 'inputnode.bmap_pha'),
83+
(inputnode, sdc, [('bmap_pha', 'inputnode.bmap_pha'),
7984
('bmap_mag', 'inputnode.bmap_mag'),
8085
('epi_param', 'inputnode.settings')]),
86+
(list_b0, sdc, [('out_idx', 'inputnode.in_ref')]),
8187
(hmc, ecc, [
8288
('outputnode.out_xfms', 'inputnode.in_xfms')]),
8389
(inputnode, ecc, [('in_file', 'inputnode.in_file'),
8490
('in_bval', 'inputnode.in_bval')]),
8591
(bet_dwi0, ecc, [('mask_file', 'inputnode.in_mask')]),
86-
(ecc, avg_b0_1, [('outputnode.out_file', 'in_dwi')]),
87-
(inputnode, avg_b0_1, [('in_bval', 'in_bval')]),
92+
(ecc, avg_b0_1, [('outputnode.out_file', 'in_file')]),
93+
(list_b0, avg_b0_1, [('out_idx', 'index')]),
8894
(avg_b0_1, bet_dwi1, [('out_file', 'in_file')]),
8995
(inputnode, unwarp, [('in_file', 'inputnode.in_dwi')]),
9096
(hmc, unwarp, [('outputnode.out_xfms', 'inputnode.in_hmc')]),
@@ -529,7 +535,7 @@ def sdc_fmb(name='fmb_correction', interp='Linear',
529535
>>> from nipype.workflows.dmri.fsl.artifacts import sdc_fmb
530536
>>> fmb = sdc_fmb()
531537
>>> fmb.inputs.inputnode.in_file = 'diffusion.nii'
532-
>>> fmb.inputs.inputnode.in_bval = 'diffusion.bval'
538+
>>> fmb.inputs.inputnode.in_ref = range(0, 30, 6)
533539
>>> fmb.inputs.inputnode.in_mask = 'mask.nii'
534540
>>> fmb.inputs.inputnode.bmap_mag = 'magnitude.nii'
535541
>>> fmb.inputs.inputnode.bmap_pha = 'phase.nii'
@@ -555,7 +561,7 @@ def sdc_fmb(name='fmb_correction', interp='Linear',
555561
'acc_factor': 2, 'enc_dir': u'AP'}
556562

557563
inputnode = pe.Node(niu.IdentityInterface(
558-
fields=['in_file', 'in_bval', 'in_mask', 'bmap_pha', 'bmap_mag',
564+
fields=['in_file', 'in_ref', 'in_mask', 'bmap_pha', 'bmap_mag',
559565
'settings']), name='inputnode')
560566

561567
outputnode = pe.Node(niu.IdentityInterface(
@@ -580,9 +586,9 @@ def sdc_fmb(name='fmb_correction', interp='Linear',
580586
input_names=['in_file', 'delta_te'], output_names=['out_file'],
581587
function=rads2radsec), name='ToRadSec')
582588

583-
avg_b0 = pe.Node(niu.Function(
584-
input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
585-
function=b0_average), name='b0_avg')
589+
baseline = pe.Node(niu.Function(
590+
input_names=['in_file', 'index'], output_names=['out_file'],
591+
function=time_avg), name='Baseline')
586592

587593
fmm2b0 = pe.Node(ants.Registration(output_warped_image=True),
588594
name="FMm_to_B0")
@@ -639,8 +645,8 @@ def sdc_fmb(name='fmb_correction', interp='Linear',
639645
('acc_factor', 'acc_factor')]),
640646
(inputnode, pha2rads, [('bmap_pha', 'in_file')]),
641647
(inputnode, firstmag, [('bmap_mag', 'in_file')]),
642-
(inputnode, avg_b0, [('in_file', 'in_dwi'),
643-
('in_bval', 'in_bval')]),
648+
(inputnode, baseline, [('in_file', 'in_file'),
649+
('in_ref', 'index')]),
644650
(firstmag, n4, [('roi_file', 'input_image')]),
645651
(n4, bet, [('output_image', 'in_file')]),
646652
(bet, dilate, [('mask_file', 'in_file')]),
@@ -650,12 +656,12 @@ def sdc_fmb(name='fmb_correction', interp='Linear',
650656
(r_params, rad2rsec, [('delta_te', 'delta_te')]),
651657
(prelude, rad2rsec, [('unwrapped_phase_file', 'in_file')]),
652658

653-
(avg_b0, fmm2b0, [('out_file', 'fixed_image')]),
659+
(baseline, fmm2b0, [('out_file', 'fixed_image')]),
654660
(n4, fmm2b0, [('output_image', 'moving_image')]),
655661
(inputnode, fmm2b0, [('in_mask', 'fixed_image_mask')]),
656662
(dilate, fmm2b0, [('out_file', 'moving_image_mask')]),
657663

658-
(avg_b0, applyxfm, [('out_file', 'reference_image')]),
664+
(baseline, applyxfm, [('out_file', 'reference_image')]),
659665
(rad2rsec, applyxfm, [('out_file', 'input_image')]),
660666
(fmm2b0, applyxfm, [
661667
('forward_transforms', 'transforms'),

nipype/workflows/dmri/fsl/utils.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,51 @@ def recompose_xfm(in_bval, in_xfms):
381381
return out_files
382382

383383

384+
def time_avg(in_file, index=[0], out_file=None):
385+
"""
386+
Average the input time-series, selecting the indices given in index
387+
388+
.. warning:: time steps should be already registered (corrected for
389+
head motion artifacts).
390+
391+
"""
392+
import numpy as np
393+
import nibabel as nb
394+
import os.path as op
395+
396+
if out_file is None:
397+
fname, ext = op.splitext(op.basename(in_file))
398+
if ext == ".gz":
399+
fname, ext2 = op.splitext(fname)
400+
ext = ext2 + ext
401+
out_file = op.abspath("%s_baseline%s" % (fname, ext))
402+
403+
index = np.atleast_1d(index).tolist()
404+
405+
imgs = np.array(nb.four_to_three(nb.load(in_file)))[index]
406+
if len(index) == 1:
407+
data = imgs[0].get_data().astype(np.float32)
408+
else:
409+
data = np.average(np.array([im.get_data().astype(np.float32) for im in imgs]),
410+
axis=0)
411+
412+
hdr = imgs[0].get_header().copy()
413+
hdr.set_data_shape(data.shape)
414+
hdr.set_xyzt_units('mm')
415+
hdr.set_data_dtype(np.float32)
416+
nb.Nifti1Image(data, imgs[0].get_affine(), hdr).to_filename(out_file)
417+
return out_file
418+
419+
420+
def b0_indices(in_bval, max_b=10.0):
421+
"""
422+
Extract the indices of slices in a b-values file with a low b value
423+
"""
424+
import numpy as np
425+
bval = np.loadtxt(in_bval)
426+
return np.argwhere(bval <= max_b).flatten().tolist()
427+
428+
384429
def b0_average(in_dwi, in_bval, max_b=10.0, out_file=None):
385430
"""
386431
A function that averages the *b0* volumes from a DWI dataset.
@@ -403,9 +448,9 @@ def b0_average(in_dwi, in_bval, max_b=10.0, out_file=None):
403448
out_file = op.abspath("%s_avg_b0%s" % (fname, ext))
404449

405450
imgs = np.array(nb.four_to_three(nb.load(in_dwi)))
406-
bval = np.loadtxt(in_bval)
451+
index = b0_indices(in_bval, max_b=max_b)
407452
b0s = [im.get_data().astype(np.float32)
408-
for im in imgs[np.where(bval <= max_b)]]
453+
for im in imgs[index]]
409454
b0 = np.average(np.array(b0s), axis=0)
410455

411456
hdr = imgs[0].get_header().copy()

0 commit comments

Comments
 (0)