Skip to content

Commit 04c568c

Browse files
committed
Added motion correction pipeline
* Added motion correction pipeline, rotating the b-matrix * Some minor fixes on the rest of pipelines
1 parent 6608524 commit 04c568c

File tree

2 files changed

+136
-20
lines changed

2 files changed

+136
-20
lines changed

nipype/workflows/dmri/fsl/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from dti import create_bedpostx_pipeline, create_eddy_correct_pipeline, create_epi_correct_pipeline
1+
from dti import create_bedpostx_pipeline, create_eddy_correct_pipeline, create_susceptibility_correct_pipeline
22
from tbss import (create_tbss_1_preproc, create_tbss_2_reg,
33
create_tbss_3_postreg, create_tbss_4_prestats,
44
create_tbss_all, create_tbss_non_FA)

nipype/workflows/dmri/fsl/dti.py

Lines changed: 135 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,41 @@ 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"):
16+
"""Creates a workflow that chains the necessary pipelines to
17+
correct for motion, eddy currents, and susceptibility
18+
artifacts in EPI dMRI sequences.
19+
20+
Example
21+
-------
22+
23+
>>> 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. =
32+
>>> nipype_dmri_preprocess.run() # doctest: +SKIP
33+
34+
Inputs::
35+
36+
inputnode.
37+
38+
Outputs::
39+
40+
outputnode.dmri_corrected
41+
42+
"""
43+
44+
pipeline = pe.Workflow(name=name)
45+
46+
return pipeline
47+
48+
49+
1550
def create_bedpostx_pipeline(name="bedpostx"):
1651
"""Creates a pipeline that does the same as bedpostx script from FSL -
1752
calculates diffusion model parameters (distributions not MLE) voxelwise for
@@ -168,6 +203,61 @@ def create_bedpostx_pipeline(name="bedpostx"):
168203
])
169204
return bedpostx
170205

206+
def create_motion_correct_pipeline(name="motion_correct"):
207+
"""Creates a pipeline that corrects for motion artifact in dMRI sequences.
208+
It takes a series of diffusion weighted images and rigidly corregisters
209+
them to one reference image. Finally, the b-matrix is rotated accordingly,
210+
making use of the rotation matrix obtained by FLIRT.
211+
212+
Example
213+
-------
214+
215+
>>> nipype_motioncorrect = create_motion_correct_pipeline("nipype_motioncorrect")
216+
>>> nipype_motioncorrect.inputs.inputnode.in_file = 'diffusion.nii'
217+
>>> nipype_motioncorrect.inputs.inputnode.in_bvec = 'diffusion.bvec'
218+
>>> nipype_motioncorrect.inputs.inputnode.ref_num = 0
219+
>>> nipype_motioncorrect.run() # doctest: +SKIP
220+
221+
Inputs::
222+
223+
inputnode.in_file
224+
inputnode.ref_num
225+
inputnode.in_bvec
226+
227+
Outputs::
228+
229+
outputnode.motion_corrected
230+
"""
231+
232+
inputnode = pe.Node(interface = util.IdentityInterface(fields=["in_file", "ref_num","in_bvec"]),
233+
name="inputnode")
234+
235+
pipeline = pe.Workflow(name=name)
236+
237+
split = pe.Node(fsl.Split(dimension='t'), name="split")
238+
pick_ref = pe.Node(util.Select(), name="pick_ref")
239+
coregistration = pe.MapNode(fsl.FLIRT(no_search=True, padding_size=1, dof=6), name = "coregistration", iterfield=["in_file"])
240+
rotate_bvecs = pe.Node( util.Function( input_names=["in_bvec", "in_matrix"], output_names=["out_file"], function=_rotate_bvecs ), name="rotate_b_matrix" )
241+
merge = pe.Node(fsl.Merge(dimension="t"), name="merge")
242+
outputnode = pe.Node(interface = util.IdentityInterface(fields=["motion_corrected","out_bvec"]),
243+
name="outputnode")
244+
245+
pipeline.connect([
246+
(inputnode, split, [("in_file", "in_file")])
247+
,(split, pick_ref, [("out_files", "inlist")])
248+
,(inputnode, pick_ref, [("ref_num", "index")])
249+
,(split, coregistration, [("out_files", "in_file")])
250+
,(inputnode, rotate_bvecs, [("in_bvec","in_bvec")])
251+
,(coregistration, rotate_bvecs, [("out_matrix_file","in_matrix")])
252+
,(pick_ref, coregistration, [("out", "reference")])
253+
,(coregistration, merge, [("out_file", "in_files")])
254+
,(merge, outputnode, [("merged_file", "motion_corrected")])
255+
,(rotate_bvecs, outputnode, [("out_file","out_bvec")])
256+
])
257+
258+
return pipeline
259+
260+
171261
def create_eddy_correct_pipeline(name="eddy_correct"):
172262
"""Creates a pipeline that replaces eddy_correct script in FSL. It takes a
173263
series of diffusion weighted images and linearly corregisters them to one
@@ -197,30 +287,26 @@ def create_eddy_correct_pipeline(name="eddy_correct"):
197287
pipeline = pe.Workflow(name=name)
198288

