Skip to content

Commit 682e60d

Browse files
committed
Replace MCFLIRT with 3dVolReg
1 parent d1e2004 commit 682e60d

File tree

4 files changed

+74
-17
lines changed

4 files changed

+74
-17
lines changed

fmriprep/utils/misc.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,58 @@
77
"""
88

99

10+
def split_and_deoblique_func(in_file):
11+
import os
12+
from nilearn.image import iter_img
13+
import nibabel as nb
14+
import numpy as np
15+
out_files = []
16+
for i, img in enumerate(iter_img(in_file)):
17+
out_file = os.path.abspath('vol%04d.nii.gz'%i)
18+
affine = img.affine
19+
affine[:3,:3] = np.diag(np.diag(affine[:3, :3]))
20+
nb.Nifti1Image(np.asanyarray(img.dataobj), affine, img.header).to_filename(out_file)
21+
out_files.append(out_file)
22+
return out_files
23+
24+
25+
def afni2itk_func(in_file):
26+
import os
27+
from scipy.io import loadmat, savemat
28+
from numpy import loadtxt, around, hstack, vstack, zeros, float64
29+
30+
def read_afni_affine(input_file, debug=False):
31+
orig_afni_mat = loadtxt(input_file)
32+
if debug:
33+
print(orig_afni_mat)
34+
35+
output = []
36+
for i in range(orig_afni_mat.shape[0]):
37+
output.append(vstack((orig_afni_mat[i,:].reshape(3, 4, order='C'), [0, 0, 0, 1])))
38+
return output
39+
40+
def get_ants_dict(affine, debug=False):
41+
out_dict = {}
42+
out_dict['AffineTransform_double_3_3'] = hstack(
43+
(affine[:3, :3].reshape(1, -1), affine[:3, 3].reshape(1, -1))).reshape(-1, 1).astype(float64)
44+
out_dict['fixed'] = zeros((3, 1))
45+
if debug:
46+
print(out_dict)
47+
48+
return out_dict
49+
50+
out_file = os.path.abspath('mc4d.txt')
51+
with open(out_file, 'w') as fp:
52+
fp.write("#Insight Transform File V1.0\n")
53+
for i, affine in enumerate(read_afni_affine(in_file)):
54+
fp.write("#Transform %d\n"%i)
55+
fp.write("Transform: AffineTransform_double_3_3\n")
56+
trans_dict = get_ants_dict(affine)
57+
fp.write("Parameters: " + ' '.join(["%g"%i for i in list(trans_dict['AffineTransform_double_3_3'])]) + "\n")
58+
fp.write("FixedParameters: " + ' '.join(["%g"%i for i in list(trans_dict['fixed'])]) + "\n")
59+
return out_file
60+
61+
1062
def fix_multi_T1w_source_name(in_files):
1163
"""
1264
Make up a generic source name when there are multiple T1s

fmriprep/workflows/bold/base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from nipype.pipeline import engine as pe
2020
from nipype.interfaces import utility as niu
2121

22+
from fmriprep.utils.misc import split_and_deoblique_func
2223
from ...interfaces import (
2324
DerivativesDataSink,
2425
GiftiNameSource,
@@ -371,7 +372,8 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
371372
omp_nthreads=omp_nthreads, enhance_t2=True)
372373

