def dwi_prep(degibbs: Path, PA: Path, out_file: Path, data_type: str = "dwi", func=None): eddy_dir = Path(degibbs.parent / "eddyqc") if not eddy_dir.is_dir(): print("Creating directory for eddy current correction parameters...") ### extract first AP volume AP_b0 = Path(degibbs.parent / "AP_b0.mif") if not AP_b0.is_file(): mrconvert = mrt.MRConvert() mrconvert.inputs.in_file = degibbs mrconvert.inputs.out_file = AP_b0 mrconvert.inputs.coord = [3, 0] print(mrconvert.cmdline) mrconvert.run() ### concatenate AP and PA dual_phased = Path(degibbs.parent / "b0s.mif") if not dual_phased.is_file(): cmd = ( f"mrcat {AP_b0.absolute()} {PA.absolute()} {dual_phased.absolute()} -axis 3" ) os.system(cmd) ### initiate dwipreproc (eddy) args = "-rpe_pair" eddyqc_text = "eddyqc/" cmd = f"dwipreproc {degibbs.absolute()} {out_file.absolute()} -pe_dir AP {args} -se_epi {dual_phased.absolute()} -eddyqc_text {degibbs.parent}/{eddyqc_text}" print(cmd) return cmd
def DWI_prep(degibbs: str, PA: str, out_file: str, data_type: str = "dwi", func=None): eddy_dir = f"{os.path.dirname(degibbs)}/eddyqc" if not os.path.isdir(eddy_dir): print("Creating directory for eddy current correction parameters...") ### extract first AP volume mrconvert = mrt.MRConvert() mrconvert.inputs.in_file = degibbs mrconvert.inputs.out_file = f"{os.path.dirname(degibbs)}/AP_b0.mif" mrconvert.inputs.coord = [3, 0] print(mrconvert.cmdline) mrconvert.run() ### concatenate AP and PA cmd = f"mrcat {mrconvert.inputs.out_file} {PA} {os.path.dirname(degibbs)}/b0s.mif -axis 3" os.system(cmd) ### initiate dwipreproc (eddy) in_file = func args = "-rpe_pair" eddyqc_text = "eddyqc/" cmd = f"dwipreproc {in_file} {out_file} -pe_dir AP {args} -se_epi {os.path.dirname(degibbs)}/b0s.mif -eddyqc_text {os.path.dirname(degibbs)}/{eddyqc_text}" print(cmd) os.system(cmd) return out_file
def convert_to_mif(in_file, out_file, bvec=None, bval=None): mrconvert = mrt.MRConvert() mrconvert.inputs.in_file = in_file mrconvert.inputs.out_file = out_file if bvec and bval: mrconvert.inputs.args = ( f"-json_import {mrconvert.inputs.in_file.replace('nii.gz','json')}" ) mrconvert.inputs.grad_fsl = (bvec, bval) mrconvert.run() return out_file
def convert_tmp_anat(in_file: str): if "mif" in in_file: out_file = f"{os.path.dirname(in_file)}/T1.nii" else: out_file = in_file.replace("nii.gz", "mif") if not os.path.isfile(out_file): mrconvert = mrt.MRConvert() mrconvert.inputs.in_file = in_file mrconvert.inputs.out_file = out_file mrconvert.inputs.args = "-strides +1,+2,+3" print(mrconvert.cmdline) mrconvert.run() return out_file
def convert_to_mif(in_file, out_file, bvec=None, bval=None, anat=False): mrconvert = mrt.MRConvert() mrconvert.inputs.in_file = in_file mrconvert.inputs.out_file = out_file mrconvert.inputs.args = "-quiet" if bvec and bval: mrconvert.inputs.args = ( f"-json_import {mrconvert.inputs.in_file.replace('nii.gz','json')}" ) mrconvert.inputs.grad_fsl = (bvec, bval) if anat: mrconvert.inputs.args = "-strides +1,+2,+3 -quiet" mrconvert.run() return out_file
def preprocess_dwi_data(self, data, index, acqp, atlas2use, ResponseSD_algorithm='tournier', fod_algorithm='csd', tract_algorithm='iFOD2', streamlines_number='10M'): ''' preprocessing of dwi data and connectome extraction Parameters ---------- subjects_dir = path to the subjects' folders data: tuple | a tuple having the path to dwi, bvecs and bvals files. It is obtained using the function grab_data() index: str | Name of text file specifying the relationship between the images in --imain and the information in --acqp and --topup. E.g. index.txt acqp: str | Name of text file with information about the acquisition of the images in --imain atlas2use: str | The input node parcellation image ResponseSD_algorithm (optional): str | Select the algorithm to be used to complete the script operation; Options are: dhollander, fa, manual, msmt_5tt, tax, tournier (Default is 'tournier') fod_algorithm (optional): str | The algorithm to use for FOD estimation. (options are: csd,msmt_csd) (Default is 'csd') tract_algorithm (optional): str | specify the tractography algorithm to use. Valid choices are: FACT, iFOD1, iFOD2, Nulldist1, Nulldist2, SD_Stream, Seedtest, Tensor_Det, Tensor_Prob (Default is 'iFOD2') streamlines_number (optional): str | set the desired number of streamlines (Default is '10M') ''' if len(data[0]) != len(data[1]): raise ValueError( 'dwi datas do not have the same shape of bvec files') if len(data[0]) != len(data[2]): raise ValueError( 'dwi datas do not have the same shape of bval files') if len(data[1]) != len(data[2]): raise ValueError( 'bvec files do not have the same shape of bvec files') for subj in range(len(data[0])): print('Extracting B0 volume for subject', subj) self.roi = fsl.ExtractROI( in_file=data[0][subj], roi_file=os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_nodiff.nii.gz'), t_min=0, t_size=1) self.roi.run() print('Converting into .mif for subject', subj) self.mrconvert = mrt.MRConvert() self.mrconvert.inputs.in_file = data[0][subj] self.mrconvert.inputs.grad_fsl = (data[1][subj], data[2][subj]) self.mrconvert.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi.mif') self.mrconvert.run() print('Denoising data for subject', subj) self.denoise = mrt.DWIDenoise() self.denoise.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi.mif') self.denoise.inputs.noise = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_noise.mif') self.denoise.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.mif') self.denoise.run() self.denoise_convert = mrt.MRConvert() self.denoise_convert.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.mif') self.denoise_convert.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.nii.gz') self.denoise_convert.run() print('Skull stripping for subject', subj) self.mybet = fsl.BET() self.mybet.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_nodiff.nii.gz') self.mybet.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain.nii.gz') self.mybet.inputs.frac = 0.1 self.mybet.inputs.robust = True self.mybet.inputs.mask = True self.mybet.run() print('Running Eddy for subject', subj) self.eddy = Eddy() self.eddy.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised.nii.gz') self.eddy.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.eddy.inputs.in_acqp = acqp self.eddy.inputs.in_bvec = data[1][subj] self.eddy.inputs.in_bval = data[2][subj] self.eddy.inputs.out_base = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.nii.gz') self.eddy.run() print('Running Bias Correction for subject', subj) self.bias_correct = mrt.DWIBiasCorrect() self.bias_correct.inputs.use_ants = True self.bias_correct.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.nii.gz') self.bias_correct.inputs.grad_fsl = (os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.eddy_rotated_bvecs.bvec'), data[2][subj]) self.bias_correct.inputs.bias = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_bias.mif') self.bias_correct.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy_unbiased.mif') self.bias_correct.run() print('Calculating Response function for subject', subj) self.resp = mrt.ResponseSD() self.resp.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy_unbiased.mif') self.resp.inputs.algorithm = ResponseSD_algorithm self.resp.inputs.grad_fsl = (os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy.eddy_rotated_bvecs.bvec'), data[2][subj]) self.resp.inputs.wm_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_response.txt') self.resp.run() print('Estimating FOD for subject', subj) self.fod = mrt.EstimateFOD() self.fod.inputs.algorithm = fod_algorithm self.fod.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi_denoised_eddy_unbiased.mif') self.fod.inputs.wm_txt = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_response.txt') self.fod.inputs.mask_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.fod.inputs.grad_fsl = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_response.txt') self.fod.run() print('Extracting whole brain tract for subject', subj) self.tk = mrt.Tractography() self.tk.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + 'fods.mif') self.tk.inputs.roi_mask = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.tk.inputs.algorithm = tract_algorithm self.tk.inputs.seed_image = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_denoised_brain_mask.nii.gz') self.tk.inputs.select = streamlines_number self.tk.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_whole_brain_' + streamlines_number + '.tck') self.tk.run() print('Extracting connectome for subject', subj) self.mat = mrt.BuildConnectome() self.mat.inputs.in_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_whole_brain_' + streamlines_number + '.tck') self.mat.inputs.in_parc = atlas2use self.mat.inputs.out_file = os.path.join( os.path.split(data[0][subj])[0] + '/' + os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_connectome.csv') self.mat.run()
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')
import sys import nipype import nipype.pipeline as pe import nipype.interfaces.io as io import nipype.interfaces.mrtrix3 as mrtrix3 #Generic datagrabber module that wraps around glob in an io_data_grabber = pe.Node(io.DataGrabber(outfields=["outfiles"]), name='io_data_grabber') io_data_grabber.inputs.sort_filelist = True io_data_grabber.inputs.template = "/Users/bsms9gep/data/*.nii" #Wraps the executable command ``mrconvert``. mrtrix3_mrconvert = pe.Node(interface=mrtrix3.MRConvert(), name='mrtrix3_mrconvert') mrtrix3_mrconvert.inputs.grad_fsl = ("/Users/bsms9gep/data/bvecs", "/Users/bsms9gep/data/bvals") #Wraps the executable command ``dwi2mask``. mrtrix3_brain_mask = pe.Node(interface=mrtrix3.BrainMask(), name='mrtrix3_brain_mask') #Wraps the executable command ``dwibiascorrect``. mrtrix3_dwibias_correct = pe.Node(interface=mrtrix3.DWIBiasCorrect(), name='mrtrix3_dwibias_correct') mrtrix3_dwibias_correct.inputs.out_file = 'dwi_unbiased.mif' #Wraps the executable command ``dwi2response``. mrtrix3_response_sd = pe.Node(interface=mrtrix3.ResponseSD(),
""" Diffusion-weighted MRI data processing pipeline: In construction: """ # pipeline engine of nipype import nipype.pipeline.engine as pe # python interface to mrtrix3 (mrtrix3 need to be installed in your computer) from nipype.interfaces import mrtrix3 from dwi_nodes import sift_filtering, rigid_transform_estimation, apply_linear_transform # Elementary bricks # Data conversion from .nii to .mif file (allows to embed diffusion bvals et bvecs) mrconvert = pe.Node(interface=mrtrix3.MRConvert(), name="mrconvert") # Bias correction of the diffusion MRI data (for more quantitative approach) dwibiascorrect = pe.Node(interface=mrtrix3.preprocess.DWIBiasCorrect(), name="dwibiascorrect") dwibiascorrect.use_ants = True # gross brain mask stemming from DWI data dwi2mask = pe.Node(interface=mrtrix3.utils.BrainMask(), name="dwi2mask") # tensor coefficients estimation dwi2tensor = pe.Node(interface=mrtrix3.reconst.FitTensor(), name="dwi2tensor") # derived FA contrast for registration tensor2fa = pe.Node(interface=mrtrix3.TensorMetrics(), name="tensor2fa")
def dholl_preproc_wf(shells=[0, 1000, 2000], lmax=[0, 8, 8], sshell=False, noreorient=False, template_dir=None, template_label=None, wdir=None, nthreads=1, name='dholl_preproc_wf'): """ Set up Dhollander response preproc workflow No assumption of registration to T1w space is made """ if template_dir is None or template_label is None: print("Missing template info") raise IOError # Grab template data templateGrabber = io.getTemplate(template_dir=template_dir, template_label=template_label, wdir=wdir) # Convert nii to mif dwiConvert = pe.Node(mrt.MRConvert(), name='dwiConvert') dwiConvert.base_dir = wdir dwiConvert.inputs.nthreads = nthreads dwiConvert.interface.num_threads = nthreads # dwi2response - included but not used dwi2response = pe.Node(mrt.ResponseSD(), name='dwi2response') dwi2response.base_dir = wdir dwi2response.inputs.algorithm = 'dhollander' dwi2response.inputs.wm_file = 'space-dwi_model-CSD_WMResp.txt' dwi2response.inputs.gm_file = 'space-dwi_model-CSD_GMResp.txt' dwi2response.inputs.csf_file = 'space-dwi_model-CSD_CSFResp.txt' dwi2response.inputs.max_sh = lmax dwi2response.inputs.shell = shells dwi2response.inputs.nthreads = nthreads dwi2response.interface.num_threads = nthreads # Convert mask (nii) to mif maskConvert = pe.Node(mrt.MRConvert(), name='maskConvert') maskConvert.base_dir = wdir maskConvert.inputs.nthreads = nthreads maskConvert.interface.num_threads = nthreads # dwi2fod dwi2fod = pe.Node(mrt.EstimateFOD(), name='dwi2fod') dwi2fod.base_dir = wdir dwi2fod.inputs.algorithm = 'msmt_csd' dwi2fod.inputs.shell = shells dwi2fod.inputs.wm_odf = 'space-dwi_model-CSD_WMFOD.mif' if sshell is False: dwi2fod.inputs.gm_odf = 'space-dwi_model-CSD_GMFOD.mif' dwi2fod.inputs.csf_odf = 'space-dwi_model-CSD_CSFFOD.mif' dwi2fod.inputs.nthreads = nthreads dwi2fod.interface.num_threads = nthreads # mtnormalise mtnormalise = pe.Node(mrt.MTNormalise(), name='mtnormalise') mtnormalise.base_dir = wdir mtnormalise.inputs.out_wm = 'space-dwi_model-CSD_WMFODNorm.mif' if sshell is False: mtnormalise.inputs.out_gm = 'space-dwi_model-CSD_GMFODNorm.mif' mtnormalise.inputs.out_csf = 'space-dwi_model-CSD_CSFFODNorm.mif' mtnormalise.inputs.nthreads = nthreads mtnormalise.interface.num_threads = nthreads # Registration MRRegister = pe.Node(mrt.MRRegister(), name='MRRegister') MRRegister.base_dir = wdir # MRRegister.inputs.ref_file = template MRRegister.inputs.nl_warp = [ 'from-dwi_to-Template_xfm.mif', 'from-Template_to-dwi_xfm.mif' ] if noreorient is not False: MRRegister.inputs.noreorientation = noreorient MRRegister.inputs.nthreads = nthreads MRRegister.interface.num_threads = nthreads # Transforms WarpSelect1 = pe.Node(niu.Select(), name='WarpSelect1') WarpSelect1.base_dir = wdir WarpSelect1.inputs.index = [0] WarpSelect1.interface.num_threads = nthreads WarpSelect2 = pe.Node(niu.Select(), name='WarpSelect2') WarpSelect2.base_dir = wdir WarpSelect2.inputs.index = [1] WarpSelect2.interface.num_threads = nthreads # Warp data MaskTransform = pe.Node(mrt.MRTransform(), name='MaskTransform') MaskTransform.base_dir = wdir MaskTransform.inputs.out_file = 'space-Template_brainmask.mif' MaskTransform.inputs.nthreads = nthreads MaskTransform.interface.num_threads = nthreads FODTransform = pe.Node(mrt.MRTransform(), name='FODTransform') FODTransform.base_dir = wdir FODTransform.inputs.out_file = 'space-Template_model-CSD_WMFODNorm.mif' FODTransform.inputs.nthreads = nthreads FODTransform.interface.num_threads = nthreads # Tensor processing DWINormalise = pe.Node(mrt.DWINormalise(), name='DWINormalise') DWINormalise.base_dir = wdir DWINormalise.inputs.out_file = 'space-dwi_dwiNorm.mif' DWINormalise.inputs.nthreads = nthreads DWINormalise.interface.num_threads = nthreads DWITransform = pe.Node(mrt.MRTransform(), name='DWITransform') DWITransform.base_dir = wdir DWITransform.inputs.out_file = 'space-Template_dwiNorm.mif' DWITransform.inputs.nthreads = nthreads DWITransform.interface.num_threads = nthreads FitTensor = pe.Node(mrt.FitTensor(), name='FitTensor') FitTensor.base_dir = wdir FitTensor.inputs.out_file = 'space-Template_desc-WLS_model-DTI_tensor.mif' FitTensor.inputs.nthreads = nthreads FitTensor.interface.num_threads = nthreads TensorMetrics = pe.Node(mrt.TensorMetrics(), name='TensorMetrics') TensorMetrics.base_dir = wdir TensorMetrics.inputs.out_fa = 'space-Template_model-DTI_FA.mif' TensorMetrics.inputs.out_adc = 'space-Template_model-DTI_MD.mif' TensorMetrics.inputs.out_ad = 'space-Template_model-DTI_AD.mif' TensorMetrics.inputs.out_rd = 'space-Template_model-DTI_RD.mif' TensorMetrics.inputs.nthreads = nthreads TensorMetrics.interface.num_threads = nthreads # Build workflow workflow = pe.Workflow(name=name) # Single shell if sshell is True: workflow.connect([ # Compute FOD (dwiConvert, dwi2response, [('out_file', 'in_file')]), (dwiConvert, dwi2fod, [('out_file', 'in_file')]), (dwi2response, dwi2fod, [('wm_file', 'wm_txt'), ('csf_file', 'csf_txt')]), (dwi2fod, mtnormalise, [('wm_odf', 'in_wm'), ('csf_odf', 'in_csf')]), (maskConvert, dwi2response, [('out_file', 'in_mask')]), (maskConvert, dwi2fod, [('out_file', 'mask_file')]), (maskConvert, mtnormalise, [('out_file', 'mask')]), (maskConvert, MRRegister, [('out_file', 'mask1')]), (templateGrabber, MRRegister, [('wm_fod', 'ref_file'), ('mask', 'mask2')]), (mtnormalise, MRRegister, [('out_wm', 'in_file')]), (MRRegister, WarpSelect1, [('nl_warp', 'inlist')]), (MRRegister, WarpSelect2, [('nl_warp', 'inlist')]), (maskConvert, MaskTransform, [('out_file', 'in_file')]), (WarpSelect1, MaskTransform, [('out', 'warp')]), (mtnormalise, FODTransform, [('out_wm', 'in_file')]), (WarpSelect1, FODTransform, [('out', 'warp')]), # Compute tensors (dwiConvert, DWINormalise, [('out_file', 'in_file')]), (maskConvert, DWINormalise, [('out_file', 'in_mask')]), (DWINormalise, DWITransform, [('out_file', 'in_file')]), (WarpSelect1, DWITransform, [('out', 'warp')]), (DWITransform, FitTensor, [('out_file', 'in_file')]), (MaskTransform, FitTensor, [('out_file', 'in_mask')]), (FitTensor, TensorMetrics, [('out_file', 'in_file')]), (MaskTransform, TensorMetrics, [('out_file', 'in_mask')]) ]) # For multi-shell else: workflow.connect([ # Compute FOD (dwiConvert, dwi2response, [('out_file', 'in_file')]), (dwiConvert, dwi2fod, [('out_file', 'in_file')]), (dwi2response, dwi2fod, [('wm_file', 'wm_txt'), ('gm_file', 'gm_txt'), ('csf_file', 'csf_txt')]), (dwi2fod, mtnormalise, [('wm_odf', 'in_wm'), ('gm_odf', 'in_gm'), ('csf_odf', 'in_csf')]), (maskConvert, dwi2response, [('out_file', 'in_mask')]), (maskConvert, dwi2fod, [('out_file', 'mask_file')]), (maskConvert, mtnormalise, [('out_file', 'mask')]), (maskConvert, MRRegister, [('out_file', 'mask1')]), (templateGrabber, MRRegister, [('wm_fod', 'ref_file'), ('mask', 'mask2')]), (mtnormalise, MRRegister, [('out_wm', 'in_file')]), (MRRegister, WarpSelect1, [('nl_warp', 'inlist')]), (MRRegister, WarpSelect2, [('nl_warp', 'inlist')]), (maskConvert, MaskTransform, [('out_file', 'in_file')]), (WarpSelect1, MaskTransform, [('out', 'warp')]), (mtnormalise, FODTransform, [('out_wm', 'in_file')]), (WarpSelect1, FODTransform, [('out', 'warp')]), # Compute tensors (dwiConvert, DWINormalise, [('out_file', 'in_file')]), (maskConvert, DWINormalise, [('out_file', 'in_mask')]), (DWINormalise, DWITransform, [('out_file', 'in_file')]), (WarpSelect1, DWITransform, [('out', 'warp')]), (DWITransform, FitTensor, [('out_file', 'in_file')]), (MaskTransform, FitTensor, [('out_file', 'in_mask')]), (FitTensor, TensorMetrics, [('out_file', 'in_file')]), (MaskTransform, TensorMetrics, [('out_file', 'in_mask')]) ]) return workflow
def create_dwi_processing_pipeline(): # Nodes inputnode = pe.Node( utility.IdentityInterface( fields=[ "diffusion_volume", "bvals", "bvecs", "t1_volume", "nb_tracks", "min_length", "max_length", ], mandatory_inputs=False, ), name="inputnode", ) # Data conversion from .nii to .mif file (allows to embed diffusion bvals et bvecs) mrconvert = pe.Node(interface=mrtrix3.MRConvert(), name="mrconvert") # Main processing steps core_pipeline = create_core_dwi_processing_pipeline() # Outputs params outputnode = pe.Node( utility.IdentityInterface( fields=[ "corrected_diffusion_volume", "wm_fod", "tractogram", "diffusion_to_t1_transform", ], mandatory_inputs=False, ), name="outputnode", ) dwi_processing_pipeline = pe.Workflow(name="dwi_processing_pipeline") dwi_processing_pipeline.connect([( inputnode, mrconvert, [ ("diffusion_volume", "in_file"), ("bvals", "in_bval"), ("bvecs", "in_bvec"), ], )]) dwi_processing_pipeline.connect([( inputnode, core_pipeline, [ ("t1_volume", "inputnode.t1_volume"), ("nb_tracks", "inputnode.nb_tracks"), ("min_length", "inputnode.min_length"), ("max_length", "inputnode.max_length"), ], )]) dwi_processing_pipeline.connect(mrconvert, "out_file", core_pipeline, "inputnode.diffusion_volume") dwi_processing_pipeline.connect( core_pipeline, "outputnode.corrected_diffusion_volume", outputnode, "corrected_diffusion_volume", ) dwi_processing_pipeline.connect(core_pipeline, "outputnode.wm_fod", outputnode, "wm_fod") dwi_processing_pipeline.connect(core_pipeline, "outputnode.tractogram", outputnode, "tractogram") dwi_processing_pipeline.connect( core_pipeline, "outputnode.diffusion_to_t1_transform", outputnode, "diffusion_to_t1_transform", ) return dwi_processing_pipeline