199289
split = pe.Node(fsl.Split(dimension='t'), name="split")
200-
pipeline.connect([(inputnode, split, [("in_file", "in_file")])])
201-
202290
pick_ref = pe.Node(util.Select(), name="pick_ref")
203-
pipeline.connect([(split, pick_ref, [("out_files", "inlist")]),
204-
(inputnode, pick_ref, [("ref_num", "index")])])
205-
206-
coregistration = pe.MapNode(fsl.FLIRT(no_search=True, padding_size=1), name = "coregistration", iterfield=["in_file"])
207-
pipeline.connect([(split, coregistration, [("out_files", "in_file")]),
208-
(pick_ref, coregistration, [("out", "reference")])])
209-
291+
coregistration = pe.MapNode(fsl.FLIRT(no_search=True, padding_size=1 ), name = "coregistration", iterfield=["in_file"])
210292
merge = pe.Node(fsl.Merge(dimension="t"), name="merge")
211-
pipeline.connect([(coregistration, merge, [("out_file", "in_files")])
212-
])
213-
214293
outputnode = pe.Node(interface = util.IdentityInterface(fields=["eddy_corrected"]),
215294
name="outputnode")
216295

217-
pipeline.connect([(merge, outputnode, [("merged_file", "eddy_corrected")])])
218-
296+
pipeline.connect([
297+
(inputnode, split, [("in_file", "in_file")])
298+
,(split, pick_ref, [("out_files", "inlist")])
299+
,(inputnode, pick_ref, [("ref_num", "index")])
300+
,(split, coregistration, [("out_files", "in_file")])
301+
,(pick_ref, coregistration, [("out", "reference")])
302+
,(coregistration, merge, [("out_file", "in_files")])
303+
,(merge, outputnode, [("merged_file", "eddy_corrected")])
304+
])
219305
return pipeline
220306

221-
def create_epi_correct_pipeline(name="epi_correct", register_to_ref=False ):
307+
def create_susceptibility_correct_pipeline(name="susceptibility_correct", register_to_ref=False ):
222308
""" Replaces the epidewarp.fsl script (http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl)
223-
for EPI distortion correction with the fieldmap information in
309+
for susceptibility distortion correction in EPI sequences with the fieldmap information in
224310
dMRI and fMRI (Jezzard et al., MRM 1995 ) using FSL's FUGUE.
225311
226312
Example
@@ -271,9 +357,6 @@ def create_epi_correct_pipeline(name="epi_correct", register_to_ref=False ):
271357

272358
pipeline = pe.Workflow(name=name)
273359

274-
275-
matrix_file = os.path.abspath( './flirt.txt' )
276-
277360
# Keep first frame from magnitude
278361
select_mag = pe.Node( interface=fsl.utils.ExtractROI(t_size=1,t_min=0), name="select_magnitude" )
279362

@@ -372,6 +455,39 @@ def create_epi_correct_pipeline(name="epi_correct", register_to_ref=False ):
372455

373456
return pipeline
374457

458+
def _rotate_bvecs( in_bvec, in_matrix ):
459+
import os
460+
import numpy as np
461+
462+
name,fext = os.path.splitext( os.path.basename(in_bvec) )
463+
if fext == '.gz': name,_ = os.path.splitext(name)
464+
out_file = os.path.abspath( './%s_rotated.bvec' % name )
465+
bvecs = np.loadtxt( in_bvec )
466+
new_bvecs = [ bvecs[:,0] ]
467+
468+
for i,vol_matrix in enumerate(in_matrix[1::]):
469+
bvec = np.matrix( bvecs[:,i] )
470+
rot = np.matrix(np.loadtxt( vol_matrix )[0:3,0:3])
471+
new_bvecs.append( (np.array( rot * bvec.T).T)[0] )
472+
np.savetxt( out_file, np.array(new_bvecs).T, fmt='%0.15f' )
473+
return out_file
474+
475+
def _cat_logs( in_files ):
476+
import shutil
477+
import os
478+
479+
name,fext = os.path.splitext( os.path.basename(in_files[0]) )
480+
if fext == '.gz': name,_ = os.path.splitext(name)
481+
out_file = os.path.abspath( './%s_ecclog.log' % name )
482+
out_str = ""
483+
with open( out_file, 'wb' ) as totallog:
484+
for i,fname in enumerate(in_files):
485+
totallog.write( "\n\npreprocessing %d\n" % i )
486+
with open(fname) as inlog:
487+
for line in inlog:
488+
totallog.write(line)
489+
return out_file
490+
375491
def _compute_dwelltime( dwell_time=0.68, is_parallel=False, is_reverse_encoding=False ):
376492
if is_parallel:
377493
dwell_time*=0.5

0 commit comments

Comments
 (0)