@@ -233,6 +233,127 @@ def create_eddy_correct_pipeline(name="eddy_correct"):
233233 return pipeline
234234
235235
236+
237+
238+ def fieldmap_correction (name = "fieldmap_correction" ):
239+ """
240+ Fieldmap-based retrospective correction of EPI images for the susceptibility distortion
241+ artifact (Jezzard et al., 1995). Fieldmap images are assumed to be already registered
242+ to EPI data, and a brain mask is required.
243+
244+ Replaces the former workflow, still available as create_epidewarp_pipeline(). The difference
245+ with respect the epidewarp pipeline is that now the workflow uses the new fsl_prepare_fieldmap
246+ available as of FSL 5.0.
247+
248+
249+
250+ Example
251+ -------
252+
253+ >>> nipype_epicorrect = fieldmap_correction("nipype_epidewarp")
254+ >>> nipype_epicorrect.inputs.inputnode.in_file = 'diffusion.nii'
255+ >>> nipype_epicorrect.inputs.inputnode.in_mask = 'brainmask.nii'
256+ >>> nipype_epicorrect.inputs.inputnode.fieldmap_pha = 'phase.nii'
257+ >>> nipype_epicorrect.inputs.inputnode.fieldmap_mag = 'magnitude.nii'
258+ >>> nipype_epicorrect.inputs.inputnode.te_diff = 2.46
259+ >>> nipype_epicorrect.inputs.inputnode.epi_echospacing = 0.77
260+ >>> nipype_epicorrect.inputs.inputnode.pi_accel_factor = 1.0
261+ >>> nipype_epicorrect.inputs.inputnode.encoding_direction = 'y'
262+ >>> nipype_epicorrect.run() # doctest: +SKIP
263+
264+ Inputs::
265+
266+ inputnode.in_file - The volume acquired with EPI sequence
267+ inputnode.in_mask - A brain mask
268+ inputnode.fieldmap_pha - The phase difference map from the fieldmapping, registered to in_file
269+ inputnode.fieldmap_mag - The magnitud maps (usually 4D, one magnitude per GRE scan)
270+ from the fieldmapping, registered to in_file
271+ inputnode.te_diff - Time difference between TE in ms of the fieldmapping (usually a GRE sequence).
272+ inputnode.epi_echospacing - The echo spacing (aka dwell time) in the EPI sequence
273+ inputnode.encoding_dir - The phase encoding direction in EPI acquisition (default y)
274+ inputnode.pi_accel_factor - Acceleration factor used for EPI parallel imaging (GRAPPA)
275+ inputnode.vsm_sigma - Sigma value of the gaussian smoothing filter applied to the vsm (voxel shift map)
276+
277+
278+ Outputs::
279+
280+ outputnode.epi_corrected
281+
282+ """
283+
284+ inputnode = pe .Node (niu .IdentityInterface (
285+ fields = ["in_file" ,
286+ "in_mask" ,
287+ "fieldmap_pha" ,
288+ "fieldmap_mag" ,
289+ "te_diff" ,
290+ "epi_echospacing" ,
291+ "vsm_sigma" ,
292+ "encoding_direction"
293+ ]), name = "inputnode"
294+ )
295+
296+ pipeline = pe .Workflow (name = name )
297+
298+ # Keep first frame from magnitude
299+ select_mag = pe .Node (fsl .utils .ExtractROI (
300+ t_size = 1 , t_min = 0 ), name = "select_magnitude" )
301+
302+ # Mask magnitude (it is required by PreparedFieldMap)
303+ mask_mag = pe .Node ( fsl .maths .ApplyMask (), name = 'mask_magnitude' )
304+
305+ # Run fsl_prepare_fieldmap
306+ fslprep = pe .Node ( fsl .PrepareFieldmap (), name = "prepare_fieldmap" )
307+
308+ fill_phase = pe .Node (niu .Function (input_names = ["in_file" ], output_names = [
309+ "out_file" ], function = _fill_phase ), name = 'fill_phasediff' )
310+
311+ # Use FUGUE to generate the voxel shift map (vsm)
312+ vsm = pe .Node (fsl .FUGUE (save_shift = True ), name = "generate_vsm" )
313+
314+ # VSM demean is not anymore present in the epi_reg script
315+ #vsm_mean = pe.Node(niu.Function(input_names=["in_file", "mask_file", "in_unwarped"], output_names=[
316+ # "out_file"], function=_vsm_remove_mean), name="vsm_mean_shift")
317+
318+ # fugue_epi
319+ dwi_split = pe .Node (niu .Function (input_names = [
320+ 'in_file' ], output_names = ['out_files' ], function = _split_dwi ), name = 'dwi_split' )
321+
322+ # 'fugue -i %s -u %s --loadshift=%s --mask=%s' % ( vol_name, out_vol_name, vsm_name, mask_name )
323+ dwi_applyxfm = pe .MapNode (fsl .FUGUE (
324+ icorr = True , save_shift = False ), iterfield = ['in_file' ], name = 'dwi_fugue' )
325+ # Merge back all volumes
326+ dwi_merge = pe .Node (fsl .utils .Merge (
327+ dimension = 't' ), name = 'dwi_merge' )
328+
329+ outputnode = pe .Node (
330+ niu .IdentityInterface (fields = ["epi_corrected" ]),
331+ name = "outputnode" )
332+
333+ pipeline .connect ([
334+ (inputnode , select_mag , [('fieldmap_mag' , 'in_file' )])
335+ ,(inputnode , fslprep , [('fieldmap_pha' , 'in_phase' ),('te_diff' , 'delta_TE' ) ])
336+ ,(inputnode , mask_mag , [('in_mask' , 'mask_file' )])
337+ ,(select_mag , mask_mag , [('roi_file' , 'in_file' )])
338+ ,(mask_mag , fslprep , [('out_file' , 'in_magnitude' )])
339+ ,(inputnode , vsm , [('fieldmap_mag' , 'in_file' )])
340+ ,(fslprep , fill_phase , [('out_fieldmap' , 'in_file' )])
341+ ,(fill_phase , vsm , [('out_file' , 'phasemap_file' )])
342+ ,(inputnode , vsm , [(('te_diff' , _ms2sec ), 'asym_se_time' ), ('vsm_sigma' , 'smooth2d' ),
343+ (('epi_echospacing' , _ms2sec ), 'dwell_time' )])
344+ ,(mask_mag , vsm , [('out_file' , 'mask_file' )])
345+ ,(inputnode , dwi_split , [('in_file' , 'in_file' )])
346+ ,(dwi_split , dwi_applyxfm , [('out_files' , 'in_file' )])
347+ ,(mask_mag , dwi_applyxfm , [('out_file' , 'mask_file' )])
348+ ,(vsm , dwi_applyxfm , [('shift_out_file' , 'shift_in_file' )])
349+ ,(dwi_applyxfm , dwi_merge , [('unwarped_file' , 'in_files' )])
350+ ,(dwi_merge , outputnode , [('merged_file' , 'epi_corrected' )])
351+ ])
352+
353+
354+ return pipeline
355+
356+
236357def create_epidewarp_pipeline (name = "epidewarp" , fieldmap_registration = False ):
237358 """ Replaces the epidewarp.fsl script (http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl)
238359 for susceptibility distortion correction of dMRI & fMRI acquired with EPI sequences and the fieldmap
@@ -453,6 +574,10 @@ def _compute_dwelltime(dwell_time=0.68, pi_factor=1.0, is_reverse_encoding=False
453574
454575 return dwell_time
455576
577+ def _effective_echospacing ( dwell_time , pi_factor = 1.0 ):
578+ dwelltime = 1.0e-3 * dwelltime * ( 1.0 / pi_factor )
579+ return dwelltime
580+
456581
457582def _prepare_phasediff (in_file ):
458583 import nibabel as nib
@@ -500,7 +625,7 @@ def _fill_phase(in_file):
500625 name , fext = os .path .splitext (os .path .basename (in_file ))
501626 if fext == '.gz' :
502627 name , _ = os .path .splitext (name )
503- out_file = os .path .abspath ('./%s_phase_unwrapped .nii.gz' % name )
628+ out_file = os .path .abspath ('./%s_fill .nii.gz' % name )
504629 nib .save (out_nii , out_file )
505630 return out_file
506631
0 commit comments