def remove_bias(name='bias_correct'): """ This workflow estimates a single multiplicative bias field from the averaged *b0* image, as suggested in [Jeurissen2014]_. .. admonition:: References .. [Jeurissen2014] Jeurissen B. et al., `Multi-tissue constrained spherical deconvolution for improved analysis of multi-shell diffusion MRI data <https://doi.org/10.1016/j.neuroimage.2014.07.061>`_. NeuroImage (2014). doi: 10.1016/j.neuroimage.2014.07.061 Example ------- >>> from nipype.workflows.dmri.fsl.artifacts import remove_bias >>> bias = remove_bias() >>> bias.inputs.inputnode.in_file = 'epi.nii' >>> bias.inputs.inputnode.in_bval = 'diffusion.bval' >>> bias.inputs.inputnode.in_mask = 'mask.nii' >>> bias.run() # doctest: +SKIP """ inputnode = pe.Node( niu.IdentityInterface(fields=['in_file', 'in_bval', 'in_mask']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['out_file']), name='outputnode') avg_b0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'], output_names=['out_file'], function=b0_average), name='b0_avg') n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3, save_bias=True, bspline_fitting_distance=600), name='Bias_b0') split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs') mult = pe.MapNode(fsl.MultiImageMaths(op_string='-div %s'), iterfield=['in_file'], name='RemoveBiasOfDWIs') thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'], name='RemoveNegative') merge = pe.Node(fsl.utils.Merge(dimension='t'), name='MergeDWIs') wf = pe.Workflow(name=name) wf.connect([(inputnode, avg_b0, [('in_file', 'in_dwi'), ('in_bval', 'in_bval')]), (avg_b0, n4, [('out_file', 'input_image')]), (inputnode, n4, [('in_mask', 'mask_image')]), (inputnode, split, [('in_file', 'in_file')]), (n4, mult, [('bias_image', 'operand_files')]), (split, mult, [('out_files', 'in_file')]), (mult, thres, [('out_file', 'in_file')]), (thres, merge, [('out_file', 'in_files')]), (merge, outputnode, [('merged_file', 'out_file')])]) return wf
def epi_sbref_registration(name='EPI_SBrefRegistration'): workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['epi_brain', 'sbref_brain']), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['epi_registered', 'out_mat']), name='outputnode') mean = pe.Node(fsl.MeanImage(dimension='T'), name='EPImean') inu = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='EPImeanBias') epi_sbref = pe.Node(fsl.FLIRT(dof=6, out_matrix_file='init.mat'), name='EPI2SBRefRegistration') epi_split = pe.Node(fsl.Split(dimension='t'), name='EPIsplit') epi_xfm = pe.MapNode(fsl.ApplyXfm(), name='EPIapplyxfm', iterfield=['in_file']) epi_merge = pe.Node(fsl.Merge(dimension='t'), name='EPImergeback') workflow.connect([ (inputnode, epi_split, [('epi_brain', 'in_file')]), (inputnode, epi_sbref, [('sbref_brain', 'reference')]), (inputnode, epi_xfm, [('sbref_brain', 'reference')]), (inputnode, mean, [('epi_brain', 'in_file')]), (mean, inu, [('out_file', 'input_image')]), (inu, epi_sbref, [('output_image', 'in_file')]), (epi_split, epi_xfm, [('out_files', 'in_file')]), (epi_sbref, epi_xfm, [('out_matrix_file', 'in_matrix_file')]), (epi_xfm, epi_merge, [('out_file', 'in_files')]), (epi_sbref, outputnode, [('out_matrix_file', 'out_mat')]), (epi_merge, outputnode, [('merged_file', 'epi_registered')]) ]) return workflow
def create_eddy_correct_pipeline(name='eddy_correct'): """ .. deprecated:: 0.9.3 Use :func:`nipype.workflows.dmri.preprocess.epi.ecc_pipeline` instead. Creates a pipeline that replaces eddy_correct script in FSL. It takes a series of diffusion weighted images and linearly co-registers them to one reference image. No rotation of the B-matrix is performed, so this pipeline should be executed after the motion correction pipeline. Example ------- >>> nipype_eddycorrect = create_eddy_correct_pipeline('nipype_eddycorrect') >>> nipype_eddycorrect.inputs.inputnode.in_file = 'diffusion.nii' >>> nipype_eddycorrect.inputs.inputnode.ref_num = 0 >>> nipype_eddycorrect.run() # doctest: +SKIP Inputs:: inputnode.in_file inputnode.ref_num Outputs:: outputnode.eddy_corrected """ warnings.warn( ('This workflow is deprecated from v.1.0.0, use ' 'nipype.workflows.dmri.preprocess.epi.ecc_pipeline instead'), DeprecationWarning) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'ref_num']), name='inputnode') pipeline = pe.Workflow(name=name) split = pe.Node(fsl.Split(dimension='t'), name='split') pick_ref = pe.Node(niu.Select(), name='pick_ref') coregistration = pe.MapNode(fsl.FLIRT(no_search=True, padding_size=1, interp='trilinear'), name='coregistration', iterfield=['in_file']) merge = pe.Node(fsl.Merge(dimension='t'), name='merge') outputnode = pe.Node(niu.IdentityInterface(fields=['eddy_corrected']), name='outputnode') pipeline.connect([(inputnode, split, [('in_file', 'in_file')]), (split, pick_ref, [('out_files', 'inlist')]), (inputnode, pick_ref, [('ref_num', 'index')]), (split, coregistration, [('out_files', 'in_file')]), (pick_ref, coregistration, [('out', 'reference')]), (coregistration, merge, [('out_file', 'in_files')]), (merge, outputnode, [('merged_file', 'eddy_corrected')]) ]) return pipeline
def fsl_RegrSliceWise(input_file,txtregr_Path,regr_Path): # scale Nifti data by factor 10 dataName = os.path.basename(input_file).split('.')[0] # proof data existence regrTextFiles = findRegData(txtregr_Path) if len(regrTextFiles) == 0: print('No regression with physio data!') output_file = os.path.join(regr_Path, os.path.basename(input_file).split('.')[0]) + '_RGR.nii.gz' shutil.copyfile(input_file, output_file) return output_file fslPath = scaleBy10(input_file, inv=False) # split input_file in slices mySplit = fsl.Split(in_file=fslPath, dimension='z', out_base_name=dataName) print(mySplit.cmdline) mySplit.run() os.remove(fslPath) # sparate ref and src volume in slices sliceFiles = findSlicesData(os.getcwd(), dataName) if not len(regrTextFiles) == len(sliceFiles): sys.exit('Error: Not enough txt.Files in %s' % txtregr_Path) print('Start separate slice Regression ... ') # start to regression slice by slice print('For all Sices ...') for i in range(len(sliceFiles)): slc = sliceFiles[i] regr = regrTextFiles[i] # only take the columns [1,2,7,9,11,12,13] of the reg-.txt Files output_file = os.path.join(regr_Path, os.path.basename(slc)) myRegr = fsl.FilterRegressor(in_file=slc,design_file=regr,out_file=output_file,filter_columns=[1,2,7,9,11,12,13]) print(myRegr.cmdline) myRegr.run() os.remove(slc) # merge slices to a single volume mcf_sliceFiles = findSlicesData(regr_Path, dataName) output_file = os.path.join(regr_Path, os.path.basename(input_file).split('.')[0]) + '_RGR.nii.gz' myMerge = fsl.Merge(in_files=mcf_sliceFiles, dimension='z', merged_file=output_file) print(myMerge.cmdline) myMerge.run() for slc in mcf_sliceFiles: os.remove(slc) # unscale result data by factor 10ˆ(-1) output_file = scaleBy10(output_file, inv=True) return output_file
def apply_all_corrections(name='UnwarpArtifacts'): """ Combines two lists of linear transforms with the deformation field map obtained typically after the SDC process. Additionally, computes the corresponding bspline coefficients and the map of determinants of the jacobian. """ inputnode = pe.Node(niu.IdentityInterface(fields=['in_sdc', 'in_hmc', 'in_ecc', 'in_dwi']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_warp', 'out_coeff', 'out_jacobian']), name='outputnode') warps = pe.MapNode(fsl.ConvertWarp(relwarp=True), iterfield=['premat', 'postmat'], name='ConvertWarp') selref = pe.Node(niu.Select(index=[0]), name='Reference') split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs') unwarp = pe.MapNode(fsl.ApplyWarp(), iterfield=['in_file', 'field_file'], name='UnwarpDWIs') coeffs = pe.MapNode(fsl.WarpUtils(out_format='spline'), iterfield=['in_file'], name='CoeffComp') jacobian = pe.MapNode(fsl.WarpUtils(write_jacobian=True), iterfield=['in_file'], name='JacobianComp') jacmult = pe.MapNode(fsl.MultiImageMaths(op_string='-mul %s'), iterfield=['in_file', 'operand_files'], name='ModulateDWIs') thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'], name='RemoveNegative') merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs') wf = pe.Workflow(name=name) wf.connect([ (inputnode, warps, [('in_sdc', 'warp1'), ('in_hmc', 'premat'), ('in_ecc', 'postmat'), ('in_dwi', 'reference')]), (inputnode, split, [('in_dwi', 'in_file')]), (split, selref, [('out_files', 'inlist')]), (warps, unwarp, [('out_file', 'field_file')]), (split, unwarp, [('out_files', 'in_file')]), (selref, unwarp, [('out', 'ref_file')]), (selref, coeffs, [('out', 'reference')]), (warps, coeffs, [('out_file', 'in_file')]), (selref, jacobian, [('out', 'reference')]), (coeffs, jacobian, [('out_file', 'in_file')]), (unwarp, jacmult, [('out_file', 'in_file')]), (jacobian, jacmult, [('out_jacobian', 'operand_files')]), (jacmult, thres, [('out_file', 'in_file')]), (thres, merge, [('out_file', 'in_files')]), (warps, outputnode, [('out_file', 'out_warp')]), (coeffs, outputnode, [('out_file', 'out_coeff')]), (jacobian, outputnode, [('out_jacobian', 'out_jacobian')]), (merge, outputnode, [('merged_file', 'out_file')]) ]) return wf
def dr_stage2(i, **kwargs): subj, mask = i regress_moco = True desnorm = True demean = True for i in kwargs.keys(): if i == 'regress_moco': if kwargs[i]: regress_moco = True else: regress_moco = False if i == 'desnorm': if kwargs[i]: desnorm = True else: desnorm = False dr_s1_txt = os.path.join(OUTPUT, 'stage1', 'dr_stage1_idc_' + subj + '.txt') moco_txt = os.path.join(os.path.dirname(INPUT), subj, feat_pfix + subj + feat_sfix, 'mc', 'prefiltered_func_data_mcf.par') dr_s1 = read_txt_file(dr_s1_txt) if regress_moco: moco_pars = read_txt_file(moco_txt) for i in range(0, len(dr_s1)): for j in range(0,6): dr_s1[i].append(moco_pars[i][j]) dr_s1_moco_txt = os.path.join(OUTPUT, 'stage1', 'dr_stage1_moco_idc_' + subj + '.txt') write_txt_file(dr_s1, dr_s1_moco_txt) designFile = dr_s1_moco_txt else: designFile = dr_s1_txt iFile = os.path.join(os.path.dirname(INPUT), subj, feat_pfix + subj + feat_sfix, ff_data_name) oFile = os.path.join(OUTPUT, 'stage2', 'dr_stage2_idc_' + subj + '.nii.gz') ozFile = os.path.join(OUTPUT, 'stage2', 'dr_stage2_Z_idc_' + subj + '.nii.gz') if os.path.exists(oFile) and os.path.exists(ozFile): return mask = os.path.join(OUTPUT, 'stage1', 'mask.nii.gz') fsl_glm = fsl.GLM(in_file=iFile, design=designFile, terminal_output='stream', out_file=oFile, out_z_name=ozFile, mask=mask, des_norm=desnorm, demean=demean, output_type='NIFTI_GZ') cmd_out = os.path.join(OUTPUT, 'stage2', 'stage2_fslglm_idc_' + subj + '.out') write_cmd_out(fsl_glm.cmdline, cmd_out) fsl_glm.run() obname = os.path.join(OUTPUT, 'stage2', 'dr_stage2_idc_' + subj + '_ic') fslsplit = fsl.Split(dimension='t', in_file=oFile, out_base_name=obname, terminal_output='stream', output_type='NIFTI_GZ') fslsplit.run() obname = os.path.join(OUTPUT, 'stage2', 'dr_stage2_idc_Z' + subj + '_ic') fslsplit = fsl.Split(dimension='t', in_file=ozFile, out_base_name=obname, terminal_output='stream', output_type='NIFTI_GZ') fslsplit.run()
def _run_interface(self, runtime): splitter = fsl.Split(dimension='t', out_base_name='out_', in_file=self.inputs.in_file) split_outputs = splitter.run().outputs.out_files if len(split_outputs[0]) == 1: split_outputs = [split_outputs] self._out_file = self.extract_index(split_outputs, self.inputs.in_id) return runtime
def create_nonbrain_meansignal(name='nonbrain_meansignal'): nonbrain_meansignal = Workflow(name=name) inputspec = Node(utility.IdentityInterface(fields=['func_file']), name='inputspec') # Split raw 4D functional image into 3D niftis split_image = Node(fsl.Split(dimension='t', output_type='NIFTI'), name='split_image') # Create a brain mask for each of the 3D images brain_mask = MapNode(fsl.BET(frac=0.3, mask=True, no_output=True, robust=True), iterfield=['in_file'], name='brain_mask') # Merge the 3D masks into a 4D nifti (producing a separate mask per volume) merge_mask = Node(fsl.Merge(dimension='t'), name='merge_mask') # Reverse the 4D brain mask, to produce a 4D non brain mask reverse_mask = Node(fsl.ImageMaths(op_string='-sub 1 -mul -1'), name='reverse_mask') # Apply the mask on the raw functional data apply_mask = Node(fsl.ImageMaths(), name='apply_mask') # Highpass filter the non brain image highpass = create_highpass_filter(name='highpass') # Extract the mean signal from the non brain image mean_signal = Node(fsl.ImageMeants(), name='mean_signal') outputspec = Node(utility.IdentityInterface(fields=['nonbrain_regressor']), name='outputspec') nonbrain_meansignal.connect(inputspec, 'func_file', split_image, 'in_file') nonbrain_meansignal.connect(split_image, 'out_files', brain_mask, 'in_file') nonbrain_meansignal.connect(brain_mask, 'mask_file', merge_mask, 'in_files') nonbrain_meansignal.connect(merge_mask, 'merged_file', reverse_mask, 'in_file') nonbrain_meansignal.connect(reverse_mask, 'out_file', apply_mask, 'mask_file') nonbrain_meansignal.connect(inputspec, 'func_file', apply_mask, 'in_file') nonbrain_meansignal.connect(apply_mask, 'out_file', highpass, 'inputspec.in_file') nonbrain_meansignal.connect(highpass, 'outputspec.filtered_file', mean_signal, 'in_file') nonbrain_meansignal.connect(mean_signal, 'out_file', outputspec, 'nonbrain_regressor') return nonbrain_meansignal
def splitting(launcher, in_file, base_name): split = flsi.Split() split.inputs.in_file = in_file split.inputs.out_base_name = base_name split.inputs.dimension = 't' split.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI'} # 'mcflirt -in functional.nii -cost mutualinfo -out moco.nii' # >>> res = mcflt.run() # doctest: +SKIP launcher.run(split.cmdline)
def dwi_flirt(name='DWICoregistration', excl_nodiff=False, flirt_param={}): """ Generates a workflow for linear registration of dwi volumes """ inputnode = pe.Node(niu.IdentityInterface(fields=['reference', 'in_file', 'ref_mask', 'in_xfms', 'in_bval']), name='inputnode') initmat = pe.Node(niu.Function(input_names=['in_bval', 'in_xfms', 'excl_nodiff'], output_names=['init_xfms'], function=_checkinitxfm), name='InitXforms') initmat.inputs.excl_nodiff = excl_nodiff dilate = pe.Node(fsl.maths.MathsCommand(nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate') split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs') pick_ref = pe.Node(niu.Select(), name='Pick_b0') n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='Bias') enhb0 = pe.Node(niu.Function(input_names=['in_file', 'in_mask', 'clip_limit'], output_names=['out_file'], function=enhance), name='B0Equalize') enhb0.inputs.clip_limit = 0.015 enhdw = pe.MapNode(niu.Function(input_names=['in_file', 'in_mask'], output_names=['out_file'], function=enhance), name='DWEqualize', iterfield=['in_file']) flirt = pe.MapNode(fsl.FLIRT(**flirt_param), name='CoRegistration', iterfield=['in_file', 'in_matrix_file']) thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'], name='RemoveNegative') merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs') outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_xfms']), name='outputnode') wf = pe.Workflow(name=name) wf.connect([ (inputnode, split, [('in_file', 'in_file')]), (inputnode, dilate, [('ref_mask', 'in_file')]), (inputnode, enhb0, [('ref_mask', 'in_mask')]), (inputnode, initmat, [('in_xfms', 'in_xfms'), ('in_bval', 'in_bval')]), (inputnode, n4, [('reference', 'input_image'), ('ref_mask', 'mask_image')]), (dilate, flirt, [('out_file', 'ref_weight'), ('out_file', 'in_weight')]), (n4, enhb0, [('output_image', 'in_file')]), (split, enhdw, [('out_files', 'in_file')]), (dilate, enhdw, [('out_file', 'in_mask')]), (enhb0, flirt, [('out_file', 'reference')]), (enhdw, flirt, [('out_file', 'in_file')]), (initmat, flirt, [('init_xfms', 'in_matrix_file')]), (flirt, thres, [('out_file', 'in_file')]), (thres, merge, [('out_file', 'in_files')]), (merge, outputnode, [('merged_file', 'out_file')]), (flirt, outputnode, [('out_matrix_file', 'out_xfms')]) ]) return wf
def create_realign_flow(name='realign'): """Realign a time series to the middle volume using spline interpolation Uses MCFLIRT to realign the time series and ApplyWarp to apply the rigid body transformations using spline interpolation (unknown order). Example ------- >>> wf = create_realign_flow() >>> wf.inputs.inputspec.func = 'f3.nii' >>> wf.run() # doctest: +SKIP """ realignflow = pe.Workflow(name=name) inputnode = pe.Node(interface=util.IdentityInterface(fields=[ 'func', ]), name='inputspec') outputnode = pe.Node(interface=util.IdentityInterface( fields=['realigned_file', 'rms_files', 'par_file']), name='outputspec') start_dropper = pe.Node(util.Function( input_names=['in_vol_fn', 'n_frames'], output_names=['out_fn'], function=remove_first_n_frames), name='start_dropper') start_dropper.inputs.n_frames = 5 realigner = pe.Node(fsl.MCFLIRT(save_mats=True, stats_imgs=True, save_rms=True, save_plots=True), name='realigner') splitter = pe.Node(fsl.Split(dimension='t'), name='splitter') warper = pe.MapNode(fsl.ApplyWarp(interp='spline'), iterfield=['in_file', 'premat'], name='warper') joiner = pe.Node(fsl.Merge(dimension='t'), name='joiner') realignflow.connect(inputnode, 'func', start_dropper, 'in_vol_fn') realignflow.connect(start_dropper, 'out_fn', realigner, 'in_file') realignflow.connect(start_dropper, ('out_fn', select_volume, 'middle'), realigner, 'ref_vol') realignflow.connect(realigner, 'out_file', splitter, 'in_file') realignflow.connect(realigner, 'mat_file', warper, 'premat') realignflow.connect(realigner, 'variance_img', warper, 'ref_file') realignflow.connect(splitter, 'out_files', warper, 'in_file') realignflow.connect(warper, 'out_file', joiner, 'in_files') realignflow.connect(joiner, 'merged_file', outputnode, 'realigned_file') realignflow.connect(realigner, 'rms_files', outputnode, 'rms_files') realignflow.connect(realigner, 'par_file', outputnode, 'par_file') return realignflow
def modify_func_fm_run(FILEROOT): # Input is like sub-sub_run-01_epi.nii.gz (already in fmap dir) NII = FILEROOT + '.nii.gz' JSONFILE = FILEROOT + '.json' JSON_DAT = read_json(JSONFILE) TASKNAME = JSON_DAT['SeriesDescription'].split('_')[1] # Splits into AP/PA sets # sub-<label>[_ses-<label>][_acq-<label>][_ce-<label>]_dir-<label>[_run-<index>]_epi.json LROOT = FILEROOT.split('_') APNAME = LROOT[0] + '_dir-AP_' + '_'.join(LROOT[1:]) PANAME = LROOT[0] + '_dir-PA_' + '_'.join(LROOT[1:]) # Volumes 1/3 are AP, 2/4 PA SPLITTER = fsl.Split(in_file=NII, dimension='t', out_base_name='tmp') SPLITTER.run() MERGE_AP = fsl.Merge(in_files=['tmp0000.nii.gz', 'tmp0002.nii.gz'], dimension='t', merged_file=APNAME + '.nii.gz') MERGE_AP.run() MERGE_PA = fsl.Merge(in_files=['tmp0001.nii.gz', 'tmp0003.nii.gz'], dimension='t', merged_file=PANAME + '.nii.gz') MERGE_PA.run() os.remove(NII) os.remove(JSONFILE) for FILE in os.listdir('.'): if FILE.startswith('tmp0'): os.remove(FILE) # TODO: should we flip 1st volume and reorient? # Find which func data to use it for (right now assumes series description matches, may need to be more open). # Kludge: if stub of IntendedFor is there, populate with all runs os.chdir('..') INTENDEDFOR = [] if 'IntendedFor' in JSON_DAT: STUB_TASKS = JSON_DAT['IntendedFor'] for STUB in STUB_TASKS: INTEND_TASK = glob.glob('func/*task-{}_*bold.nii.gz'.format(STUB)) INTENDEDFOR += INTEND_TASK else: INTENDEDFOR = glob.glob('func/*task-{}_*bold.nii.gz'.format(TASKNAME)) JSON_DAT['IntendedFor'] = sorted(INTENDEDFOR) os.chdir('fmap') write_json(APNAME + '.json', JSON_DAT) write_json(PANAME + '.json', JSON_DAT)
def create_eddy_correct_pipeline(name="eddy_correct"): """Creates a pipeline that replaces eddy_correct script in FSL. It takes a series of diffusion weighted images and linearly corregisters them to one reference image. Example ------- >>> nipype_eddycorrect = create_eddy_correct_pipeline("nipype_eddycorrect") >>> nipype_eddycorrect.inputs.inputnode.in_file = 'diffusion.nii' >>> nipype_eddycorrect.inputs.inputnode.ref_num = 0 >>> nipype_eddycorrect.run() # doctest: +SKIP Inputs:: inputnode.in_file inputnode.ref_num Outputs:: outputnode.eddy_corrected """ inputnode = pe.Node( interface=util.IdentityInterface(fields=["in_file", "ref_num"]), name="inputnode") pipeline = pe.Workflow(name=name) split = pe.Node(fsl.Split(dimension='t'), name="split") pipeline.connect([(inputnode, split, [("in_file", "in_file")])]) pick_ref = pe.Node(util.Select(), name="pick_ref") pipeline.connect([(split, pick_ref, [("out_files", "inlist")]), (inputnode, pick_ref, [("ref_num", "index")])]) coregistration = pe.MapNode(fsl.FLIRT(no_search=True, padding_size=1), name="coregistration", iterfield=["in_file"]) pipeline.connect([(split, coregistration, [("out_files", "in_file")]), (pick_ref, coregistration, [("out", "reference")])]) merge = pe.Node(fsl.Merge(dimension="t"), name="merge") pipeline.connect([(coregistration, merge, [("out_file", "in_files")])]) outputnode = pe.Node( interface=util.IdentityInterface(fields=["eddy_corrected"]), name="outputnode") pipeline.connect([(merge, outputnode, [("merged_file", "eddy_corrected")]) ]) return pipeline
def test_spm(name='test_spm_3d'): """ A simple workflow to test SPM's installation. By default will split the 4D volume in time-steps. """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_data']), name='inputnode') dgr = pe.Node(nio.DataGrabber(template="feeds/data/fmri.nii.gz", outfields=['out_file'], sort_filelist=False), name='datasource') stc = pe.Node(spm.SliceTiming(num_slices=21, time_repetition=1.0, time_acquisition=2. - 2. / 32, slice_order=list(range(21, 0, -1)), ref_slice=10), name='stc') realign_estimate = pe.Node(spm.Realign(jobtype='estimate'), name='realign_estimate') realign_write = pe.Node(spm.Realign(jobtype='write'), name='realign_write') realign_estwrite = pe.Node(spm.Realign(jobtype='estwrite'), name='realign_estwrite') smooth = pe.Node(spm.Smooth(fwhm=[6, 6, 6]), name='smooth') if name == 'test_spm_3d': split = pe.Node(fsl.Split(dimension="t", output_type="NIFTI"), name="split") workflow.connect([(dgr, split, [(('out_file', _get_first), 'in_file') ]), (split, stc, [("out_files", "in_files")])]) elif name == 'test_spm_4d': gunzip = pe.Node(Gunzip(), name="gunzip") workflow.connect([(dgr, gunzip, [(('out_file', _get_first), 'in_file') ]), (gunzip, stc, [("out_file", "in_files")])]) else: raise NotImplementedError( 'No implementation of the test workflow \'{}\' was found'.format( name)) workflow.connect([ (inputnode, dgr, [('in_data', 'base_directory')]), (stc, realign_estimate, [('timecorrected_files', 'in_files')]), (realign_estimate, realign_write, [('modified_in_files', 'in_files')]), (stc, realign_estwrite, [('timecorrected_files', 'in_files')]), (realign_write, smooth, [('realigned_files', 'in_files')]) ]) return workflow
def _run_interface(self, runtime): from dipy.core import gradients splitter = fsl.Split(dimension='t', out_base_name='dwi_', in_file=self.inputs.in_file) gtab = gradients.gradient_table( bvals=self.inputs.in_bval, bvecs=self.inputs.in_bvec, b0_threshold=self.inputs.in_bval_threshold) masklist = list(gtab.b0s_mask) split_outputs = splitter.run().outputs.out_files self._b0s, self._dwis, self._all, self._indices = self.extract_sublists( split_outputs, masklist) return runtime
def fsl_SeparateSliceMoCo(input_file, par_folder): # scale Nifti data by factor 10 dataName = os.path.basename(input_file).split('.')[0] fslPath = scaleBy10(input_file, inv=False) mySplit = fsl.Split(in_file=fslPath, dimension='z', out_base_name=dataName) print(mySplit.cmdline) mySplit.run() os.remove(fslPath) # sparate ref and src volume in slices sliceFiles = findSlicesData(os.getcwd(), dataName) # refFiles = findSlicesData(os.getcwd(),'ref') print('For all slices ... ') # start to correct motions slice by slice for i in range(len(sliceFiles)): slc = sliceFiles[i] # ref = refFiles[i] # take epi as ref output_file = os.path.join(par_folder, os.path.basename(slc)) myMCFLIRT = fsl.preprocess.MCFLIRT(in_file=slc, out_file=output_file, save_plots=True, terminal_output='none') print(myMCFLIRT.cmdline) myMCFLIRT.run() os.remove(slc) # os.remove(ref) # merge slices to a single volume mcf_sliceFiles = findSlicesData(par_folder, dataName) output_file = os.path.join( os.path.dirname(input_file), os.path.basename(input_file).split('.')[0]) + '_mcf.nii.gz' myMerge = fsl.Merge(in_files=mcf_sliceFiles, dimension='z', merged_file=output_file) print(myMerge.cmdline) myMerge.run() for slc in mcf_sliceFiles: os.remove(slc) # unscale result data by factor 10ˆ(-1) output_file = scaleBy10(output_file, inv=True) return output_file
def _run_interface(self, runtime): split = fsl.Split(dimension='t', in_file=self.inputs.dwi_file) split_dwi_files = split.run().outputs.out_files split_bval_files, split_bvec_files = split_bvals_bvecs( self.inputs.bval_file, self.inputs.bvec_file, runtime) bvalues = np.loadtxt(self.inputs.bval_file) b0_indices = np.flatnonzero(bvalues < self.inputs.b0_threshold) b0_paths = [split_dwi_files[idx] for idx in b0_indices] self._results['dwi_files'] = split_dwi_files self._results['bval_files'] = split_bval_files self._results['bvec_files'] = split_bvec_files self._results['b0_images'] = b0_paths self._results['b0_indices'] = b0_indices.tolist() return runtime
def create_transform_pipeline(name='transfrom_timeseries'): # set fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # initiate workflow transform_ts = Workflow(name='transform_timeseries') # inputnode inputnode=Node(util.IdentityInterface(fields=['orig_ts', 'anat_head', 'mat_moco', 'fullwarp', 'resolution', 'brain_mask' ]), name='inputnode') # outputnode outputnode=Node(util.IdentityInterface(fields=['trans_ts', 'trans_ts_mean', 'trans_ts_masked', 'resamp_brain', 'brain_mask_resamp', 'out_dvars' ]), name='outputnode') #resample anatomy resample = Node(fsl.FLIRT(datatype='float', out_file='T1_resampled.nii.gz'), name = 'resample_anat') transform_ts.connect([(inputnode, resample, [('anat_head', 'in_file'), ('anat_head', 'reference'), ('resolution', 'apply_isoxfm') ]), (resample, outputnode, [('out_file', 'resamp_brain')]) ]) # split timeseries in single volumes split=Node(fsl.Split(dimension='t', out_base_name='timeseries'), name='split') transform_ts.connect([(inputnode, split, [('orig_ts','in_file')])]) # applymoco premat and fullwarpfield applywarp = MapNode(fsl.ApplyWarp(interp='spline', relwarp=True, out_file='rest2anat.nii.gz', datatype='float'), iterfield=['in_file', 'premat'], name='applywarp') transform_ts.connect([(split, applywarp, [('out_files', 'in_file')]), (inputnode, applywarp, [('mat_moco', 'premat'), ('fullwarp','field_file')]), (resample, applywarp, [('out_file', 'ref_file')]) ]) # re-concatenate volumes merge=Node(fsl.Merge(dimension='t', merged_file='rest2anat.nii.gz'), name='merge') transform_ts.connect([(applywarp,merge,[('out_file','in_files')]), (merge, outputnode, [('merged_file', 'trans_ts')])]) # calculate new mean tmean = Node(fsl.maths.MeanImage(dimension='T', out_file='rest_mean2anat_lowres.nii.gz'), name='tmean') transform_ts.connect([(merge, tmean, [('merged_file', 'in_file')]), (tmean, outputnode, [('out_file', 'trans_ts_mean')]) ]) # resample brain mask resample_brain = Node(afni.Resample(resample_mode='NN', outputtype='NIFTI_GZ', out_file='T1_brain_mask_lowres.nii.gz'), name = 'resample_brain') transform_ts.connect([(inputnode, resample_brain, [('brain_mask', 'in_file')]), (tmean, resample_brain, [('out_file', 'master')]), (resample_brain, outputnode, [('out_file', 'brain_mask_resamp')]) ]) #mask the transformed file mask = Node(fsl.ApplyMask(), name="mask") transform_ts.connect([(resample_brain,mask, [('out_file', 'mask_file')]), (merge, mask, [('merged_file', 'in_file')]), (mask, outputnode, [('out_file', 'trans_ts_masked')]) ]) #calculate DVARS dvars = Node(confounds.ComputeDVARS(save_all=True, save_plot=True), name="dvars") transform_ts.connect([(resample_brain, dvars, [('out_file', 'in_mask')]), (merge, dvars, [('merged_file', 'in_file')]), (dvars, outputnode, [('out_all', 'out_dvars')]) ]) return transform_ts
def build_core_nodes(self): """Build and connect the core nodes of the pipeline. Notes: - If `FSLOUTPUTTYPE` environment variable is not set, `nipype` takes NIFTI by default. Todo: - [x] Detect space automatically. - [ ] Allow for custom parcellations (See TODOs in utils). """ import nipype.interfaces.utility as niu import nipype.pipeline.engine as npe import nipype.interfaces.fsl as fsl import nipype.interfaces.freesurfer as fs import nipype.interfaces.mrtrix3 as mrtrix3 from clinica.lib.nipype.interfaces.mrtrix.preprocess import MRTransform from clinica.lib.nipype.interfaces.mrtrix3.reconst import EstimateFOD from clinica.lib.nipype.interfaces.mrtrix3.tracking import Tractography from clinica.utils.exceptions import ClinicaException, ClinicaCAPSError from clinica.utils.stream import cprint import clinica.pipelines.dwi_connectome.dwi_connectome_utils as utils from clinica.utils.mri_registration import convert_flirt_transformation_to_mrtrix_transformation # cprint('Building the pipeline...') # Nodes # ===== # B0 Extraction (only if space=b0) # ------------- split_node = npe.Node(name="Reg-0-DWI-B0Extraction", interface=fsl.Split()) split_node.inputs.output_type = "NIFTI_GZ" split_node.inputs.dimension = 't' select_node = npe.Node(name="Reg-0-DWI-B0Selection", interface=niu.Select()) select_node.inputs.index = 0 # B0 Brain Extraction (only if space=b0) # ------------------- mask_node = npe.Node(name="Reg-0-DWI-BrainMasking", interface=fsl.ApplyMask()) mask_node.inputs.output_type = "NIFTI_GZ" # T1-to-B0 Registration (only if space=b0) # --------------------- t12b0_reg_node = npe.Node(name="Reg-1-T12B0Registration", interface=fsl.FLIRT( dof=6, interp='spline', cost='normmi', cost_func='normmi', )) t12b0_reg_node.inputs.output_type = "NIFTI_GZ" # MGZ File Conversion (only if space=b0) # ------------------- t1_brain_conv_node = npe.Node(name="Reg-0-T1-T1BrainConvertion", interface=fs.MRIConvert()) wm_mask_conv_node = npe.Node(name="Reg-0-T1-WMMaskConvertion", interface=fs.MRIConvert()) # WM Transformation (only if space=b0) # ----------------- wm_transform_node = npe.Node(name="Reg-2-WMTransformation", interface=fsl.ApplyXFM()) wm_transform_node.inputs.apply_xfm = True # Nodes Generation # ---------------- label_convert_node = npe.MapNode( name="0-LabelsConversion", iterfield=['in_file', 'in_config', 'in_lut', 'out_file'], interface=mrtrix3.LabelConvert()) label_convert_node.inputs.in_config = utils.get_conversion_luts() label_convert_node.inputs.in_lut = utils.get_luts() # FSL flirt matrix to MRtrix matrix Conversion (only if space=b0) # -------------------------------------------- fsl2mrtrix_conv_node = npe.Node( name='Reg-2-FSL2MrtrixConversion', interface=niu.Function( input_names=[ 'in_source_image', 'in_reference_image', 'in_flirt_matrix', 'name_output_matrix' ], output_names=['out_mrtrix_matrix'], function=convert_flirt_transformation_to_mrtrix_transformation) ) # Parc. Transformation (only if space=b0) # -------------------- parc_transform_node = npe.MapNode( name="Reg-2-ParcTransformation", iterfield=["in_files", "out_filename"], interface=MRTransform()) # Response Estimation # ------------------- resp_estim_node = npe.Node(name="1a-ResponseEstimation", interface=mrtrix3.ResponseSD()) resp_estim_node.inputs.algorithm = 'tournier' # FOD Estimation # -------------- fod_estim_node = npe.Node(name="1b-FODEstimation", interface=EstimateFOD()) fod_estim_node.inputs.algorithm = 'csd' # Tracts Generation # ----------------- tck_gen_node = npe.Node(name="2-TractsGeneration", interface=Tractography()) tck_gen_node.inputs.n_tracks = self.parameters['n_tracks'] tck_gen_node.inputs.algorithm = 'iFOD2' # BUG: Info package does not exist # from nipype.interfaces.mrtrix3.base import Info # from distutils.version import LooseVersion # # if Info.looseversion() >= LooseVersion("3.0"): # tck_gen_node.inputs.select = self.parameters['n_tracks'] # elif Info.looseversion() <= LooseVersion("0.4"): # tck_gen_node.inputs.n_tracks = self.parameters['n_tracks'] # else: # from clinica.utils.exceptions import ClinicaException # raise ClinicaException("Your MRtrix version is not supported.") # Connectome Generation # --------------------- # only the parcellation and output filename should be iterable, the tck # file stays the same. conn_gen_node = npe.MapNode(name="3-ConnectomeGeneration", iterfield=['in_parc', 'out_file'], interface=mrtrix3.BuildConnectome()) # Print begin message # ------------------- print_begin_message = npe.MapNode(interface=niu.Function( input_names=['in_bids_or_caps_file'], function=utils.print_begin_pipeline), iterfield='in_bids_or_caps_file', name='WriteBeginMessage') # Print end message # ----------------- print_end_message = npe.MapNode(interface=niu.Function( input_names=['in_bids_or_caps_file', 'final_file'], function=utils.print_end_pipeline), iterfield=['in_bids_or_caps_file'], name='WriteEndMessage') # CAPS File names Generation # -------------------------- caps_filenames_node = npe.Node( name='CAPSFilenamesGeneration', interface=niu.Function(input_names='dwi_file', output_names=self.get_output_fields(), function=utils.get_caps_filenames)) # Connections # =========== # Computation of the diffusion model, tractography & connectome # ------------------------------------------------------------- self.connect([ (self.input_node, print_begin_message, [('dwi_file', 'in_bids_or_caps_file')]), # noqa (self.input_node, caps_filenames_node, [('dwi_file', 'dwi_file')]), # Response Estimation (self.input_node, resp_estim_node, [('dwi_file', 'in_file')] ), # Preproc. DWI # noqa (self.input_node, resp_estim_node, [('dwi_brainmask_file', 'in_mask')]), # B0 brain mask # noqa (self.input_node, resp_estim_node, [('grad_fsl', 'grad_fsl') ]), # bvecs and bvals # noqa (caps_filenames_node, resp_estim_node, [('response', 'wm_file')]), # output response filename # noqa # FOD Estimation (self.input_node, fod_estim_node, [('dwi_file', 'in_file')] ), # Preproc. DWI # noqa (resp_estim_node, fod_estim_node, [('wm_file', 'wm_txt')]), # Response (txt file) # noqa (self.input_node, fod_estim_node, [('dwi_brainmask_file', 'mask_file')]), # B0 brain mask # noqa (self.input_node, fod_estim_node, [('grad_fsl', 'grad_fsl')]), # T1-to-B0 matrix file # noqa (caps_filenames_node, fod_estim_node, [('fod', 'wm_odf')]), # output odf filename # noqa # Tracts Generation (fod_estim_node, tck_gen_node, [('wm_odf', 'in_file')] ), # ODF file # noqa (caps_filenames_node, tck_gen_node, [('tracts', 'out_file')]), # output tck filename # noqa # Label Conversion (self.input_node, label_convert_node, [('atlas_files', 'in_file')] ), # atlas image files # noqa (caps_filenames_node, label_convert_node, [ ('nodes', 'out_file') ]), # converted atlas image filenames # noqa # Connectomes Generation (tck_gen_node, conn_gen_node, [('out_file', 'in_file')]), # noqa (caps_filenames_node, conn_gen_node, [('connectomes', 'out_file') ]), # noqa ]) # Registration T1-DWI (only if space=b0) # ------------------- if self.parameters['dwi_space'] == 'b0': self.connect([ # MGZ Files Conversion (self.input_node, t1_brain_conv_node, [('t1_brain_file', 'in_file')]), # noqa (self.input_node, wm_mask_conv_node, [('wm_mask_file', 'in_file')]), # noqa # B0 Extraction (self.input_node, split_node, [('dwi_file', 'in_file')] ), # noqa (split_node, select_node, [('out_files', 'inlist')]), # noqa # Masking (select_node, mask_node, [('out', 'in_file')]), # B0 # noqa (self.input_node, mask_node, [('dwi_brainmask_file', 'mask_file')]), # Brain mask # noqa # T1-to-B0 Registration (t1_brain_conv_node, t12b0_reg_node, [('out_file', 'in_file')] ), # Brain # noqa (mask_node, t12b0_reg_node, [('out_file', 'reference') ]), # B0 brain-masked # noqa # WM Transformation (wm_mask_conv_node, wm_transform_node, [('out_file', 'in_file')]), # Brain mask # noqa (mask_node, wm_transform_node, [('out_file', 'reference') ]), # BO brain-masked # noqa (t12b0_reg_node, wm_transform_node, [ ('out_matrix_file', 'in_matrix_file') ]), # T1-to-B0 matrix file # noqa # FSL flirt matrix to MRtrix matrix Conversion (t1_brain_conv_node, fsl2mrtrix_conv_node, [('out_file', 'in_source_image')]), # noqa (mask_node, fsl2mrtrix_conv_node, [('out_file', 'in_reference_image')]), # noqa (t12b0_reg_node, fsl2mrtrix_conv_node, [('out_matrix_file', 'in_flirt_matrix')]), # noqa # Apply registration without resampling on parcellations (label_convert_node, parc_transform_node, [('out_file', 'in_files')]), # noqa (fsl2mrtrix_conv_node, parc_transform_node, [('out_mrtrix_matrix', 'linear_transform')]), # noqa (caps_filenames_node, parc_transform_node, [('nodes', 'out_filename')]), # noqa ]) # Special care for Parcellation & WM mask # --------------------------------------- if self.parameters['dwi_space'] == 'b0': self.connect([ (wm_transform_node, tck_gen_node, [('out_file', 'seed_image') ]), # noqa (parc_transform_node, conn_gen_node, [('out_file', 'in_parc') ]), # noqa (parc_transform_node, self.output_node, [('out_file', 'nodes') ]), # noqa ]) elif self.parameters['dwi_space'] == 'T1w': self.connect([ (self.input_node, tck_gen_node, [('wm_mask_file', 'seed_image') ]), # noqa (label_convert_node, conn_gen_node, [('out_file', 'in_parc') ]), # noqa (label_convert_node, self.output_node, [('out_file', 'nodes') ]), # noqa ]) else: raise ClinicaCAPSError( 'Bad preprocessed DWI space. Please check your CAPS ' 'folder.') # Outputs # ------- self.connect([ (resp_estim_node, self.output_node, [('wm_file', 'response')]), (fod_estim_node, self.output_node, [('wm_odf', 'fod')]), (tck_gen_node, self.output_node, [('out_file', 'tracts')]), (conn_gen_node, self.output_node, [('out_file', 'connectomes')]), (self.input_node, print_end_message, [('dwi_file', 'in_bids_or_caps_file')]), (conn_gen_node, print_end_message, [('out_file', 'final_file')]), ])
def _b1resize( datapath, b1name, regdir, b1FAmap=None, outfolder=Path.cwd(), inrefname=None, outrefname="Ref_CESTres.nii.gz", phantom=False, ): """B1_RESIZE - Preprocesses B1 Data for Use with FABBER Takes the raw B1 data and processes it into a B1 map. Also flirts it into the reference volume space. Does not apply any actual registration, just resamples it so it is in the same resolution as the Reference data. Parameters: ----------- datapath : pathlib Path object The path to the datafolder b1name : str The name of the B1+ scan to register. regdir : pathlib Path object The registration directory being used for all of the registration computations. b1FAmap : str The name of the B1+ FA map to register. If None, will assume this is in the b1name file. outfolder : pathlib Path object The output directory of the data being analyzed. If blank, the datapath directory will be used. refname : str The name of the reference volume to register b1 to. If blank, the file Ref_CESTres.nii.gz will be used. Returns: -------- None Author: asmith Version: 1.0 Changelog: 20181217 - initial creation """ b1dir = sorted(datapath.glob("*{0}*.nii.gz".format(b1name))) if len(b1dir) > 1 and b1FAmap is None: fslmerge = fsl.Merge() fslmerge.inputs.in_files = [str(i) for v, i in enumerate(b1dir)] fslmerge.inputs.dimension = "t" fslmerge.inputs.merged_file = str(regdir / f"{b1name}_merged.nii.gz") fslmerge.run() b1dir = regdir / f"{b1name}_merged.nii.gz" try: b1vol = nib.load(str(b1dir[1])) except TypeError: b1vol = nib.load(str(b1dir)) except IndexError: b1vol = nib.load(str(b1dir[0])) except: print(f"Unexpected Error: {sys.exc_info()[0]}") if b1FAmap is None and b1vol.ndim < 4: if len(b1dir) > 1: b1FAmap = Path(b1dir[-1].stem).stem else: raise NoFAMapError( "No FA Map specified for B1 Data!\nProvide a FA map to proceed!" ) if b1FAmap is None and b1vol.shape[3] > 2: # Split Data fsplt = fsl.Split() fsplt.inputs.in_file = str(b1dir) fsplt.inputs.out_base_name = str(regdir / "DREAM_s") fsplt.inputs.dimension = "t" fsplt.run() # set variables so anatomical and FA map are defined b1dirs = sorted(regdir.glob("*DREAM_s*.nii.gz")) b1dir = str(b1dirs[1]) b1FAmapdir = str(b1dirs[-1]) elif b1FAmap is None and b1vol.shape[3] == 2: # Split Data fsplt = fsl.Split() fsplt.inputs.in_file = str(b1dir) fsplt.inputs.out_base_name = str(regdir / "DREAM_s") fsplt.inputs.dimension = "t" fsplt.run() # Split b1vol into component anatomicals for registration b1dirs = sorted(regdir.glob("*DREAM_s*.nii.gz")) b1dir = str(b1dirs[1]) # Define b1FAmap for use in downstream registration b1FAmapdir = regdir / "B1map.nii.gz" # Build FA map from anatomical maps fmaths = fsl.ImageMaths() fmaths.inputs.in_file = str(b1dirs[0]) fmaths.inputs.op_string = "-mul 2 -div" fmaths.inputs.in_file2 = str(b1dirs[1]) fmaths.inputs.out_file = str(regdir / "tmp1.nii.gz") fmaths.run() fmaths = fsl.ImageMaths() fmaths.inputs.in_file = str(regdir / "tmp1.nii.gz") fmaths.inputs.op_string = f"-sqrt -atan -div {radians(60)} -mul 600" fmaths.inputs.out_file = str(b1FAmapdir) fmaths.run() else: b1FAmapdir = sorted(datapath.glob(f"*{b1FAmap}*.nii.gz"))[0] try: b1dir = str(b1dir[1]) except IndexError: b1dir = str(b1dir[0]) b1splt = fsl.ExtractROI() b1splt.inputs.in_file = b1dir b1splt.inputs.roi_file = str(regdir / "B1_1.nii.gz") b1splt.inputs.t_size = 1 b1splt.inputs.t_min = 0 b1splt.run() # Run FAST on B1 input data to get better registration b1FAST = fsl.FAST() b1FAST.inputs.in_files = str(regdir / "B1_1.nii.gz") b1FAST.inputs.out_basename = str(regdir / "B1_bc") b1FAST.inputs.output_biascorrected = True b1FAST.inputs.no_pve = True b1FAST.inputs.output_type = "NIFTI_GZ" b1FAST.run(ignore_exception=True) if phantom: # _FOVDiff(str(regdir / "B1_bc_restore.nii.gz"), str(inrefdir), "B1resred.txt", regdir=regdir) # Flirt B1 Image Data to Original Reference volume flt = fsl.FLIRT() flt.inputs.in_file = str(regdir / "B1_bc_restore.nii.gz") flt.inputs.reference = str(regdir / "Ref_bc_restore.nii.gz") flt.inputs.out_file = str(regdir / "B1_to_ref.nii.gz") flt.inputs.output_type = "NIFTI_GZ" flt.inputs.rigid2D = True # flt.inputs.in_matrix_file = str(regdir / "B1resred.txt") # flt.inputs.apply_xfm=True flt.inputs.out_matrix_file = str(regdir / "B1resred.txt") flt.run() else: # Flirt B1 Image Data to Original Reference volume flt = fsl.FLIRT() flt.inputs.in_file = str(regdir / "B1_bc_restore.nii.gz") flt.inputs.reference = str(regdir / "Ref_bc_restore.nii.gz") flt.inputs.out_file = str(regdir / "B1_to_ref.nii.gz") flt.inputs.output_type = "NIFTI_GZ" flt.inputs.out_matrix_file = str(regdir / "B1resred.txt") flt.run() if len(_slicenumber2d) > 0: # Flirt B1 Map Data to Original Reference volume flt = fsl.FLIRT() flt.inputs.in_file = str(b1FAmapdir) flt.inputs.reference = str(regdir / "Ref_bc_restore.nii.gz") flt.inputs.out_file = str(regdir / "B1map_to_ref.nii.gz") flt.inputs.output_type = "NIFTI_GZ" flt.inputs.in_matrix_file = str(regdir / "B1resred.txt") flt.inputs.apply_xfm = True flt.inputs.out_matrix_file = str(regdir / "B1resred.txt") flt.run() if _slicenumber2d[1] > 1: # Run for B1 Map fsl.ExtractROI( in_file=str(regdir / "B1map_to_ref.nii.gz"), roi_file=str(regdir / "B1map_sROI.nii.gz"), x_min=0, x_size=-1, y_min=0, y_size=-1, z_min=_slicenumber2d[0] - 1, z_size=_slicenumber2d[1], ).run() else: # Run for B1 Map fsl.ExtractROI( in_file=str(regdir / "B1map_to_ref.nii.gz"), roi_file=str(regdir / "B1map_sROI.nii.gz"), x_min=0, x_size=-1, y_min=0, y_size=-1, z_min=_slicenumber2d[0], z_size=_slicenumber2d[1], ).run() # Warp 2D B1map to CEST Space flt.inputs.in_file = str(regdir / "B1map_sROI.nii.gz") flt.inputs.out_file = str(regdir / "B1map_resred.nii.gz") flt.inputs.reference = str(regdir / outrefname) flt.inputs.in_matrix_file = str(regdir / "Ref_CESTres.txt") flt.inputs.apply_xfm = True flt.inputs.rigid2D = True flt.inputs.out_matrix_file = str(regdir / "B1toCEST.txt") flt.run() else: # Combine B1->Ref matrix with Ref->CEST matrix xfmcomb = fsl.ConvertXFM() xfmcomb.inputs.in_file = str(regdir / "B1resred.txt") xfmcomb.inputs.in_file2 = str(regdir / "Ref_CESTres.txt") xfmcomb.inputs.concat_xfm = True xfmcomb.inputs.out_file = str(regdir / "B1toCEST.txt") xfmcomb.run() # Use combine Ref->CEST matrix to register B1 FA map to CEST data flt.inputs.in_file = str(b1FAmapdir) flt.inputs.out_file = str(regdir / "B1map_resred.nii.gz") flt.inputs.reference = str(regdir / outrefname) flt.inputs.in_matrix_file = str(regdir / "B1toCEST.txt") flt.inputs.apply_xfm = True flt.inputs.out_matrix_file = str(regdir / "B1toCEST.txt") flt.run() # Convert Registered FA Map to Fraction of nominal angle and move to analysis folder fmaths = fsl.ImageMaths() fmaths.inputs.in_file = str(regdir / "B1map_resred.nii.gz") fmaths.inputs.op_string = "-div 600 -mul" fmaths.inputs.in_file2 = str(regdir / "Ref_Mask.nii.gz") fmaths.inputs.out_file = str(outfolder / "B1map_resize.nii.gz") fmaths.run() return None
def ecc_pipeline(name='eddy_correct'): """ ECC stands for Eddy currents correction. Creates a pipeline that corrects for artifacts induced by Eddy currents in dMRI sequences. It takes a series of diffusion weighted images and linearly co-registers them to one reference image (the average of all b0s in the dataset). DWIs are also modulated by the determinant of the Jacobian as indicated by [Jones10]_ and [Rohde04]_. A list of rigid transformation matrices can be provided, sourcing from a :func:`.hmc_pipeline` workflow, to initialize registrations in a *motion free* framework. A list of affine transformation matrices is available as output, so that transforms can be chained (discussion `here <https://github.com/nipy/nipype/pull/530#issuecomment-14505042>`_). .. admonition:: References .. [Jones10] Jones DK, `The signal intensity must be modulated by the determinant of the Jacobian when correcting for eddy currents in diffusion MRI <http://cds.ismrm.org/protected/10MProceedings/files/1644_129.pdf>`_, Proc. ISMRM 18th Annual Meeting, (2010). .. [Rohde04] Rohde et al., `Comprehensive Approach for Correction of Motion and Distortion in Diffusion-Weighted MRI <http://stbb.nichd.nih.gov/pdf/com_app_cor_mri04.pdf>`_, MRM 51:103-114 (2004). Example ------- >>> from nipype.workflows.dmri.fsl.artifacts import ecc_pipeline >>> ecc = ecc_pipeline() >>> ecc.inputs.inputnode.in_file = 'diffusion.nii' >>> ecc.inputs.inputnode.in_bval = 'diffusion.bval' >>> ecc.inputs.inputnode.in_mask = 'mask.nii' >>> ecc.run() # doctest: +SKIP Inputs:: inputnode.in_file - input dwi file inputnode.in_mask - weights mask of reference image (a file with data \ range sin [0.0, 1.0], indicating the weight of each voxel when computing the \ metric. inputnode.in_bval - b-values table inputnode.in_xfms - list of matrices to initialize registration (from \ head-motion correction) Outputs:: outputnode.out_file - corrected dwi file outputnode.out_xfms - list of transformation matrices """ from nipype.workflows.data import get_flirt_schedule params = dict(dof=12, no_search=True, interp='spline', bgvalue=0, schedule=get_flirt_schedule('ecc')) # cost='normmi', cost_func='normmi', bins=64, inputnode = pe.Node(niu.IdentityInterface( fields=['in_file', 'in_bval', 'in_mask', 'in_xfms']), name='inputnode') avg_b0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'], output_names=['out_file'], function=b0_average), name='b0_avg') pick_dws = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval', 'b'], output_names=['out_file'], function=extract_bval), name='ExtractDWI') pick_dws.inputs.b = 'diff' flirt = dwi_flirt(flirt_param=params, excl_nodiff=True) mult = pe.MapNode(fsl.BinaryMaths(operation='mul'), name='ModulateDWIs', iterfield=['in_file', 'operand_value']) thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'], name='RemoveNegative') split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs') get_mat = pe.Node(niu.Function(input_names=['in_bval', 'in_xfms'], output_names=['out_files'], function=recompose_xfm), name='GatherMatrices') merge = pe.Node(niu.Function( input_names=['in_dwi', 'in_bval', 'in_corrected'], output_names=['out_file'], function=recompose_dwi), name='MergeDWIs') outputnode = pe.Node( niu.IdentityInterface(fields=['out_file', 'out_xfms']), name='outputnode') wf = pe.Workflow(name=name) wf.connect([(inputnode, avg_b0, [('in_file', 'in_dwi'), ('in_bval', 'in_bval')]), (inputnode, pick_dws, [('in_file', 'in_dwi'), ('in_bval', 'in_bval')]), (inputnode, merge, [('in_file', 'in_dwi'), ('in_bval', 'in_bval')]), (inputnode, flirt, [('in_mask', 'inputnode.ref_mask'), ('in_xfms', 'inputnode.in_xfms'), ('in_bval', 'inputnode.in_bval')]), (inputnode, get_mat, [('in_bval', 'in_bval')]), (avg_b0, flirt, [('out_file', 'inputnode.reference')]), (pick_dws, flirt, [('out_file', 'inputnode.in_file')]), (flirt, get_mat, [('outputnode.out_xfms', 'in_xfms')]), (flirt, mult, [(('outputnode.out_xfms', _xfm_jacobian), 'operand_value')]), (flirt, split, [('outputnode.out_file', 'in_file')]), (split, mult, [('out_files', 'in_file')]), (mult, thres, [('out_file', 'in_file')]), (thres, merge, [('out_file', 'in_corrected')]), (get_mat, outputnode, [('out_files', 'out_xfms')]), (merge, outputnode, [('out_file', 'out_file')])]) return wf
def b0_flirt_pipeline(num_b0s, name="b0_coregistration"): """ Rigid registration of the B0 dataset onto the first volume. Rigid registration is achieved using FLIRT and the normalized correlation. Args: num_b0s (int): Number of the B0 volumes in the dataset. name (str): Name of the workflow. Inputnode: in_file(str): B0 dataset. Outputnode out_b0_reg(str): The set of B0 volumes registered to the first volume. Returns: The workflow """ import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe from nipype.interfaces import fsl from clinica.utils.dwi import merge_volumes_tdim inputnode = pe.Node(niu.IdentityInterface(fields=["in_file"]), name="inputnode") fslroi_ref = pe.Node(fsl.ExtractROI(args="0 1"), name="b0_reference") tsize = num_b0s - 1 fslroi_moving = pe.Node(fsl.ExtractROI(args="1 " + str(tsize)), name="b0_moving") split_moving = pe.Node(fsl.Split(dimension="t"), name="split_b0_moving") bet_ref = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True), name="bet_ref") dilate = pe.Node( fsl.maths.MathsCommand(nan2zeros=True, args="-kernel sphere 5 -dilM"), name="mask_dilate", ) flirt = pe.MapNode( fsl.FLIRT( interp="spline", dof=6, bins=50, save_log=True, cost="corratio", cost_func="corratio", padding_size=10, searchr_x=[-4, 4], searchr_y=[-4, 4], searchr_z=[-4, 4], fine_search=1, coarse_search=10, ), name="b0_co_registration", iterfield=["in_file"], ) merge = pe.Node(fsl.Merge(dimension="t"), name="merge_registered_b0s") thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=["in_file"], name="remove_negative") insert_ref = pe.Node( niu.Function( input_names=["in_file1", "in_file2"], output_names=["out_file"], function=merge_volumes_tdim, ), name="concat_ref_moving", ) outputnode = pe.Node( niu.IdentityInterface(fields=["out_file", "out_xfms"]), name="outputnode") wf = pe.Workflow(name=name) wf.connect([ (inputnode, fslroi_ref, [("in_file", "in_file")]), (inputnode, fslroi_moving, [("in_file", "in_file")]), (fslroi_moving, split_moving, [("roi_file", "in_file")]), (fslroi_ref, bet_ref, [("roi_file", "in_file")]), (bet_ref, dilate, [("mask_file", "in_file")]), (dilate, flirt, [("out_file", "ref_weight"), ("out_file", "in_weight")]), (fslroi_ref, flirt, [("roi_file", "reference")]), (split_moving, flirt, [("out_files", "in_file")]), (flirt, thres, [("out_file", "in_file")]), (thres, merge, [("out_file", "in_files")]), (merge, insert_ref, [("merged_file", "in_file2")]), (fslroi_ref, insert_ref, [("roi_file", "in_file1")]), (insert_ref, outputnode, [("out_file", "out_file")]), (flirt, outputnode, [("out_matrix_file", "out_xfms")]), ]) return wf
def _cestreg( datapath, cestprefix, offsetspath, regdir, outfolder=Path.cwd(), CESTRefImage=0, phantom=False, ): """ _cestreg7T - Co-registers CEST data, and then registers that data to the high resolution reference measurement set up in _reg_ref_7T """ cestdir = sorted(datapath.glob(f"*{cestprefix}*.nii.gz")) offsets = np.loadtxt(str(offsetspath)) n_ones = np.where(abs(offsets) < 1)[0] cestoutname = cestprefix cestvol = nib.load(str(cestdir[0])) if cestvol.ndim == 4: fslsplit = fsl.Split() fslsplit.inputs.in_file = str(cestdir[0]) fslsplit.inputs.out_base_name = str(regdir / f"{cestoutname}_Presplit") fslsplit.inputs.output_type = "NIFTI_GZ" fslsplit.inputs.dimension = "t" fslsplit.run() cestdir = sorted((regdir.glob(f"*{cestoutname}_Presplit*.nii.gz"))) concatname1 = [str(i) for v, i in enumerate(cestdir) if v < n_ones[1]] concatname2 = [str(i) for v, i in enumerate(cestdir) if v > n_ones[-1]] concatname2.append(str(cestdir[CESTRefImage])) # Merge first half of files fslmerge = fsl.Merge() fslmerge.inputs.in_files = concatname1 fslmerge.inputs.dimension = "t" fslmerge.inputs.merged_file = str(regdir / f"{cestoutname}_merged1.nii.gz") fslmerge.run() # Merge second half of files fslmerge.inputs.in_files = concatname2 fslmerge.inputs.merged_file = str(regdir / f"{cestoutname}_merged2.nii.gz") fslmerge.run() # Motion-Correct Data mcflirt = fsl.MCFLIRT() mcflirt.inputs.in_file = str(regdir / f"{cestoutname}_merged1.nii.gz") mcflirt.inputs.ref_vol = CESTRefImage mcflirt.inputs.out_file = str(regdir / f"{cestoutname}_merged1_mcf.nii.gz") if cestvol.ndim < 3: mcflirt.inputs.args = "-2d" mcflirt.run() mcflirt = fsl.MCFLIRT() mcflirt.inputs.in_file = str(regdir / f"{cestoutname}_merged2.nii.gz") mcflirt.inputs.ref_vol = len(concatname2) - 1 mcflirt.inputs.out_file = str(regdir / f"{cestoutname}_merged2_mcf.nii.gz") if cestvol.ndim < 3: mcflirt.inputs.args = "-2d" mcflirt.run() # Extract one datapoint near middle of CEST fslroi = fsl.ExtractROI() fslroi.inputs.in_file = str(regdir / f"{cestoutname}_merged1_mcf.nii.gz") fslroi.inputs.roi_file = str(regdir / f"{cestoutname}_mcfMin.nii.gz") fslroi.inputs.t_min = len(concatname1) - 1 fslroi.inputs.t_size = 1 fslroi.run() # Remove extra reference image in merged2 fslroi = fsl.ExtractROI() fslroi.inputs.in_file = str(regdir / f"{cestoutname}_merged2_mcf.nii.gz") fslroi.inputs.roi_file = str(regdir / f"{cestoutname}_merged2_mcf.nii.gz") fslroi.inputs.t_min = 0 fslroi.inputs.t_size = len(concatname2) - 1 fslroi.run() concatname3 = [str(i) for v, i in enumerate(cestdir) if v in n_ones[1:]] concatname3.insert(0, str(regdir / f"{cestoutname}_mcfMin.nii.gz")) fslmerge.inputs.in_files = concatname3 fslmerge.inputs.merged_file = str(regdir / f"{cestoutname}_merged3.nii.gz") fslmerge.run() # MCFLIRT middle range (e.g. where abs(offsets) < 1) mcflirt = fsl.MCFLIRT() mcflirt.inputs.in_file = str(regdir / f"{cestoutname}_merged3.nii.gz") mcflirt.inputs.ref_vol = 0 mcflirt.inputs.out_file = str(regdir / f"{cestoutname}_merged3_mcf.nii.gz") mcflirt.inputs.cost = "normmi" if cestvol.ndim < 3: mcflirt.inputs.args = "-2d" mcflirt.run() fslroi = fsl.ExtractROI() fslroi.inputs.in_file = str(regdir / f"{cestoutname}_merged3_mcf.nii.gz") fslroi.inputs.roi_file = str(regdir / f"{cestoutname}_mcfMid.nii.gz") fslroi.inputs.t_min = 1 fslroi.inputs.t_size = len(n_ones) - 1 fslroi.run() # Merge all CEST images together fslmerge = fsl.Merge() fslmerge.inputs.in_files = [ str(regdir / f"{cestoutname}_merged1_mcf.nii.gz"), str(regdir / f"{cestoutname}_mcfMid.nii.gz"), str(regdir / f"{cestoutname}_merged2_mcf.nii.gz"), ] fslmerge.inputs.dimension = "t" fslmerge.inputs.merged_file = str(regdir / f"{cestoutname}_mergedTot_mcf.nii.gz") fslmerge.run() # Separate CEST reference image to use as registration template for CEST data fslroi = fsl.ExtractROI() fslroi.inputs.in_file = str(regdir / f"{cestoutname}_mergedTot_mcf.nii.gz") fslroi.inputs.roi_file = str(regdir / f"{cestoutname}_prereg.nii.gz") fslroi.inputs.t_min = CESTRefImage fslroi.inputs.t_size = 1 fslroi.run() # Run FAST on Ref image cestfast = fsl.FAST() cestfast.inputs.in_files = str(regdir / f"{cestoutname}_prereg.nii.gz") cestfast.inputs.out_basename = str(regdir / f"{cestoutname}_bc") cestfast.inputs.output_biascorrected = True cestfast.inputs.output_biasfield = True cestfast.inputs.no_pve = True cestfast.run(ignore_exception=True) # Skull Strip CEST Image if phantom: fmaths = fsl.ImageMaths() fmaths.inputs.in_file = str(regdir / f"{cestoutname}_bc_restore.nii.gz") fmaths.inputs.out_file = str(regdir / f"{cestoutname}_prereg_brain.nii.gz") fmaths.inputs.op_string = "-thrp 10" fmaths.run() fmaths.inputs.in_file = str(regdir / f"{cestoutname}_prereg_brain.nii.gz") fmaths.inputs.out_file = str(regdir / f"{cestoutname}_prereg_brain_mask.nii.gz") fmaths.inputs.op_string = "-bin" fmaths.run() else: betcest0 = fsl.BET() betcest0.inputs.in_file = str(regdir / f"{cestoutname}_bc_restore.nii.gz") betcest0.inputs.out_file = str(regdir / f"{cestoutname}_prereg_brain.nii.gz") betcest0.inputs.mask = True if ( cestvol.ndim <= 2 or cestvol.shape[3] < 5 or cestvol.header.get_zooms()[2] * cestvol.shape[2] < 25 ): betcest0.inputs.padding = True betcest0.run() # BET rest of data fmaths = fsl.ImageMaths() fmaths.inputs.in_file = str(regdir / f"{cestoutname}_mergedTot_mcf.nii.gz") fmaths.inputs.op_string = "-mul" fmaths.inputs.in_file2 = str(regdir / f"{cestoutname}_prereg_brain_mask.nii.gz") fmaths.inputs.out_file = str(regdir / f"{cestoutname}_mergedTot_bc_brain.nii.gz") fmaths.run() # Move CEST data to analysis folder shutil.copyfile( str(regdir / f"{cestoutname}_mergedTot_bc_brain.nii.gz"), str(outfolder / f"{cestoutname}_reg.nii.gz"), ) # Correct Mask so it is set at extent of CEST data fslmaths = fsl.ImageMaths() fslmaths.inputs.in_file = str(regdir / "Ref_Mask.nii.gz") fslmaths.inputs.op_string = "-thr 0.95 -mul" fslmaths.inputs.in_file2 = str(outfolder / f"{cestoutname}_reg.nii.gz") fslmaths.inputs.args = "-bin" fslmaths.inputs.out_file = str(regdir / "Ref_Mask.nii.gz") fslmaths.run() # Copy Corrected mask into Analysis folder shutil.copyfile(str(regdir / "Ref_Mask.nii.gz"), str(outfolder / "Ref_Mask.nii.gz")) # Change mask to only a single volume (instead of 4D volume from CEST data) maskroi = fsl.ExtractROI() maskroi.inputs.in_file = str(outfolder / "Ref_Mask.nii.gz") maskroi.inputs.roi_file = str(outfolder / "Ref_Mask.nii.gz") maskroi.inputs.t_min = 0 maskroi.inputs.t_size = 1 maskroi.run() return None
def epi_pipeline(name="susceptibility_distortion_correction_using_t1"): """ This workflow allows to correct for echo-planareinduced susceptibility artifacts without fieldmap (e.g. ADNI Database) by elastically register DWIs to their respective baseline T1-weighted structural scans using an inverse consistent registration algorithm with a mutual information cost function (SyN algorithm). This workflow allows also a coregistration of DWIs with their respective baseline T1-weighted structural scans in order to latter combine tracks and cortex parcelation. .. warning:: This workflow rotates the `b`-vectors' .. References .. Nir et al. (Neurobiology of Aging 2015)- Connectivity network measures predict volumetric atrophy in mild cognitive impairment Leow et al. (IEEE Trans Med Imaging 2007)- Statistical Properties of Jacobian Maps and the Realization of Unbiased Large Deformation Nonlinear Image Registration Example ------- >>> epi = epi_pipeline() >>> epi.inputs.inputnode.DWI = 'DWI.nii' >>> epi.inputs.inputnode.bvec = 'bvec.txt' >>> epi.inputs.inputnode.T1 = 'T1.nii' >>> epi.run() # doctest: +SKIP """ import nipype.interfaces.c3 as c3 import nipype.interfaces.fsl as fsl import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe from clinica.pipelines.dwi_preprocessing_using_t1.dwi_preprocessing_using_t1_utils import ( ants_combin_transform, ants_registration_syn_quick, ants_warp_image_multi_transform, change_itk_transform_type, create_jacobian_determinant_image, expend_matrix_list, rotate_bvecs, ) inputnode = pe.Node(niu.IdentityInterface(fields=["T1", "DWI", "bvec"]), name="inputnode") split = pe.Node(fsl.Split(dimension="t"), name="SplitDWIs") pick_ref = pe.Node(niu.Select(), name="Pick_b0") pick_ref.inputs.index = [0] flirt_b0_2_T1 = pe.Node(interface=fsl.FLIRT(dof=6), name="flirt_B0_2_T1") flirt_b0_2_T1.inputs.interp = "spline" flirt_b0_2_T1.inputs.cost = "normmi" flirt_b0_2_T1.inputs.cost_func = "normmi" apply_xfm = pe.Node(interface=fsl.preprocess.ApplyXFM(), name="apply_xfm") apply_xfm.inputs.apply_xfm = True expend_matrix = pe.Node( interface=niu.Function( input_names=["in_matrix", "in_bvec"], output_names=["out_matrix_list"], function=expend_matrix_list, ), name="expend_matrix", ) rot_bvec = pe.Node( niu.Function( input_names=["in_matrix", "in_bvec"], output_names=["out_file"], function=rotate_bvecs, ), name="Rotate_Bvec", ) antsRegistrationSyNQuick = pe.Node( interface=niu.Function( input_names=["fix_image", "moving_image"], output_names=[ "image_warped", "affine_matrix", "warp", "inverse_warped", "inverse_warp", ], function=ants_registration_syn_quick, ), name="antsRegistrationSyNQuick", ) c3d_flirt2ants = pe.Node(c3.C3dAffineTool(), name="fsl_reg_2_itk") c3d_flirt2ants.inputs.itk_transform = True c3d_flirt2ants.inputs.fsl2ras = True change_transform = pe.Node( niu.Function( input_names=["input_affine_file"], output_names=["updated_affine_file"], function=change_itk_transform_type, ), name="change_transform_type", ) merge_transform = pe.Node(niu.Merge(3), name="MergeTransforms") apply_transform = pe.MapNode( interface=niu.Function( input_names=["fix_image", "moving_image", "ants_warp_affine"], output_names=["out_warp_field", "out_warped"], function=ants_combin_transform, ), iterfield=["moving_image"], name="warp_filed", ) jacobian = pe.MapNode( interface=niu.Function( input_names=["imageDimension", "deformationField", "outputImage"], output_names=["outputImage"], function=create_jacobian_determinant_image, ), iterfield=["deformationField"], name="jacobian", ) jacobian.inputs.imageDimension = 3 jacobian.inputs.outputImage = "Jacobian_image.nii.gz" jacmult = pe.MapNode( fsl.MultiImageMaths(op_string="-mul %s"), iterfield=["in_file", "operand_files"], name="ModulateDWIs", ) thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=["in_file"], name="RemoveNegative") merge = pe.Node(fsl.Merge(dimension="t"), name="MergeDWIs") outputnode = pe.Node( niu.IdentityInterface(fields=[ "DWI_2_T1_Coregistration_matrix", "epi_correction_deformation_field", "epi_correction_affine_transform", "epi_correction_image_warped", "DWIs_epicorrected", "warp_epi", "out_bvec", ]), name="outputnode", ) wf = pe.Workflow(name="epi_pipeline") wf.connect([(inputnode, split, [("DWI", "in_file")])]) wf.connect([(split, pick_ref, [("out_files", "inlist")])]) wf.connect([(pick_ref, flirt_b0_2_T1, [("out", "in_file")])]) wf.connect([(inputnode, flirt_b0_2_T1, [("T1", "reference")])]) wf.connect([(inputnode, rot_bvec, [("bvec", "in_bvec")])]) wf.connect([(flirt_b0_2_T1, expend_matrix, [("out_matrix_file", "in_matrix")])]) wf.connect([(inputnode, expend_matrix, [("bvec", "in_bvec")])]) wf.connect([(expend_matrix, rot_bvec, [("out_matrix_list", "in_matrix")])]) wf.connect([(inputnode, antsRegistrationSyNQuick, [("T1", "fix_image")])]) wf.connect([(flirt_b0_2_T1, antsRegistrationSyNQuick, [("out_file", "moving_image")])]) wf.connect([(inputnode, c3d_flirt2ants, [("T1", "reference_file")])]) wf.connect([(pick_ref, c3d_flirt2ants, [("out", "source_file")])]) wf.connect([(flirt_b0_2_T1, c3d_flirt2ants, [("out_matrix_file", "transform_file")])]) wf.connect([(c3d_flirt2ants, change_transform, [("itk_transform", "input_affine_file")])]) wf.connect([(antsRegistrationSyNQuick, merge_transform, [("warp", "in1")]) ]) wf.connect([(antsRegistrationSyNQuick, merge_transform, [("affine_matrix", "in2")])]) wf.connect([(change_transform, merge_transform, [("updated_affine_file", "in3")])]) wf.connect([(inputnode, apply_transform, [("T1", "fix_image")])]) wf.connect([(split, apply_transform, [("out_files", "moving_image")])]) wf.connect([(merge_transform, apply_transform, [("out", "ants_warp_affine") ])]) wf.connect([(apply_transform, jacobian, [("out_warp_field", "deformationField")])]) wf.connect([(apply_transform, jacmult, [("out_warped", "operand_files")])]) wf.connect([(jacobian, jacmult, [("outputImage", "in_file")])]) wf.connect([(jacmult, thres, [("out_file", "in_file")])]) wf.connect([(thres, merge, [("out_file", "in_files")])]) wf.connect([(merge, outputnode, [("merged_file", "DWIs_epicorrected")])]) wf.connect([( flirt_b0_2_T1, outputnode, [("out_matrix_file", "DWI_2_T1_Coregistration_matrix")], )]) wf.connect([( antsRegistrationSyNQuick, outputnode, [ ("warp", "epi_correction_deformation_field"), ("affine_matrix", "epi_correction_affine_transform"), ("image_warped", "epi_correction_image_warped"), ], )]) wf.connect([(merge_transform, outputnode, [("out", "warp_epi")])]) wf.connect([(rot_bvec, outputnode, [("out_file", "out_bvec")])]) return wf
def remove_bias(name="bias_correct"): """ This workflow estimates a single multiplicative bias field from the averaged *b0* image, as suggested in [Jeurissen2014]_. .. admonition:: References .. [Jeurissen2014] Jeurissen B. et al., `Multi-tissue constrained spherical deconvolution for improved analysis of multi-shell diffusion MRI data <http://dx.doi.org/10.1016/j.neuroimage.2014.07.061>`_.squeue NeuroImage (2014). doi: 10.1016/j.neuroimage.2014.07.061 Example ------- >>> from nipype.workflows.dmri.fsl.artifacts import remove_bias >>> bias = remove_bias() >>> bias.inputs.inputnode.in_file = 'epi.nii' >>> bias.inputs.inputnode.in_bval = 'diffusion.bval' >>> bias.inputs.inputnode.in_mask = 'mask.nii' >>> bias.run() # doctest: +SKIP """ import nipype.interfaces.ants as ants import nipype.interfaces.fsl as fsl import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe inputnode = pe.Node(niu.IdentityInterface(fields=["in_file"]), name="inputnode") outputnode = pe.Node(niu.IdentityInterface(fields=["out_file", "b0_mask"]), name="outputnode") get_b0 = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="get_b0") mask_b0 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True), name="mask_b0") n4 = pe.Node( ants.N4BiasFieldCorrection(dimension=3, save_bias=True, bspline_fitting_distance=600), name="Bias_b0", ) split = pe.Node(fsl.Split(dimension="t"), name="SplitDWIs") mult = pe.MapNode( fsl.MultiImageMaths(op_string="-div %s"), iterfield=["in_file"], name="RemoveBiasOfDWIs", ) thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=["in_file"], name="RemoveNegative") merge = pe.Node(fsl.utils.Merge(dimension="t"), name="MergeDWIs") wf = pe.Workflow(name=name) wf.connect([ (inputnode, get_b0, [("in_file", "in_file")]), (get_b0, n4, [("roi_file", "input_image")]), (get_b0, mask_b0, [("roi_file", "in_file")]), (mask_b0, n4, [("mask_file", "mask_image")]), (inputnode, split, [("in_file", "in_file")]), (n4, mult, [("bias_image", "operand_files")]), (split, mult, [("out_files", "in_file")]), (mult, thres, [("out_file", "in_file")]), (thres, merge, [("out_file", "in_files")]), (merge, outputnode, [("merged_file", "out_file")]), (mask_b0, outputnode, [("mask_file", "b0_mask")]), ]) return wf
def ecc_pipeline(name="eddy_correct"): """ ECC stands for Eddy currents correction. Creates a pipelines that corrects for artifacts induced by Eddy currents in dMRI sequences. It takes a series of diffusion weighted images and linearly co-registers them to one reference image (the average of all b0s in the dataset). DWIs are also modulated by the determinant of the Jacobian as indicated by [Jones10]_ and [Rohde04]_. A list of rigid transformation matrices can be provided, sourcing from a :func:`.hmc_pipeline` workflow, to initialize registrations in a *motion free* framework. A list of affine transformation matrices is available as output, so that transforms can be chained (discussion `here <https://github.com/nipy/nipype/pull/530#issuecomment-14505042>`_). .. admonition:: References .. [Jones10] Jones DK, `The signal intensity must be modulated by the determinant of the Jacobian when correcting for eddy currents in diffusion MRI <http://cds.ismrm.org/protected/10MProceedings/files/1644_129.pdf>`_, Proc. ISMRM 18th Annual Meeting, (2010). .. [Rohde04] Rohde et al., `Comprehensive Approach for Correction of Motion and Distortion in Diffusion-Weighted MRI <http://stbb.nichd.nih.gov/pdf/com_app_cor_mri04.pdf>`_, MRM 51:103-114 (2004). Example ------- from nipype.workflows.dmri.fsl.artifacts import ecc_pipeline ecc = ecc_pipeline() ecc.inputs.inputnode.in_file = 'diffusion.nii' ecc.inputs.inputnode.in_bval = 'diffusion.bval' ecc.inputs.inputnode.in_mask = 'mask.nii' ecc.run() # doctest: +SKIP Inputs:: inputnode.in_file - input dwi file inputnode.in_mask - weights mask of reference image (a file with data \ range sin [0.0, 1.0], indicating the weight of each voxel when computing the \ metric. inputnode.in_bval - b-values table inputnode.in_xfms - list of matrices to initialize registration (from \ head-motion correction) Outputs:: outputnode.out_file - corrected dwi file outputnode.out_xfms - list of transformation matrices """ import nipype.interfaces.fsl as fsl import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe from nipype.workflows.data import get_flirt_schedule from nipype.workflows.dmri.fsl.artifacts import _xfm_jacobian from nipype.workflows.dmri.fsl.utils import ( extract_bval, recompose_dwi, recompose_xfm, ) from clinica.utils.dwi import merge_volumes_tdim from clinica.workflows.dwi_preprocessing import dwi_flirt params = dict( dof=12, no_search=True, interp="spline", bgvalue=0, schedule=get_flirt_schedule("ecc"), ) inputnode = pe.Node( niu.IdentityInterface( fields=["in_file", "in_bval", "in_mask", "in_xfms"]), name="inputnode", ) getb0 = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="get_b0") pick_dws = pe.Node( niu.Function( input_names=["in_dwi", "in_bval", "b"], output_names=["out_file"], function=extract_bval, ), name="extract_dwi", ) pick_dws.inputs.b = "diff" flirt = dwi_flirt(flirt_param=params, excl_nodiff=True) mult = pe.MapNode( fsl.BinaryMaths(operation="mul"), name="ModulateDWIs", iterfield=["in_file", "operand_value"], ) thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=["in_file"], name="RemoveNegative") split = pe.Node(fsl.Split(dimension="t"), name="SplitDWIs") get_mat = pe.Node( niu.Function( input_names=["in_bval", "in_xfms"], output_names=["out_files"], function=recompose_xfm, ), name="GatherMatrices", ) merge = pe.Node( niu.Function( input_names=["in_dwi", "in_bval", "in_corrected"], output_names=["out_file"], function=recompose_dwi, ), name="MergeDWIs", ) merged_volumes = pe.Node( niu.Function( input_names=["in_file1", "in_file2"], output_names=["out_file"], function=merge_volumes_tdim, ), name="merge_enhanced_ref_dwis", ) outputnode = pe.Node( niu.IdentityInterface(fields=["out_file", "out_xfms"]), name="outputnode") wf = pe.Workflow(name=name) wf.connect([ (inputnode, getb0, [("in_file", "in_file")]), (inputnode, pick_dws, [("in_file", "in_dwi"), ("in_bval", "in_bval")]), ( flirt, merged_volumes, [ ("outputnode.out_ref", "in_file1"), ("outputnode.out_file", "in_file2"), ], ), (merged_volumes, merge, [("out_file", "in_dwi")]), (inputnode, merge, [("in_bval", "in_bval")]), ( inputnode, flirt, [ ("in_mask", "inputnode.ref_mask"), ("in_xfms", "inputnode.in_xfms"), ("in_bval", "inputnode.in_bval"), ], ), (inputnode, get_mat, [("in_bval", "in_bval")]), (getb0, flirt, [("roi_file", "inputnode.reference")]), (pick_dws, flirt, [("out_file", "inputnode.in_file")]), (flirt, get_mat, [("outputnode.out_xfms", "in_xfms")]), (flirt, mult, [(("outputnode.out_xfms", _xfm_jacobian), "operand_value")]), (flirt, split, [("outputnode.out_file", "in_file")]), (split, mult, [("out_files", "in_file")]), (mult, thres, [("out_file", "in_file")]), (thres, merge, [("out_file", "in_corrected")]), (get_mat, outputnode, [("out_files", "out_xfms")]), (merge, outputnode, [("out_file", "out_file")]), ]) return wf
def create_motion_correct_pipeline(name='motion_correct'): """Creates a pipeline that corrects for motion artifact in dMRI sequences. It takes a series of diffusion weighted images and rigidly co-registers them to one reference image. Finally, the b-matrix is rotated accordingly (Leemans et al. 2009 - http://www.ncbi.nlm.nih.gov/pubmed/19319973), making use of the rotation matrix obtained by FLIRT. .. deprecated:: 0.9.3 Use :func:`nipype.workflows.dmri.preprocess.epi.hmc_pipeline` instead. .. warning:: This workflow rotates the b-vectors, so please be adviced that not all the dicom converters ensure the consistency between the resulting nifti orientation and the b matrix table (e.g. dcm2nii checks it). Example ------- >>> nipype_motioncorrect = create_motion_correct_pipeline('nipype_motioncorrect') >>> nipype_motioncorrect.inputs.inputnode.in_file = 'diffusion.nii' >>> nipype_motioncorrect.inputs.inputnode.in_bvec = 'diffusion.bvec' >>> nipype_motioncorrect.inputs.inputnode.ref_num = 0 >>> nipype_motioncorrect.run() # doctest: +SKIP Inputs:: inputnode.in_file inputnode.ref_num inputnode.in_bvec Outputs:: outputnode.motion_corrected outputnode.out_bvec """ warnings.warn( ('This workflow is deprecated from v.1.0.0, use ' 'nipype.workflows.dmri.preprocess.epi.hmc_pipeline instead'), DeprecationWarning) inputnode = pe.Node( niu.IdentityInterface(fields=['in_file', 'ref_num', 'in_bvec']), name='inputnode') pipeline = pe.Workflow(name=name) split = pe.Node(fsl.Split(dimension='t'), name='split') pick_ref = pe.Node(niu.Select(), name='pick_ref') coregistration = pe.MapNode(fsl.FLIRT(no_search=True, interp='spline', padding_size=1, dof=6), name='coregistration', iterfield=['in_file']) rotate_bvecs = pe.Node(niu.Function(input_names=['in_bvec', 'in_matrix'], output_names=['out_file'], function=_rotate_bvecs), name='rotate_b_matrix') merge = pe.Node(fsl.Merge(dimension='t'), name='merge') outputnode = pe.Node( niu.IdentityInterface(fields=['motion_corrected', 'out_bvec']), name='outputnode') pipeline.connect([ (inputnode, split, [('in_file', 'in_file')]), (split, pick_ref, [('out_files', 'inlist')]), (inputnode, pick_ref, [('ref_num', 'index')]), (split, coregistration, [('out_files', 'in_file')]), (inputnode, rotate_bvecs, [('in_bvec', 'in_bvec')]), (coregistration, rotate_bvecs, [('out_matrix_file', 'in_matrix')]), (pick_ref, coregistration, [('out', 'reference')]), (coregistration, merge, [('out_file', 'in_files')]), (merge, outputnode, [('merged_file', 'motion_corrected')]), (rotate_bvecs, outputnode, [('out_file', 'out_bvec')]) ]) return pipeline
def create_indnet_workflow(hp_cutoff=100, smoothing=5, smm_threshold=0.5, binarise_threshold=0.5, melodic_seed=None, aggr_aroma=False, name="indnet"): indnet = Workflow(name=name) # Input node inputspec = Node(utility.IdentityInterface( fields=['anat_file', 'func_file', 'templates', 'networks']), name='inputspec') # T1 skullstrip anat_bet = Node(fsl.BET(), name="anat_bet") # EPI preprocessing func_realignsmooth = create_featreg_preproc(highpass=False, whichvol='first', name='func_realignsmooth') func_realignsmooth.inputs.inputspec.fwhm = smoothing # Transform EPI to MNI space func_2mni = create_reg_workflow(name='func_2mni') func_2mni.inputs.inputspec.target_image = fsl.Info.standard_image( 'MNI152_T1_2mm.nii.gz') func_2mni.inputs.inputspec.target_image_brain = fsl.Info.standard_image( 'MNI152_T1_2mm_brain.nii.gz') func_2mni.inputs.inputspec.config_file = 'T1_2_MNI152_2mm' # Segmentation of T1 anat_segmentation = Node(fsl.FAST(output_biascorrected=True), name='anat_segmentation') # Transfrom segments to EPI space segments_2func = create_segments_2func_workflow( threshold=binarise_threshold, name='segments_2func') # Transform templates to EPI space templates_2func = create_templates_2func_workflow( threshold=binarise_threshold, name='templates_2func') # Mask network templates with GM gm_mask_templates = MapNode(fsl.ImageMaths(op_string='-mul'), iterfield=['in_file2'], name='gm_mask_templates') # Mask for ICA-AROMA and statistics func_brainmask = Node(fsl.BET(frac=0.3, mask=True, no_output=True, robust=True), name='func_brainmask') # Melodic ICA if melodic_seed != None: func_melodic = Node(fsl.MELODIC(args='--seed={}'.format(melodic_seed), out_stats=True), name='func_melodic') # ICA-AROMA func_aroma = Node(fsl.ICA_AROMA(), name='func_aroma') if aggr_aroma: func_aroma.inputs.denoise_type = 'aggr' else: func_aroma.inputs.denoise_type = 'nonaggr' # Highpass filter ICA results func_highpass = create_highpass_filter(cutoff=hp_cutoff, name='func_highpass') # Calculate mean CSF sgnal csf_meansignal = Node(fsl.ImageMeants(), name='csf_meansignal') # Calculate mean WM signal wm_meansignal = Node(fsl.ImageMeants(), name='wm_meansignal') # Calculate mean non-brain signal nonbrain_meansignal = create_nonbrain_meansignal( name='nonbrain_meansignal') # Calculate first Eigenvariates firsteigenvariates = MapNode(fsl.ImageMeants(show_all=True, eig=True), iterfield=['mask'], name='firsteigenvariates') # Combine first eigenvariates and wm/csf/non-brain signals regressors = Node(utility.Merge(4), name='regressors') # z-transform regressors ztransform = MapNode(Ztransform(), iterfield=['in_file'], name='ztransform') # Create design matrix designmatrix = Node(DesignMatrix(), name='designmatrix') # Create contrasts contrasts = Node(Contrasts(), name='contrasts') # GLM glm = Node(fsl.GLM(), name='glm') glm.inputs.out_z_name = 'z_stats.nii.gz' glm.inputs.demean = True # Split z-maps zmaps = Node(fsl.Split(), name='zmaps') zmaps.inputs.dimension = 't' # Spatial Mixture Modelling smm = MapNode(fsl.SMM(), iterfield=['spatial_data_file'], name='smm') # Transform probability maps to native (anat) space actmaps_2anat = MapNode(fsl.ApplyXFM(), iterfield=['in_file'], name='actmaps_2anat') # Transform probability maps to MNI space actmaps_2mni = MapNode(fsl.ApplyWarp(), iterfield=['in_file'], name='actmaps_2mni') actmaps_2mni.inputs.ref_file = fsl.Info.standard_image( 'MNI152_T1_2mm.nii.gz') # Create network masks in native (func) space network_masks_func = create_network_masks_workflow( name='network_masks_func', smm_threshold=smm_threshold) # Create network masks in native (anat) space network_masks_anat = create_network_masks_workflow( name='network_masks_anat', smm_threshold=smm_threshold) # Create network masks in MNI space network_masks_mni = create_network_masks_workflow( name='network_masks_mni', smm_threshold=smm_threshold) # Output node outputspec = Node(utility.IdentityInterface(fields=[ 'network_masks_func_main', 'network_masks_func_exclusive', 'network_masks_anat_main', 'network_masks_anat_exclusive', 'network_masks_mni_main', 'network_masks_mni_exclusive', 'preprocessed_func_file', 'preprocessed_anat_file', 'motion_parameters', 'func2anat_transform', 'anat2mni_transform' ]), name='outputspec') # Helper functions def get_first_item(x): try: return x[0] except: return x def get_second_item(x): return x[1] def get_third_item(x): return x[2] def get_components(x): return [y['components'] for y in x] # Connect the nodes # anat_bet indnet.connect(inputspec, 'anat_file', anat_bet, 'in_file') # func_realignsmooth indnet.connect(inputspec, 'func_file', func_realignsmooth, 'inputspec.func') # func_2mni indnet.connect(func_realignsmooth, ('outputspec.smoothed_files', get_first_item), func_2mni, 'inputspec.source_files') indnet.connect(inputspec, 'anat_file', func_2mni, 'inputspec.anatomical_image') indnet.connect(func_realignsmooth, 'outputspec.reference', func_2mni, 'inputspec.mean_image') # anat_segmentation indnet.connect(anat_bet, 'out_file', anat_segmentation, 'in_files') # segments_2func indnet.connect(anat_segmentation, 'partial_volume_files', segments_2func, 'inputspec.segments') indnet.connect(func_2mni, 'outputspec.func2anat_transform', segments_2func, 'inputspec.premat') indnet.connect(func_realignsmooth, 'outputspec.mean', segments_2func, 'inputspec.func_file') # templates_2func indnet.connect(func_realignsmooth, 'outputspec.mean', templates_2func, 'inputspec.func_file') indnet.connect(func_2mni, 'outputspec.func2anat_transform', templates_2func, 'inputspec.premat') indnet.connect(func_2mni, 'outputspec.anat2target_transform', templates_2func, 'inputspec.warp') indnet.connect(inputspec, 'templates', templates_2func, 'inputspec.templates') # gm_mask_templates indnet.connect(segments_2func, ('outputspec.segments_2func_files', get_second_item), gm_mask_templates, 'in_file') indnet.connect(templates_2func, 'outputspec.templates_2func_files', gm_mask_templates, 'in_file2') # func_brainmask indnet.connect(func_realignsmooth, 'outputspec.mean', func_brainmask, 'in_file') # func_melodic if melodic_seed != None: indnet.connect(func_realignsmooth, ('outputspec.smoothed_files', get_first_item), func_melodic, 'in_files') indnet.connect(func_brainmask, 'mask_file', func_melodic, 'mask') # func_aroma indnet.connect(func_realignsmooth, ('outputspec.smoothed_files', get_first_item), func_aroma, 'in_file') indnet.connect(func_2mni, 'outputspec.func2anat_transform', func_aroma, 'mat_file') indnet.connect(func_2mni, 'outputspec.anat2target_transform', func_aroma, 'fnirt_warp_file') indnet.connect(func_realignsmooth, ('outputspec.motion_parameters', get_first_item), func_aroma, 'motion_parameters') indnet.connect(func_brainmask, 'mask_file', func_aroma, 'mask') if melodic_seed != None: indnet.connect(func_melodic, 'out_dir', func_aroma, 'melodic_dir') # func_highpass if aggr_aroma: indnet.connect(func_aroma, 'aggr_denoised_file', func_highpass, 'inputspec.in_file') else: indnet.connect(func_aroma, 'nonaggr_denoised_file', func_highpass, 'inputspec.in_file') # csf_meansignal indnet.connect(segments_2func, ('outputspec.segments_2func_files', get_first_item), csf_meansignal, 'mask') indnet.connect(func_highpass, 'outputspec.filtered_file', csf_meansignal, 'in_file') # wm_meansignal indnet.connect(segments_2func, ('outputspec.segments_2func_files', get_third_item), wm_meansignal, 'mask') indnet.connect(func_highpass, 'outputspec.filtered_file', wm_meansignal, 'in_file') # nonbrain_meansignal indnet.connect(inputspec, 'func_file', nonbrain_meansignal, 'inputspec.func_file') # firsteigenvariates indnet.connect(gm_mask_templates, 'out_file', firsteigenvariates, 'mask') indnet.connect(func_highpass, 'outputspec.filtered_file', firsteigenvariates, 'in_file') # regressors indnet.connect(firsteigenvariates, 'out_file', regressors, 'in1') indnet.connect(wm_meansignal, 'out_file', regressors, 'in2') indnet.connect(csf_meansignal, 'out_file', regressors, 'in3') indnet.connect(nonbrain_meansignal, 'outputspec.nonbrain_regressor', regressors, 'in4') # ztransform indnet.connect(regressors, 'out', ztransform, 'in_file') # designmatrix indnet.connect(ztransform, 'out_file', designmatrix, 'in_files') # contrasts indnet.connect(inputspec, ('networks', get_components), contrasts, 'in_list') indnet.connect(designmatrix, 'out_file', contrasts, 'design') # glm indnet.connect(designmatrix, 'out_file', glm, 'design') indnet.connect(contrasts, 'out_file', glm, 'contrasts') indnet.connect(func_brainmask, 'mask_file', glm, 'mask') indnet.connect(func_highpass, 'outputspec.filtered_file', glm, 'in_file') # zmaps indnet.connect(glm, 'out_z', zmaps, 'in_file') # smm indnet.connect(zmaps, 'out_files', smm, 'spatial_data_file') indnet.connect(func_brainmask, 'mask_file', smm, 'mask') # actmaps_2anat indnet.connect(smm, 'activation_p_map', actmaps_2anat, 'in_file') indnet.connect(func_2mni, 'outputspec.func2anat_transform', actmaps_2anat, 'in_matrix_file') indnet.connect(anat_bet, 'out_file', actmaps_2anat, 'reference') # actmaps_2mni indnet.connect(smm, 'activation_p_map', actmaps_2mni, 'in_file') indnet.connect(templates_2func, 'outputspec.func_2mni_warp', actmaps_2mni, 'field_file') # network_masks_func indnet.connect(smm, 'activation_p_map', network_masks_func, 'inputspec.actmaps') indnet.connect(inputspec, 'networks', network_masks_func, 'inputspec.networks') # network_masks_anat indnet.connect(actmaps_2anat, 'out_file', network_masks_anat, 'inputspec.actmaps') indnet.connect(inputspec, 'networks', network_masks_anat, 'inputspec.networks') # network_masks_mni indnet.connect(actmaps_2mni, 'out_file', network_masks_mni, 'inputspec.actmaps') indnet.connect(inputspec, 'networks', network_masks_mni, 'inputspec.networks') # output node indnet.connect(network_masks_func, 'outputspec.main_masks', outputspec, 'network_masks_func_main') indnet.connect(network_masks_func, 'outputspec.exclusive_masks', outputspec, 'network_masks_func_exclusive') indnet.connect(network_masks_anat, 'outputspec.main_masks', outputspec, 'network_masks_anat_main') indnet.connect(network_masks_anat, 'outputspec.exclusive_masks', outputspec, 'network_masks_anat_exclusive') indnet.connect(network_masks_mni, 'outputspec.main_masks', outputspec, 'network_masks_mni_main') indnet.connect(network_masks_mni, 'outputspec.exclusive_masks', outputspec, 'network_masks_mni_exclusive') indnet.connect(func_highpass, 'outputspec.filtered_file', outputspec, 'preprocessed_func_file') indnet.connect(anat_segmentation, 'restored_image', outputspec, 'preprocessed_anat_file') indnet.connect(func_realignsmooth, ('outputspec.motion_parameters', get_first_item), outputspec, 'motion_parameters') indnet.connect(func_2mni, 'outputspec.func2anat_transform', outputspec, 'func2anat_transform') indnet.connect(func_2mni, 'outputspec.anat2target_transform', outputspec, 'anat2mni_transform') return indnet
def dwi_flirt(name="DWICoregistration", excl_nodiff=False, flirt_param={}): """ Generates a workflow for linear registration of dwi volumes using flirt. Inputnode --------- reference : FILE Mandatory input. Reference data set. in_file : FILE Mandatory input. Moving data set. ref_mask : FILE Mandatory input. Binary mask of the reference volume. in_xfms : FILE Mandatory input. Intialisation matrices for flirt. in_bval : FILE Mandatory input. B values file. """ import nipype.interfaces.ants as ants import nipype.interfaces.fsl as fsl import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe from nipype.workflows.dmri.fsl.utils import _checkinitxfm, enhance inputnode = pe.Node( niu.IdentityInterface( fields=["reference", "in_file", "ref_mask", "in_xfms", "in_bval"]), name="inputnode", ) initmat = pe.Node( niu.Function( input_names=["in_bval", "in_xfms", "excl_nodiff"], output_names=["init_xfms"], function=_checkinitxfm, ), name="InitXforms", ) initmat.inputs.excl_nodiff = excl_nodiff dilate = pe.Node( fsl.maths.MathsCommand(nan2zeros=True, args="-kernel sphere 5 -dilM"), name="MskDilate", ) split = pe.Node(fsl.Split(dimension="t"), name="SplitDWIs") n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name="Bias") flirt = pe.MapNode( fsl.FLIRT(**flirt_param), name="CoRegistration", iterfield=["in_file", "in_matrix_file"], ) thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=["in_file"], name="RemoveNegative") merge = pe.Node(fsl.Merge(dimension="t"), name="MergeDWIs") outputnode = pe.Node( niu.IdentityInterface(fields=["out_file", "out_xfms", "out_ref"]), name="outputnode", ) enhb0 = pe.Node( niu.Function( input_names=["in_file", "in_mask", "clip_limit"], output_names=["out_file"], function=enhance, ), name="B0Equalize", ) enhb0.inputs.clip_limit = 0.015 enhdw = pe.MapNode( niu.Function( input_names=["in_file", "in_mask"], output_names=["out_file"], function=enhance, ), name="DWEqualize", iterfield=["in_file"], ) # enhb0.inputs.clip_limit = clip_limit wf = pe.Workflow(name=name) wf.connect([ (inputnode, split, [("in_file", "in_file")]), (inputnode, dilate, [("ref_mask", "in_file")]), (inputnode, n4, [("reference", "input_image"), ("ref_mask", "mask_image")]), # (inputnode, flirt, [('ref_mask', 'reference')]), (n4, enhb0, [("output_image", "in_file")]), (enhb0, flirt, [("out_file", "reference")]), (inputnode, initmat, [("in_xfms", "in_xfms"), ("in_bval", "in_bval")]), (split, enhdw, [("out_files", "in_file")]), (dilate, enhdw, [("out_file", "in_mask")]), (dilate, flirt, [("out_file", "ref_weight"), ("out_file", "in_weight")]), (enhdw, flirt, [("out_file", "in_file")]), (initmat, flirt, [("init_xfms", "in_matrix_file")]), (flirt, thres, [("out_file", "in_file")]), (thres, merge, [("out_file", "in_files")]), (merge, outputnode, [("merged_file", "out_file")]), (enhb0, outputnode, [("out_file", "out_ref")]), (flirt, outputnode, [("out_matrix_file", "out_xfms")]), ]) return wf
def sdc_fmb(name='fmb_correction', interp='Linear', fugue_params=dict(smooth3d=2.0)): """ SDC stands for susceptibility distortion correction. FMB stands for fieldmap-based. The fieldmap based (FMB) method implements SDC by using a mapping of the B0 field as proposed by [Jezzard95]_. This workflow uses the implementation of FSL (`FUGUE <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE>`_). Phase unwrapping is performed using `PRELUDE <http://fsl.fmrib.ox.ac.uk/fsl/fsl-4.1.9/fugue/prelude.html>`_ [Jenkinson03]_. Preparation of the fieldmap is performed reproducing the script in FSL `fsl_prepare_fieldmap <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE/Guide#SIEMENS_data>`_. Example ------- >>> from nipype.workflows.dmri.fsl.artifacts import sdc_fmb >>> fmb = sdc_fmb() >>> fmb.inputs.inputnode.in_file = 'diffusion.nii' >>> fmb.inputs.inputnode.in_ref = list(range(0, 30, 6)) >>> fmb.inputs.inputnode.in_mask = 'mask.nii' >>> fmb.inputs.inputnode.bmap_mag = 'magnitude.nii' >>> fmb.inputs.inputnode.bmap_pha = 'phase.nii' >>> fmb.inputs.inputnode.settings = 'epi_param.txt' >>> fmb.run() # doctest: +SKIP .. warning:: Only SIEMENS format fieldmaps are supported. .. admonition:: References .. [Jezzard95] Jezzard P, and Balaban RS, `Correction for geometric distortion in echo planar images from B0 field variations <https://doi.org/10.1002/mrm.1910340111>`_, MRM 34(1):65-73. (1995). doi: 10.1002/mrm.1910340111. .. [Jenkinson03] Jenkinson M., `Fast, automated, N-dimensional phase-unwrapping algorithm <https://doi.org/10.1002/mrm.10354>`_, MRM 49(1):193-197, 2003, doi: 10.1002/mrm.10354. """ epi_defaults = { 'delta_te': 2.46e-3, 'echospacing': 0.77e-3, 'acc_factor': 2, 'enc_dir': u'AP' } inputnode = pe.Node(niu.IdentityInterface(fields=[ 'in_file', 'in_ref', 'in_mask', 'bmap_pha', 'bmap_mag', 'settings' ]), name='inputnode') outputnode = pe.Node( niu.IdentityInterface(fields=['out_file', 'out_vsm', 'out_warp']), name='outputnode') r_params = pe.Node(JSONFileGrabber(defaults=epi_defaults), name='SettingsGrabber') eff_echo = pe.Node(niu.Function(function=_eff_t_echo, input_names=['echospacing', 'acc_factor'], output_names=['eff_echo']), name='EffEcho') firstmag = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name='GetFirst') n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='Bias') bet = pe.Node(fsl.BET(frac=0.4, mask=True), name='BrainExtraction') dilate = pe.Node(fsl.maths.MathsCommand(nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate') pha2rads = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_file'], function=siemens2rads), name='PreparePhase') prelude = pe.Node(fsl.PRELUDE(process3d=True), name='PhaseUnwrap') rad2rsec = pe.Node(niu.Function(input_names=['in_file', 'delta_te'], output_names=['out_file'], function=rads2radsec), name='ToRadSec') baseline = pe.Node(niu.Function(input_names=['in_file', 'index'], output_names=['out_file'], function=time_avg), name='Baseline') fmm2b0 = pe.Node(ants.Registration(output_warped_image=True), name="FMm_to_B0") fmm2b0.inputs.transforms = ['Rigid'] * 2 fmm2b0.inputs.transform_parameters = [(1.0, )] * 2 fmm2b0.inputs.number_of_iterations = [[50], [20]] fmm2b0.inputs.dimension = 3 fmm2b0.inputs.metric = ['Mattes', 'Mattes'] fmm2b0.inputs.metric_weight = [1.0] * 2 fmm2b0.inputs.radius_or_number_of_bins = [64, 64] fmm2b0.inputs.sampling_strategy = ['Regular', 'Random'] fmm2b0.inputs.sampling_percentage = [None, 0.2] fmm2b0.inputs.convergence_threshold = [1.e-5, 1.e-8] fmm2b0.inputs.convergence_window_size = [20, 10] fmm2b0.inputs.smoothing_sigmas = [[6.0], [2.0]] fmm2b0.inputs.sigma_units = ['vox'] * 2 fmm2b0.inputs.shrink_factors = [[6], [1]] # ,[1] ] fmm2b0.inputs.use_estimate_learning_rate_once = [True] * 2 fmm2b0.inputs.use_histogram_matching = [True] * 2 fmm2b0.inputs.initial_moving_transform_com = 0 fmm2b0.inputs.collapse_output_transforms = True fmm2b0.inputs.winsorize_upper_quantile = 0.995 applyxfm = pe.Node(ants.ApplyTransforms(dimension=3, interpolation=interp), name='FMp_to_B0') pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='PreliminaryFugue') demean = pe.Node(niu.Function(input_names=['in_file', 'in_mask'], output_names=['out_file'], function=demean_image), name='DemeanFmap') cleanup = cleanup_edge_pipeline() addvol = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_file'], function=add_empty_vol), name='AddEmptyVol') vsm = pe.Node(fsl.FUGUE(save_shift=True, **fugue_params), name="ComputeVSM") split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs') merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs') unwarp = pe.MapNode(fsl.FUGUE(icorr=True, forward_warping=False), iterfield=['in_file'], name='UnwarpDWIs') thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'], name='RemoveNegative') vsm2dfm = vsm2warp() vsm2dfm.inputs.inputnode.scaling = 1.0 wf = pe.Workflow(name=name) wf.connect([(inputnode, r_params, [('settings', 'in_file')]), (r_params, eff_echo, [('echospacing', 'echospacing'), ('acc_factor', 'acc_factor')]), (inputnode, pha2rads, [('bmap_pha', 'in_file')]), (inputnode, firstmag, [('bmap_mag', 'in_file')]), (inputnode, baseline, [('in_file', 'in_file'), ('in_ref', 'index')]), (firstmag, n4, [('roi_file', 'input_image')]), (n4, bet, [('output_image', 'in_file')]), (bet, dilate, [('mask_file', 'in_file')]), (pha2rads, prelude, [('out_file', 'phase_file')]), (n4, prelude, [('output_image', 'magnitude_file')]), (dilate, prelude, [('out_file', 'mask_file')]), (r_params, rad2rsec, [('delta_te', 'delta_te')]), (prelude, rad2rsec, [('unwrapped_phase_file', 'in_file')]), (baseline, fmm2b0, [('out_file', 'fixed_image')]), (n4, fmm2b0, [('output_image', 'moving_image')]), (inputnode, fmm2b0, [('in_mask', 'fixed_image_mask')]), (dilate, fmm2b0, [('out_file', 'moving_image_mask')]), (baseline, applyxfm, [('out_file', 'reference_image')]), (rad2rsec, applyxfm, [('out_file', 'input_image')]), (fmm2b0, applyxfm, [('forward_transforms', 'transforms'), ('forward_invert_flags', 'invert_transform_flags')]), (applyxfm, pre_fugue, [('output_image', 'fmap_in_file')]), (inputnode, pre_fugue, [('in_mask', 'mask_file')]), (pre_fugue, demean, [('fmap_out_file', 'in_file')]), (inputnode, demean, [('in_mask', 'in_mask')]), (demean, cleanup, [('out_file', 'inputnode.in_file')]), (inputnode, cleanup, [('in_mask', 'inputnode.in_mask')]), (cleanup, addvol, [('outputnode.out_file', 'in_file')]), (inputnode, vsm, [('in_mask', 'mask_file')]), (addvol, vsm, [('out_file', 'fmap_in_file')]), (r_params, vsm, [('delta_te', 'asym_se_time')]), (eff_echo, vsm, [('eff_echo', 'dwell_time')]), (inputnode, split, [('in_file', 'in_file')]), (split, unwarp, [('out_files', 'in_file')]), (vsm, unwarp, [('shift_out_file', 'shift_in_file')]), (r_params, unwarp, [(('enc_dir', _fix_enc_dir), 'unwarp_direction')]), (unwarp, thres, [('unwarped_file', 'in_file')]), (thres, merge, [('out_file', 'in_files')]), (r_params, vsm2dfm, [(('enc_dir', _fix_enc_dir), 'inputnode.enc_dir')]), (merge, vsm2dfm, [('merged_file', 'inputnode.in_ref')]), (vsm, vsm2dfm, [('shift_out_file', 'inputnode.in_vsm')]), (merge, outputnode, [('merged_file', 'out_file')]), (vsm, outputnode, [('shift_out_file', 'out_vsm')]), (vsm2dfm, outputnode, [('outputnode.out_warp', 'out_warp')])]) return wf