373374
# Top-level BOLD splitter
374-
bold_split = pe.Node(FSLSplit(dimension='t'), name='bold_split',
375+
bold_split = pe.Node(niu.Function(function=split_and_deoblique_func, input_names=['in_file'],
376+
output_names=['out_files']), name='bold_split',
375377
mem_gb=mem_gb['filesize'] * 3)
376378

377379
# HMC on the BOLD

fmriprep/workflows/bold/hmc.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
"""
1111

1212
from nipype.pipeline import engine as pe
13-
from nipype.interfaces import utility as niu, fsl
13+
from nipype.interfaces import utility as niu, fsl, afni
1414
from niworkflows.interfaces import NormalizeMotionParams
15+
from fmriprep.utils.misc import afni2itk_func
1516
from ...engine import Workflow
1617
from ...interfaces import MCFLIRT2ITK
1718

@@ -73,24 +74,24 @@ def init_bold_hmc_wf(mem_gb, omp_nthreads, name='bold_hmc_wf'):
7374
name='outputnode')
7475

7576
# Head motion correction (hmc)
76-
mcflirt = pe.Node(fsl.MCFLIRT(save_mats=True, save_plots=True),
77-
name='mcflirt', mem_gb=mem_gb * 3)
77+
mc = pe.Node(afni.Volreg(args='-prefix NULL -twopass',
78+
zpad=4, outputtype='NIFTI_GZ'), name="mc", mem_gb=mem_gb * 3)
7879

79-
fsl2itk = pe.Node(MCFLIRT2ITK(), name='fsl2itk',
80-
mem_gb=0.05, n_procs=omp_nthreads)
80+
afni2itk = pe.Node(niu.Function(function=afni2itk_func,
81+
input_names=["in_file"],
82+
output_names=["out_files"]), name='afni2itk',
83+
mem_gb=0.05)
8184

82-
normalize_motion = pe.Node(NormalizeMotionParams(format='FSL'),
85+
normalize_motion = pe.Node(NormalizeMotionParams(format='AFNI'),
8386
name="normalize_motion",
8487
mem_gb=DEFAULT_MEMORY_MIN_GB)
8588

8689
workflow.connect([
87-
(inputnode, mcflirt, [('raw_ref_image', 'ref_file'),
88-
('bold_file', 'in_file')]),
89-
(inputnode, fsl2itk, [('raw_ref_image', 'in_source'),
90-
('raw_ref_image', 'in_reference')]),
91-
(mcflirt, fsl2itk, [('mat_file', 'in_files')]),
92-
(mcflirt, normalize_motion, [('par_file', 'in_file')]),
93-
(fsl2itk, outputnode, [('out_file', 'xforms')]),
90+
(inputnode, mc, [('raw_ref_image', 'basefile'),
91+
('bold_file', 'in_file')]),
92+
(mc, afni2itk, [('oned_matrix_save', 'in_file')]),
93+
(mc, normalize_motion, [('oned_file', 'in_file')]),
94+
(afni2itk, outputnode, [('out_files', 'xforms')]),
9495
(normalize_motion, outputnode, [('out_file', 'movpar_file')]),
9596
])
9697

fmriprep/workflows/bold/util.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,18 @@ def init_bold_reference_wf(omp_nthreads, bold_file=None, name='bold_reference_wf
102102

103103
gen_ref = pe.Node(EstimateReferenceImage(), name="gen_ref",
104104
mem_gb=1) # OE: 128x128x128x50 * 64 / 8 ~ 900MB.
105+
deoblique = pe.Node(afni.Refit(deoblique=True), name='deoblique')
105106
enhance_and_skullstrip_bold_wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=omp_nthreads)
106107

107108
workflow.connect([
108109
(inputnode, validate, [('bold_file', 'in_file')]),
109110
(validate, gen_ref, [('out_file', 'in_file')]),
110-
(gen_ref, enhance_and_skullstrip_bold_wf, [('ref_image', 'inputnode.in_file')]),
111+
(gen_ref, deoblique, [('ref_image', 'in_file')]),
112+
(deoblique, enhance_and_skullstrip_bold_wf, [('out_file', 'inputnode.in_file')]),
111113
(validate, outputnode, [('out_file', 'bold_file'),
112114
('out_report', 'validation_report')]),
113-
(gen_ref, outputnode, [('ref_image', 'raw_ref_image'),
114-
('n_volumes_to_discard', 'skip_vols')]),
115+
(deoblique, outputnode, [('out_file', 'raw_ref_image')]),
116+
(gen_ref, outputnode, [('n_volumes_to_discard', 'skip_vols')]),
115117
(enhance_and_skullstrip_bold_wf, outputnode, [
116118
('outputnode.bias_corrected_file', 'ref_image'),
117119
('outputnode.mask_file', 'bold_mask'),

0 commit comments

Comments
 (0)