def eddy_fsl_pipeline(epi_param, name="eddy_fsl"): """ Using eddy from fsl for head motion correction and eddy current distortion correction. """ import nipype.interfaces.utility as niu # utility import nipype.pipeline.engine as pe # pypeline engine from nipype.interfaces.fsl import Eddy from clinica.pipelines.dwi_preprocessing_using_t1.dwi_preprocessing_using_t1_utils import ( b0_indices, eddy_fsl, generate_acq, generate_index, ) inputnode = pe.Node( niu.IdentityInterface( fields=["in_file", "in_bvec", "in_bval", "in_mask", "ref_b0"]), name="inputnode", ) generate_acq = pe.Node( niu.Function( function=generate_acq, input_names=["in_b0", "epi_param"], output_names=["out_file"], ), name="generate_acq", ) generate_acq.inputs.epi_param = epi_param list_b0 = pe.Node( niu.Function(input_names=["in_bval"], output_names=["out_idx"], function=b0_indices), name="find_b0_indices", ) generate_index = pe.Node( niu.Function( function=generate_index, input_names=["in_bval", "b0_index"], output_names=["eddy_index"], ), name="generate_index", ) eddy = pe.Node( niu.Function( input_names=[ "in_bvec", "in_bval", "in_file", "in_mask", "in_acqp", "in_index", ], output_names=[ "out_parameter", "out_corrected", "out_rotated_bvecs" ], function=eddy_fsl, ), name="eddy_fsl", ) eddy = pe.Node(interface=Eddy(), name="eddy_fsl") eddy.inputs.flm = "linear" outputnode = pe.Node( niu.IdentityInterface( fields=["out_parameter", "out_corrected", "out_rotated_bvecs"]), name="outputnode", ) wf = pe.Workflow(name=name) wf.connect([ (inputnode, generate_acq, [("ref_b0", "in_b0")]), (inputnode, generate_index, [("in_bval", "in_bval")]), (list_b0, generate_index, [("out_idx", "b0_index")]), (inputnode, list_b0, [("in_bval", "in_bval")]), (inputnode, eddy, [("in_bvec", "in_bvec")]), (inputnode, eddy, [("in_bval", "in_bval")]), (inputnode, eddy, [("in_file", "in_file")]), (inputnode, eddy, [("in_mask", "in_mask")]), (generate_acq, eddy, [("out_file", "in_acqp")]), (generate_index, eddy, [("eddy_index", "in_index")]), (eddy, outputnode, [("out_parameter", "out_parameter")]), (eddy, outputnode, [("out_corrected", "out_corrected")]), (eddy, outputnode, [("out_rotated_bvecs", "out_rotated_bvecs")]), ]) return wf
def __init__(self, parent, dir_dic, bids): super().__init__(parent, dir_dic, bids) # Create interfaces ============================================================================================ # BET T1w_BET = Node(BET(), name="T1w_BET") T1w_BET.btn_string = 'T1w Brain Extraction' self.interfaces.append(T1w_BET) T1w_gad_BET = Node(BET(), name="T1w_gad_BET") T1w_gad_BET.btn_string = 'T1w Gadolinium Enhanced Brain Extraction' self.interfaces.append(T1w_gad_BET) T2w_dbs_BET = Node(BET(), name="T2w_dbs_BET") T2w_dbs_BET.btn_string = 'T2w DBS Acquisition Brain Extraction' self.interfaces.append(T2w_dbs_BET) dwi_BET = Node(BET(), name="dwi_BET") dwi_BET.btn_string = 'dwi Brain Extraction' self.interfaces.append(dwi_BET) # BFC T1w_BFC = Node(N4BiasFieldCorrection(), name="T1w_BFC") T1w_BFC.btn_string = 'T1w Bias Field Correction' self.interfaces.append(T1w_BFC) # Split dwi_ROI_b0 = Node(ExtractROI(), name="dwi_ROI_b0") dwi_ROI_b0.btn_string = 'dwi Extract b0' self.interfaces.append(dwi_ROI_b0) # Eddy current correction dwi_Eddy = Node(Eddy(), name="dwi_Eddy") dwi_Eddy.btn_string = 'dwi Eddy Current Correction' self.interfaces.append(dwi_Eddy) # Distortion correction # as this section is script/comment heavy it was put into a function self.distortion_correction_workflow() # Data output (i.e. sink) ====================================================================================== self.sink = Node(DataSink(), name="sink") self.sink.btn_string = 'data sink' self.sink.inputs.base_directory = self.dir_dic['data_dir'] self.jsink = Node(JSONFileSink(), name="jsink") self.jsink.btn_string = 'json sink' self.jsink.inputs.base_directory = self.dir_dic['data_dir'] # Initialize workflow ========================================================================================== self.wf = Workflow(name='pre_processing') # T1w BET to ants N4BiasFieldCorrection self.wf.connect([(self.return_interface("T1w_BET"), self.return_interface("T1w_BFC"), [("out_file", "input_image")])]) self.wf.connect([(self.return_interface("T1w_BET"), self.return_interface("T1w_BFC"), [("mask_file", "mask_image")])]) # Eddy self.wf.connect([(self.return_interface("dwi_BET"), self.return_interface("dwi_Eddy"), [("out_file", "in_file")])]) self.wf.connect([(self.return_interface("dwi_BET"), self.return_interface("dwi_Eddy"), [("mask_file", "in_mask")])]) # ROI b0 self.wf.connect([(self.return_interface("dwi_Eddy"), self.return_interface("dwi_ROI_b0"), [("out_corrected", "in_file")])]) # Distortion Correction: # b0_T1_Reg: # -i: moving image # -r: T1 # -x: T1 mask self.wf.connect([(self.return_interface("dwi_ROI_b0"), self.return_interface("b0_T1w_Reg"), [("roi_file", "moving_image")])]) self.wf.connect([(self.return_interface("T1w_BFC"), self.return_interface("b0_T1w_Reg"), [("output_image", "fixed_image")])]) # test remove as doesn't seem useful (see self.distortion_correction_workflow()) and causes a crash when added # self.wf.connect([(self.return_interface("T1w_BET"), self.return_interface("b0_T1w_Reg"), # [("mask_file", "fixed_image_mask")])]) # dwi_T1_Tran: # -i: Eddy corrected image # -r: Eddy corrected b0 # -t: transforms self.wf.connect([(self.return_interface("dwi_Eddy"), self.return_interface("dwi_T1w_Tran"), [("out_corrected", "input_image")])]) self.wf.connect([(self.return_interface("dwi_ROI_b0"), self.return_interface("dwi_T1w_Tran"), [("roi_file", "reference_image")])]) self.wf.connect([(self.return_interface("b0_T1w_Reg"), self.return_interface("dwi_T1w_Tran"), [("composite_transform", "transforms")])]) # BaseInterface generates a dict mapping button strings to the workflow nodes # self.map_workflow() graph_file = self.wf.write_graph("pre_processing", graph2use='flat') self.graph_file = graph_file.replace("pre_processing.png", "pre_processing_detailed.png") self.init_settings() self.init_ui()
import os from os.path import abspath from datetime import datetime from IPython.display import Image import pydot from nipype import Workflow, Node, MapNode, Function, config from nipype.interfaces.fsl import TOPUP, ApplyTOPUP, BET, ExtractROI, Eddy, FLIRT, FUGUE from nipype.interfaces.fsl.maths import MathsCommand import nipype.interfaces.utility as util import nipype.interfaces.mrtrix3 as mrt #Requirements for the workflow to run smoothly: All files as in NIfTI-format and named according to the following standard: #Images are from the tonotopy DKI sequences on the 7T Philips Achieva scanner in Lund. It should work with any DKI sequence and possibly also a standard DTI but the setting for B0-corrections, epi-distortion corrections and eddy current corrections will be wrong. #DKI file has a base name shared with bvec and bval in FSL format. E.g. "DKI.nii.gz" "DKI.bvec" and "DKI.bval". #There is one b0-volume with reversed (P->A) phase encoding called DKIbase+_revenc. E.g. "DKI_revenc.nii.gz". #Philips B0-map magnitude and phase offset (in Hz) images. #One input file for topup describing the images as specified by topup. #Set nbrOfThreads to number of available CPU threads to run the analyses. ### Need to make better revenc for the 15 version if we choose to use it (i.e. same TE and TR) #Set to relevant directory/parameters datadir=os.path.abspath("/Users/ling-men/Documents/MRData/testDKI") rawDKI_base='DKI_15' B0map_base = 'B0map' nbrOfThreads=6 print_graph = True acqparam_file = os.path.join(datadir,'acqparams.txt') index_file = os.path.join(datadir,'index.txt') #### #config.enable_debug_mode() DKI_nii=os.path.join(datadir, rawDKI_base+'.nii.gz') DKI_bval=os.path.join(datadir, rawDKI_base+'.bval')
"binary_maths": {BinaryMaths().version: BinaryMaths}, "BET": {BET().version: BET}, "CAT12 Segmentation": {"12.7": Cat12Segmentation}, "fslmerge": {Merge().version: Merge}, "fslreorient2std": {Reorient2Std().version: Reorient2Std}, "fslroi": {ExtractROI().version: ExtractROI}, "FAST": {FastWrapper.version: FastWrapper}, "FLIRT": {FLIRT().version: FLIRT}, "FNIRT": {FNIRT().version: FNIRT}, "FSL Anatomical Processing Script": {FslAnat.__version__: FslAnat}, "mean_image": {MeanImage().version: MeanImage}, "robustfov": {RobustFOV().version: RobustFOV}, "ReconAll": {ReconAll().version: ReconAll}, "SUSAN": {SUSAN().version: SUSAN}, "topup": {TopupWrapper.version: TopupWrapper}, "eddy": {Eddy().version: Eddy}, "denoise": {DWIDenoise().version: DWIDenoise}, "degibbs": {MRDeGibbs().version: MRDeGibbs}, "bias_correct": {DWIBiasCorrect().version: DWIBiasCorrect}, "dwifslpreproc": {DwiFslPreproc.__version__: DwiFslPreproc}, "mrconvert": {MRConvert.__version__: MRConvert}, "dwi2fod": { ConstrainedSphericalDeconvolution().version: ConstrainedSphericalDeconvolution # noqa: E501 }, "dwi2response": {ResponseSD().version: ResponseSD}, "5ttgen": {Generate5tt().version: Generate5tt}, "dwi2tensor": {Dwi2Tensor.__version__: Dwi2Tensor}, "tensor2metric": {Tensor2metric.__version__: Tensor2metric}, "mrcat": {MRCat.__version__: MRCat}, "dwigradcheck": {DwiGradCheck.__version__: DwiGradCheck}, "Mutual Information Score": {"1.0": MutualInformationScore},
def dti_artifact_correction(wf_name="dti_artifact_correction"): """ Run the diffusion MRI pre-processing workflow against the diff files in `data_dir`. It will resample/regrid the diffusion image to have isometric voxels. Corrects for head motion correction and Eddy currents. Estimates motion outliers and exports motion reports using nipype.algorithms.RapidArt. Nipype Inputs ------------- dti_art_input.diff: traits.File path to the diffusion MRI image dti_art_input.bval: traits.File path to the bvals file dti_art_input.bvec: traits.File path to the bvecs file Nipype Outputs -------------- dti_art_output.eddy_corr_file: traits.File Eddy currents corrected DTI image. dti_art_output.bvec_rotated: traits.File Rotated bvecs file dti_art_output.brain_mask_1: traits.File Brain mask extracted using BET on the first B0 image. dti_art_output.brain_mask_2: traits.File Brain mask extracted using BET on the average B0 image, after motion correction. dti_art_output.acpq: traits.File Text file with acquisition parameters calculated for Eddy. dti_art_output.index: traits.File Text file with acquisition indices calculated for Eddy. dti_art_output.avg_b0: traits.File The average b=0 image extracted from the motion and eddy currents correted diffusion MRI. dti_art_output.hmc_corr_file: traits.File dti_art_output.hmc_corr_bvec: traits.File dti_art_output.hmc_corr_xfms: traits.File dti_art_output.art_displacement_files: traits.File dti_art_output.art_intensity_files: traits.File dti_art_output.art_norm_files: traits.File dti_art_output.art_outlier_files: traits.File dti_art_output.art_plot_files: traits.File dti_art_output.art_statistic_files: traits.File Returns ------- wf: nipype Workflow """ # specify input and output fields in_fields = ["diff", "bval", "bvec"] out_fields = ["eddy_corr_file", "bvec_rotated", "brain_mask_1", "brain_mask_2", "acqp", "index", "avg_b0", ] do_rapidart = get_config_setting("dmri.artifact_detect", True) if do_rapidart: out_fields += ["hmc_corr_file", "hmc_corr_bvec", "hmc_corr_xfms", "art_displacement_files", "art_intensity_files", "art_norm_files", "art_outlier_files", "art_plot_files", "art_statistic_files", ] # input interface dti_input = setup_node(IdentityInterface(fields=in_fields, mandatory_inputs=True), name="dti_art_input") # resample resample = setup_node(Function(function=reslice, input_names=['in_file', 'new_zooms', 'order', 'out_file'], output_names=['out_file']), name='dti_reslice') ## extract first b0 for Eddy and HMC brain mask list_b0 = pe.Node(Function(function=b0_indices, input_names=['in_bval'], output_names=['out_idx'],), name='b0_indices') extract_b0 = pe.Node(ExtractROI(t_size=1), name="extract_first_b0") # For Eddy, the mask is only used for selecting voxels for the estimation of the hyperparameters, # so isn’t very critical. # Note also that it is better with a too conservative (small) mask than a too big. bet_dwi0 = setup_node(BET(frac=0.3, mask=True, robust=True), name='bet_dwi_pre') pick_first = lambda lst: lst[0] # motion artifacts detection, requires linear co-registration for motion estimation. if do_rapidart: # head motion correction hmc = hmc_pipeline() art = setup_node(rapidart_dti_artifact_detection(), name="detect_artifacts") # Eddy eddy = setup_node(Eddy(method='jac'), name="eddy") ## acquisition parameters for Eddy write_acqp = setup_node(Function(function=dti_acquisition_parameters, input_names=["in_file"], output_names=["out_acqp", "out_index"],), name="write_acqp") ## rotate b-vecs rot_bvec = setup_node(Function(function=eddy_rotate_bvecs, input_names=["in_bvec", "eddy_params"], output_names=["out_file"],), name="rot_bvec") ## extract all b0s and average them after Eddy correction avg_b0_post = pe.Node(Function(function=b0_average, input_names=['in_dwi', 'in_bval'], output_names=['out_file'],), name='b0_avg_post') bet_dwi1 = setup_node(BET(frac=0.3, mask=True, robust=True), name='bet_dwi_post') # nlmeans denoise apply_nlmeans = get_config_setting("dmri.apply_nlmeans", True) if apply_nlmeans: nlmeans = setup_node(Function(function=nlmeans_denoise, input_names=['in_file', 'mask_file', 'out_file', 'N'], output_names=['out_file']), name='nlmeans_denoise') # output interface dti_output = setup_node(IdentityInterface(fields=out_fields), name="dti_art_output") # Create the workflow object wf = pe.Workflow(name=wf_name) # Connect the nodes wf.connect([ # resample to iso-voxel (dti_input, resample, [("diff", "in_file"),]), # read from input file the acquisition parameters for eddy (dti_input, write_acqp, [("diff", "in_file")]), # reference mask for hmc and eddy (dti_input, list_b0, [("bval", "in_bval")]), (resample, extract_b0, [("out_file", "in_file")]), (list_b0, extract_b0, [(("out_idx", pick_first), "t_min")]), (extract_b0, bet_dwi0, [("roi_file", "in_file")]), # Eddy (resample, eddy, [("out_file", "in_file")]), (bet_dwi0, eddy, [("mask_file", "in_mask")]), (dti_input, eddy, [("bval", "in_bval"), ("bvec", "in_bvec") ]), (write_acqp, eddy, [("out_acqp", "in_acqp"), ("out_index", "in_index") ]), # rotate bvecs (dti_input, rot_bvec, [("bvec", "in_bvec")]), (eddy, rot_bvec, [("out_parameter", "eddy_params")]), # final avg b0 (dti_input, avg_b0_post, [("bval", "in_bval")]), (eddy, avg_b0_post, [("out_corrected", "in_dwi" )]), (avg_b0_post, bet_dwi1, [("out_file", "in_file")]), # output (write_acqp, dti_output, [("out_acqp", "acqp"), ("out_index", "index")]), (bet_dwi0, dti_output, [("mask_file", "brain_mask_1")]), (bet_dwi1, dti_output, [("mask_file", "brain_mask_2")]), (rot_bvec, dti_output, [("out_file", "bvec_rotated")]), (avg_b0_post, dti_output, [("out_file", "avg_b0")]), ]) if apply_nlmeans: wf.connect([ # non-local means (eddy, nlmeans, [("out_corrected", "in_file")]), (bet_dwi1, nlmeans, [("mask_file", "mask_file")]), # output (nlmeans, dti_output, [("out_file", "eddy_corr_file")]), ]) else: wf.connect([ # output (eddy, dti_output, [("out_corrected", "eddy_corr_file")]), ]) if do_rapidart: wf.connect([ # head motion correction (dti_input, hmc, [("bval", "inputnode.in_bval"), ("bvec", "inputnode.in_bvec"), ]), (resample, hmc, [("out_file", "inputnode.in_file")]), (bet_dwi0, hmc, [("mask_file", "inputnode.in_mask")]), (list_b0, hmc, [(("out_idx", pick_first), "inputnode.ref_num"),]), # artifact detection (hmc, art, [("outputnode.out_file", "realigned_files"), ("outputnode.out_xfms", "realignment_parameters"), ]), (bet_dwi1, art, [("mask_file", "mask_file"),]), # output (hmc, dti_output, [("outputnode.out_file", "hmc_corr_file"), ("outputnode.out_bvec", "hmc_corr_bvec"), ("outputnode.out_xfms", "hmc_corr_xfms"), ]), (art, dti_output, [("displacement_files", "art_displacement_files"), ("intensity_files", "art_intensity_files"), ("norm_files", "art_norm_files"), ("outlier_files", "art_outlier_files"), ("plot_files", "art_plot_files"), ("statistic_files", "art_statistic_files"), ]), ]) return wf
"versions": [{ "title": ApplyTOPUP().version or "1.0", "description": f"Default apply_topup version for nipype {_NIPYPE_VERSION}.", # noqa: E501 "input": APPLY_TOPUP_INPUT_SPECIFICATION, "output": APPLY_TOPUP_OUTPUT_SPECIFICATION, "nested_results_attribute": "outputs.get_traitsfree", }], }, { "title": "eddy", "description": "estimates and corrects eddy currents induced distortions.", # noqa: E501 "versions": [{ "title": Eddy().version or "1.0", "description": f"Default eddy version for nipype {_NIPYPE_VERSION}.", # noqa: E501 "input": EDDY_INPUT_SPECIFICATION, "output": EDDY_OUTPUT_SPECIFICATION, "nested_results_attribute": "outputs.get_traitsfree", }], }, { "title": "binary_maths", "description": "Perform mathematical operations using a second image or a numeric value.", # noqa: E501 "versions": [{ "title": BinaryMaths().version or "1.0", "description":
def eddy_fsl_pipeline(epi_param, name='eddy_fsl'): """ Using eddy from fsl for head motion correction and eddy current distortion correction. """ from nipype.interfaces.fsl import Eddy import nipype.interfaces.utility as niu # utility import nipype.pipeline.engine as pe # pypeline engine from clinica.pipelines.dwi_preprocessing_using_t1.dwi_preprocessing_using_t1_utils import eddy_fsl, generate_acq, generate_index, b0_indices inputnode = pe.Node( niu.IdentityInterface( fields=['in_file', 'in_bvec', 'in_bval', 'in_mask', 'ref_b0']), name='inputnode') generate_acq = pe.Node(niu.Function(function=generate_acq, input_names=['in_b0', 'epi_param'], output_names=['out_file']), name='generate_acq') generate_acq.inputs.epi_param = epi_param list_b0 = pe.Node(niu.Function(input_names=['in_bval'], output_names=['out_idx'], function=b0_indices), name='find_b0_indices') generate_index = pe.Node(niu.Function(function=generate_index, input_names=['in_bval', 'b0_index'], output_names=['eddy_index']), name='generate_index') eddy = pe.Node(niu.Function(input_names=['in_bvec', 'in_bval', 'in_file', 'in_mask', 'in_acqp', 'in_index'], output_names=['out_parameter', 'out_corrected', 'out_rotated_bvecs'], function=eddy_fsl), name='eddy_fsl') eddy = pe.Node(interface=Eddy(), name='eddy_fsl') eddy.inputs.flm = 'linear' outputnode = pe.Node(niu.IdentityInterface(fields=['out_parameter', 'out_corrected', 'out_rotated_bvecs']), name='outputnode') wf = pe.Workflow(name=name) wf.connect([ (inputnode, generate_acq, [('ref_b0', 'in_b0')]), (inputnode, generate_index, [('in_bval', 'in_bval')]), (list_b0, generate_index, [('out_idx', 'b0_index')]), (inputnode, list_b0, [('in_bval', 'in_bval')]), (inputnode, eddy, [('in_bvec', 'in_bvec')]), (inputnode, eddy, [('in_bval', 'in_bval')]), (inputnode, eddy, [('in_file', 'in_file')]), (inputnode, eddy, [('in_mask', 'in_mask')]), (generate_acq, eddy, [('out_file', 'in_acqp')]), (generate_index, eddy, [('eddy_index', 'in_index')]), (eddy, outputnode, [('out_parameter', 'out_parameter')]), (eddy, outputnode, [('out_corrected', 'out_corrected')]), (eddy, outputnode, [('out_rotated_bvecs', 'out_rotated_bvecs')]) ]) return wf
def init_eddy_wf(debug=False, name="eddy_wf"): """ Create a workflow for head-motion & Eddy currents distortion estimation with FSL. Parameters ---------- name : :obj:`str` Name of workflow (default: ``eddy_wf``) Inputs ------ dwi_file dwi NIfTI file Outputs ------- out_eddy The eddy corrected diffusion image.. """ from nipype.interfaces.fsl import Eddy, ExtractROI inputnode = pe.Node( niu.IdentityInterface( fields=["dwi_file", "metadata", "dwi_mask", "in_bvec", "in_bval"] ), name="inputnode", ) outputnode = pe.Node( niu.IdentityInterface( fields=["out_rotated_bvecs", "eddy_ref_image", "out_eddy"] ), name="outputnode", ) workflow = Workflow(name=name) workflow.__desc__ = f"""\ Geometrical distortions derived from the so-called Eddy-currents, and head-motion realignment parameters were estimated with the joint modeling of ``eddy_openmp``, included in FSL {Eddy().version} [@eddy]. """ eddy = pe.Node( Eddy(), name="eddy", ) if debug: eddy.inputs.niter = 1 eddy.inputs.is_shelled = True eddy.inputs.dont_peas = True eddy.inputs.nvoxhp = 100 # Generate the acqp and index files for eddy gen_eddy_files = pe.Node( niu.Function( input_names=["in_file", "in_meta"], output_names=["out_acqparams", "out_index"], function=gen_eddy_textfiles, ), name="gen_eddy_files", ) eddy_ref_img = pe.Node(ExtractROI(t_min=0, t_size=1), name="eddy_roi") # fmt:off workflow.connect([ (inputnode, eddy, [ ("dwi_file", "in_file"), ("dwi_mask", "in_mask"), ("in_bvec", "in_bvec"), ("in_bval", "in_bval"), ]), (inputnode, gen_eddy_files, [ ("dwi_file", "in_file"), ("metadata", "in_meta") ]), (gen_eddy_files, eddy, [ ("out_acqparams", "in_acqp"), ("out_index", "in_index"), ]), (eddy, outputnode, [ ("out_corrected", "out_eddy"), ("out_rotated_bvecs", "out_rotated_bvecs") ]), (eddy, eddy_ref_img, [("out_corrected", "in_file")]), (eddy_ref_img, outputnode, [("roi_file", "eddy_ref_image")]), ]) # fmt:on return workflow