def nipype_bbregister(t1path): splitpath = t1path.split(os.sep) sub_fsdir = os.path.join(BIDS_DATA_DIR, "derivatives", "freesurfer_{0}".format(splitpath[-3]), splitpath[-4]) if not os.path.isdir(sub_fsdir): os.mkdir(sub_fsdir) outdir = os.path.join(BIDS_DATA_DIR, "derivatives", "freesurfer_projection_{0}".format(splitpath[-3]), splitpath[-4]) if not os.path.isdir(outdir): os.makedirs(outdir) funcpath = os.path.join( BIDS_DATA_DIR, "derivatives", "spmpreproc_{0}".format(splitpath[-3]), splitpath[-4], "wrr{0}_{1}_task-localizer_bold.nii.gz".format(splitpath[-4], splitpath[-3])) assert os.path.isfile(funcpath), funcpath basename = os.path.basename(funcpath).replace(".nii.gz", "") os.environ["SUBJECTS_DIR"] = os.path.dirname(sub_fsdir) bbreg = freesurfer.BBRegister( subject_id=splitpath[-4], source_file=funcpath, init="fsl", contrast_type="t2", dof=6, fsldof=6, reg_frame=0, out_fsl_file=os.path.join(outdir, basename + ".fsl.mat"), out_reg_file=os.path.join(outdir, basename + ".reg.dat")) print(bbreg.cmdline) if PROCESS: bbreg.run()
def test_bbregister(create_files_in_directory): filelist, outdir = create_files_in_directory bbr = freesurfer.BBRegister() # make sure command gets called assert bbr.cmd == "bbregister" # test raising error with mandatory args absent with pytest.raises(ValueError): bbr.cmdline bbr.inputs.subject_id = "fsaverage" bbr.inputs.source_file = filelist[0] bbr.inputs.contrast_type = "t2" # Check that 'init' is mandatory in FS < 6, but not in 6+ if Info.looseversion() < LooseVersion("6.0.0"): with pytest.raises(ValueError): bbr.cmdline else: bbr.cmdline bbr.inputs.init = "fsl" base, ext = os.path.splitext(os.path.basename(filelist[0])) if ext == ".gz": base, _ = os.path.splitext(base) assert bbr.cmdline == ("bbregister --t2 --init-fsl " "--reg {base}_bbreg_fsaverage.dat " "--mov {full} --s fsaverage".format( full=filelist[0], base=base))
def create_bbregister_workflow(name="bbregister", contrast_type="t2", partial_brain=False, init_with="fsl"): """Find a linear transformation to align the EPI file with the anatomy.""" in_fields = ["subject_id", "timeseries"] if partial_brain: in_fields.append("whole_brain_template") inputnode = Node(IdentityInterface(in_fields), "inputs") # Take the mean over time to get a target volume meanvol = MapNode(fsl.MeanImage(), "in_file", "meanvol") # Do a rough skullstrip using BET skullstrip = MapNode(fsl.BET(), "in_file", "bet") # Estimate the registration to Freesurfer conformed space func2anat = MapNode( fs.BBRegister(contrast_type=contrast_type, init=init_with, epi_mask=True, registered_file=True, out_reg_file="func2anat_tkreg.dat", out_fsl_file="func2anat_flirt.mat"), "source_file", "func2anat") # Make an image for quality control on the registration report = MapNode(CoregReport(), "in_file", "coreg_report") # Define the workflow outputs outputnode = Node(IdentityInterface(["tkreg_mat", "flirt_mat", "report"]), "outputs") bbregister = Workflow(name=name) # Connect the registration bbregister.connect([ (inputnode, func2anat, [("subject_id", "subject_id")]), (inputnode, report, [("subject_id", "subject_id")]), (inputnode, meanvol, [("timeseries", "in_file")]), (meanvol, skullstrip, [("out_file", "in_file")]), (skullstrip, func2anat, [("out_file", "source_file")]), (func2anat, report, [("registered_file", "in_file")]), (func2anat, outputnode, [("out_reg_file", "tkreg_mat")]), (func2anat, outputnode, [("out_fsl_file", "flirt_mat")]), (report, outputnode, [("out_file", "report")]), ]) # Possibly connect the full_fov image if partial_brain: bbregister.connect([ (inputnode, func2anat, [("whole_brain_template", "intermediate_file")]), ]) return bbregister
def epi_fs_coregister(name='epi_fs_coregister'): inputnode = pe.Node( utility.IdentityInterface( fields=['fmri','subject_id','subjects_dir', 'roi_file','mask_file']), name='inputspec') outputnode = pe.Node( utility.IdentityInterface( fields=['fmri_mask','fmri_rois','reg_file','fsl_reg_file']), name='outputspec') n_bbregister = pe.Node( freesurfer.BBRegister(init='fsl', contrast_type='t2', out_fsl_file=True), name='bbregister') n_fsmask2epi = pe.Node( freesurfer.ApplyVolTransform(inverse=True, interp='nearest', transformed_file='mask_epi.nii.gz'), name='fsmask2epi') n_fsrois2epi = pe.Node( freesurfer.ApplyVolTransform(inverse=True, interp='nearest', transformed_file='epi_aparc.aseg.nii.gz'), name='fsrois2epi') w=pe.Workflow(name=name) w.connect([ (inputnode, n_bbregister,[('fmri','source_file'), ('subjects_dir','subjects_dir'), ('subject_id','subject_id')]), (n_bbregister, n_fsrois2epi,[('out_reg_file','reg_file')]), (inputnode, n_fsrois2epi, [('fmri','source_file'), ('roi_file','target_file')]), (n_bbregister, n_fsmask2epi,[('out_reg_file','reg_file')]), (inputnode, n_fsmask2epi, [('fmri','source_file'), ('mask_file','target_file')]), (n_bbregister, outputnode,[('out_reg_file','reg_file')]), (n_bbregister, outputnode,[('out_fsl_file','fsl_reg_file')]), (n_fsmask2epi, outputnode, [('transformed_file','fmri_mask')]), (n_fsrois2epi, outputnode, [('transformed_file','fmri_rois')]), ]) return w
def test_bbregister(): input_map = dict( args=dict(argstr='%s', ), contrast_type=dict( argstr='--%s', mandatory=True, ), environ=dict(), init=dict( argstr='--init-%s', xor=['init_reg_file'], ), init_reg_file=dict( xor=['init'], mandatory=True, ), out_reg_file=dict(argstr='--reg %s', ), registered_file=dict(argstr='--o %s', ), reg_frame=dict(argstr="--frame %d", ), reg_middle_frame=dict(argstr="--mid-frame", ), intermediate_file=dict(argstr="--int %s", ), source_file=dict( copyfile=False, mandatory=True, argstr='--mov %s', ), subject_id=dict( mandatory=True, argstr='--s %s', ), subjects_dir=dict(), ) instance = freesurfer.BBRegister() for key, metadata in input_map.items(): for metakey, value in metadata.items(): yield (assert_equal, getattr(instance.inputs.traits()[key], metakey), value)
def min_func_preproc(subject, sessions, data_dir, fs_dir, wd, sink, TR, EPI_resolution): #initiate min func preproc workflow wf = pe.Workflow(name='MPP') wf.base_dir = wd wf.config['execution']['crashdump_dir'] = wf.base_dir + "/crash_files" ## set fsl output type to nii.gz fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # I/O nodes inputnode = pe.Node(util.IdentityInterface(fields=['subjid', 'fs_dir']), name='inputnode') inputnode.inputs.subjid = subject inputnode.inputs.fs_dir = fs_dir ds = pe.Node(nio.DataSink(base_directory=sink, parameterization=False), name='sink') ds.inputs.substitutions = [('moco.nii.gz.par', 'moco.par'), ('moco.nii.gz_', 'moco_')] #infosource to interate over sessions: COND, EXT1, EXT2 sessions_infosource = pe.Node(util.IdentityInterface(fields=['session']), name='session') sessions_infosource.iterables = [('session', sessions)] #select files templates = { 'func_data': '{session}/func_data.nii.gz', 'T1_brain': 'T1/T1_brain.nii.gz', 'wmedge': 'T1/MASKS/aparc_aseg.WMedge.nii.gz' } selectfiles = pe.Node(nio.SelectFiles(templates, base_directory=data_dir), name='selectfiles') wf.connect(sessions_infosource, 'session', selectfiles, 'session') wf.connect(sessions_infosource, 'session', ds, 'container') ########################################################################## ######################## START ###################################### ########################################################################## ########################################################################### ######################## No. 3 ###################################### #change the data type to float fsl_float = pe.Node(fsl.maths.MathsCommand(output_datatype='float'), name='fsl_float') wf.connect(selectfiles, 'func_data', fsl_float, 'in_file') ########################################################################### ######################## No. 4 ###################################### #get FD from fsl_motion_outliers FD = pe.Node(fsl.MotionOutliers(out_file='func_data_FD_outliers.txt', out_metric_values='func_data_FD.txt', metric='fd'), name='FD') wf.connect(fsl_float, 'out_file', FD, 'in_file') wf.connect(FD, 'out_metric_values', ds, 'QC.@FD') wf.connect(FD, 'out_file', ds, 'QC.@FDoutliers') ########################################################################### ######################## No. 5 ###################################### #slice timing correction: sequential ascending slicetimer = pe.Node( fsl.SliceTimer( index_dir=False, interleaved=False, #slice_direction=3, #z direction time_repetition=TR, out_file='func_data_stc.nii.gz'), name='slicetimer') wf.connect(fsl_float, 'out_file', slicetimer, 'in_file') wf.connect(slicetimer, 'slice_time_corrected_file', ds, 'TEMP.@slicetimer') ########################################################################### ######################## No. 6 ###################################### #do realignment to the middle or first volume mcflirt = pe.Node(fsl.MCFLIRT(save_mats=True, save_plots=True, save_rms=True, ref_vol=1, out_file='func_data_stc_moco.nii.gz'), name='mcflirt') wf.connect(slicetimer, 'slice_time_corrected_file', mcflirt, 'in_file') wf.connect(mcflirt, 'out_file', ds, 'TEMP.@mcflirt') wf.connect(mcflirt, 'par_file', ds, 'MOCO.@par_file') wf.connect(mcflirt, 'rms_files', ds, 'MOCO.@rms_files') wf.connect(mcflirt, 'mat_file', ds, 'MOCO_MAT.@mcflirt') # plot motion parameters rotplotter = pe.Node(fsl.PlotMotionParams(in_source='fsl', plot_type='rotations', out_file='rotation.png'), name='rotplotter') transplotter = pe.Node(fsl.PlotMotionParams(in_source='fsl', plot_type='translations', out_file='translation.png'), name='transplotter') dispplotter = pe.Node( interface=fsl.PlotMotionParams(in_source='fsl', plot_type='displacement', out_file='displacement.png'), name='dispplotter') wf.connect(mcflirt, 'par_file', rotplotter, 'in_file') wf.connect(mcflirt, 'par_file', transplotter, 'in_file') wf.connect(mcflirt, 'rms_files', dispplotter, 'in_file') wf.connect(rotplotter, 'out_file', ds, 'PLOTS.@rotplot') wf.connect(transplotter, 'out_file', ds, 'PLOTS.@transplot') wf.connect(dispplotter, 'out_file', ds, 'PLOTS.@disppplot') #calculate tSNR and the mean moco_Tmean = pe.Node(fsl.maths.MathsCommand(args='-Tmean', out_file='moco_Tmean.nii.gz'), name='moco_Tmean') moco_Tstd = pe.Node(fsl.maths.MathsCommand(args='-Tstd', out_file='moco_Tstd.nii.gz'), name='moco_Tstd') tSNR0 = pe.Node(fsl.maths.MultiImageMaths(op_string='-div %s', out_file='moco_tSNR.nii.gz'), name='moco_tSNR') wf.connect(mcflirt, 'out_file', moco_Tmean, 'in_file') wf.connect(mcflirt, 'out_file', moco_Tstd, 'in_file') wf.connect(moco_Tmean, 'out_file', tSNR0, 'in_file') wf.connect(moco_Tstd, 'out_file', tSNR0, 'operand_files') wf.connect(moco_Tmean, 'out_file', ds, 'TEMP.@moco_Tmean') wf.connect(moco_Tstd, 'out_file', ds, 'TEMP.@moco_Tstd') wf.connect(tSNR0, 'out_file', ds, 'TEMP.@moco_Tsnr') ########################################################################### ######################## No. 7 ###################################### #bias field correction of mean epi for better coregistration bias = pe.Node( fsl.FAST( img_type=2, #restored_image='epi_Tmeanrestored.nii.gz', output_biascorrected=True, out_basename='moco_Tmean', no_pve=True, probability_maps=False), name='bias') wf.connect(moco_Tmean, 'out_file', bias, 'in_files') wf.connect(bias, 'restored_image', ds, 'TEMP.@restored_image') #co-registration to anat using FS BBregister and mean EPI bbregister = pe.Node(fs.BBRegister( subject_id=subject, subjects_dir=fs_dir, contrast_type='t2', init='fsl', out_fsl_file='func2anat.mat', out_reg_file='func2anat.dat', registered_file='moco_Tmean_restored2anat.nii.gz', epi_mask=True), name='bbregister') wf.connect(bias, 'restored_image', bbregister, 'source_file') wf.connect(bbregister, 'registered_file', ds, 'TEMP.@registered_file') wf.connect(bbregister, 'out_fsl_file', ds, 'COREG.@out_fsl_file') wf.connect(bbregister, 'out_reg_file', ds, 'COREG.@out_reg_file') wf.connect(bbregister, 'min_cost_file', ds, 'COREG.@min_cost_file') #inverse func2anat mat inverseXFM = pe.Node(fsl.ConvertXFM(invert_xfm=True, out_file='anat2func.mat'), name='inverseXFM') wf.connect(bbregister, 'out_fsl_file', inverseXFM, 'in_file') wf.connect(inverseXFM, 'out_file', ds, 'COREG.@out_fsl_file_inv') #plot the corregistration quality slicer = pe.Node(fsl.Slicer(middle_slices=True, out_file='func2anat.png'), name='slicer') wf.connect(selectfiles, 'wmedge', slicer, 'image_edges') wf.connect(bbregister, 'registered_file', slicer, 'in_file') wf.connect(slicer, 'out_file', ds, 'PLOTS.@func2anat') ########################################################################### ######################## No. 8 ###################################### #MOCO and COREGISTRATION #resample T1 to EPI resolution to use it as a reference image resample_T1 = pe.Node( fsl.FLIRT(datatype='float', apply_isoxfm=EPI_resolution, out_file='T1_brain_EPI.nii.gz'), #interp='nearestneighbour'),keep spline so it looks nicer name='resample_T1') wf.connect(selectfiles, 'T1_brain', resample_T1, 'in_file') wf.connect(selectfiles, 'T1_brain', resample_T1, 'reference') wf.connect(resample_T1, 'out_file', ds, 'COREG.@resample_T1') #concate matrices (moco and func2anat) volume-wise concat_xfm = pe.MapNode(fsl.ConvertXFM(concat_xfm=True), iterfield=['in_file'], name='concat_xfm') wf.connect(mcflirt, 'mat_file', concat_xfm, 'in_file') wf.connect(bbregister, 'out_fsl_file', concat_xfm, 'in_file2') wf.connect(concat_xfm, 'out_file', ds, 'MOCO2ANAT_MAT.@concat_out') #split func_data split = pe.Node(fsl.Split(dimension='t'), name='split') wf.connect(slicetimer, 'slice_time_corrected_file', split, 'in_file') #motion correction and corregistration in one interpolation step flirt = pe.MapNode(fsl.FLIRT(apply_xfm=True, interp='spline', datatype='float'), iterfield=['in_file', 'in_matrix_file'], name='flirt') wf.connect(split, 'out_files', flirt, 'in_file') wf.connect(resample_T1, 'out_file', flirt, 'reference') wf.connect(concat_xfm, 'out_file', flirt, 'in_matrix_file') #merge the files to have 4d dataset motion corrected and co-registerd to T1 merge = pe.Node(fsl.Merge(dimension='t', merged_file='func_data_stc_moco2anat.nii.gz'), name='merge') wf.connect(flirt, 'out_file', merge, 'in_files') wf.connect(merge, 'merged_file', ds, 'TEMP.@merged') ########################################################################### ######################## No. 9 ###################################### #run BET on co-registered EPI in 1mm and get the mask bet = pe.Node(fsl.BET(mask=True, functional=True, out_file='moco_Tmean_restored2anat_BET.nii.gz'), name='bet') wf.connect(bbregister, 'registered_file', bet, 'in_file') wf.connect(bet, 'out_file', ds, 'TEMP.@func_data_example') wf.connect(bet, 'mask_file', ds, 'TEMP.@func_data_mask') #resample BET mask to EPI resolution resample_mask = pe.Node(fsl.FLIRT( datatype='int', apply_isoxfm=EPI_resolution, interp='nearestneighbour', out_file='prefiltered_func_data_mask.nii.gz'), name='resample_mask') wf.connect(bet, 'mask_file', resample_mask, 'in_file') wf.connect(resample_T1, 'out_file', resample_mask, 'reference') wf.connect(resample_mask, 'out_file', ds, '@mask') #apply the mask to 4D data to get rid of the "eyes and the rest" mask4D = pe.Node(fsl.maths.ApplyMask(), name='mask') wf.connect(merge, 'merged_file', mask4D, 'in_file') wf.connect(resample_mask, 'out_file', mask4D, 'mask_file') ########################################################################### ######################## No. 10 ###################################### #get the values necessary for intensity normalization median = pe.Node(fsl.utils.ImageStats(op_string='-k %s -p 50'), name='median') wf.connect(resample_mask, 'out_file', median, 'mask_file') wf.connect(mask4D, 'out_file', median, 'in_file') #compute the scaling factor def get_factor(val): factor = 10000 / val return factor get_scaling_factor = pe.Node(util.Function(input_names=['val'], output_names=['out_val'], function=get_factor), name='scaling_factor') #normalize the 4D func data with one scaling factor multiplication = pe.Node(fsl.maths.BinaryMaths( operation='mul', out_file='prefiltered_func_data.nii.gz'), name='multiplication') wf.connect(median, 'out_stat', get_scaling_factor, 'val') wf.connect(get_scaling_factor, 'out_val', multiplication, 'operand_value') wf.connect(mask4D, 'out_file', multiplication, 'in_file') wf.connect(multiplication, 'out_file', ds, '@prefiltered_func_data') ########################################################################### ######################## No. 11 ###################################### #calculate tSNR and the mean of the new prefiltered and detrend dataset tsnr_detrend = pe.Node(misc.TSNR( regress_poly=1, detrended_file='prefiltered_func_data_detrend.nii.gz', mean_file='prefiltered_func_data_detrend_Tmean.nii.gz', tsnr_file='prefiltered_func_data_detrend_tSNR.nii.gz'), name='tsnr_detrend') wf.connect(multiplication, 'out_file', tsnr_detrend, 'in_file') wf.connect(tsnr_detrend, 'tsnr_file', ds, 'QC.@tsnr_detrend') wf.connect(tsnr_detrend, 'mean_file', ds, 'QC.@detrend_mean_file') wf.connect(tsnr_detrend, 'detrended_file', ds, '@detrend_file') #resample the EPI mask to original EPI dimensions convert2func = pe.Node(fsl.FLIRT(apply_xfm=True, interp='nearestneighbour', out_file='func_data_mask2func.nii.gz'), name='conver2func') wf.connect(resample_mask, 'out_file', convert2func, 'in_file') wf.connect(bias, 'restored_image', convert2func, 'reference') wf.connect(inverseXFM, 'out_file', convert2func, 'in_matrix_file') wf.connect(convert2func, 'out_file', ds, 'QC.@inv') ########################################################################### ######################## RUN ###################################### wf.write_graph(dotfilename='wf.dot', graph2use='colored', format='pdf', simple_form=True) wf.run(plugin='MultiProc', plugin_args={'n_procs': 2}) #wf.run() return
def create_getmask_flow(name='getmask', dilate_mask=True): """Registers a source file to freesurfer space and create a brain mask in source space Requires fsl tools for initializing registration Parameters ---------- name : string name of workflow dilate_mask : boolean indicates whether to dilate mask or not Example ------- >>> getmask = create_getmask_flow() >>> getmask.inputs.inputspec.source_file = 'mean.nii' >>> getmask.inputs.inputspec.subject_id = 's1' >>> getmask.inputs.inputspec.subjects_dir = '.' >>> getmask.inputs.inputspec.contrast_type = 't2' Inputs:: inputspec.source_file : reference image for mask generation inputspec.subject_id : freesurfer subject id inputspec.subjects_dir : freesurfer subjects directory inputspec.contrast_type : MR contrast of reference image Outputs:: outputspec.mask_file : binary mask file in reference image space outputspec.reg_file : registration file that maps reference image to freesurfer space outputspec.reg_cost : cost of registration (useful for detecting misalignment) """ import nipype.pipeline.engine as pe import nipype.interfaces.utility as niu import nipype.interfaces.freesurfer as fs import nipype.interfaces.io as nio """ Initialize the workflow """ getmask = pe.Workflow(name=name) """ Define the inputs to the workflow. """ inputnode = pe.Node(niu.IdentityInterface(fields=['source_file', 'subject_id', 'subjects_dir', 'contrast_type']), name='inputspec') """ Define all the nodes of the workflow: fssource: used to retrieve aseg.mgz threshold : binarize aseg register : coregister source file to freesurfer space voltransform: convert binarized aseg to source file space """ fssource = pe.Node(nio.FreeSurferSource(), name = 'fssource') threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'), name='threshold') register = pe.MapNode(fs.BBRegister(init='fsl'), iterfield=['source_file'], name='register') voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True), iterfield=['source_file', 'reg_file'], name='transform') """ Connect the nodes """ getmask.connect([ (inputnode, fssource, [('subject_id','subject_id'), ('subjects_dir','subjects_dir')]), (inputnode, register, [('source_file', 'source_file'), ('subject_id', 'subject_id'), ('subjects_dir', 'subjects_dir'), ('contrast_type', 'contrast_type')]), (inputnode, voltransform, [('subjects_dir', 'subjects_dir'), ('source_file', 'source_file')]), (fssource, threshold, [(('aparc_aseg', get_aparc_aseg), 'in_file')]), (register, voltransform, [('out_reg_file','reg_file')]), (threshold, voltransform, [('binary_file','target_file')]) ]) """ Add remaining nodes and connections dilate : dilate the transformed file in source space threshold2 : binarize transformed file """ threshold2 = pe.MapNode(fs.Binarize(min=0.5, out_type='nii'), iterfield=['in_file'], name='threshold2') if dilate_mask: threshold2.inputs.dilate = 1 getmask.connect([ (voltransform, threshold2, [('transformed_file', 'in_file')]) ]) """ Setup an outputnode that defines relevant inputs of the workflow. """ outputnode = pe.Node(niu.IdentityInterface(fields=["mask_file", "reg_file", "reg_cost" ]), name="outputspec") getmask.connect([ (register, outputnode, [("out_reg_file", "reg_file")]), (register, outputnode, [("min_cost_file", "reg_cost")]), (threshold2, outputnode, [("binary_file", "mask_file")]), ]) return getmask
# Below is the command that runs AFNI's 3dTshift command # this is the node that performs the slice timing correction # I input the study func files as a list and the slice timing # as a list of lists. I'm using a MapNode to iterate over the two. # this should allow me to parallelize this on the HPC tshifter = pe.MapNode(afni.TShift(), iterfield=['in_file', 'slice_timing'], name='tshifter') tshifter.inputs.tr = '1.76' tshifter.inputs.slice_timing = slice_timing_list tshifter.inputs.outputtype = 'NIFTI_GZ' psb6351_wf.connect(volreg, 'out_file', tshifter, 'in_file') # Calculate the transformation matrix from EPI space to FreeSurfer space # using the BBRegister command fs_register = pe.Node(fs.BBRegister(init='fsl'), name='fs_register') fs_register.inputs.contrast_type = 't2' fs_register.inputs.out_fsl_file = True fs_register.inputs.subject_id = f'sub-{sids[0]}' fs_register.inputs.subjects_dir = fs_dir psb6351_wf.connect(extractref, 'roi_file', fs_register, 'source_file') # Add a mapnode to spatially blur the data # save the outputs to the datasink Blur = pe.MapNode(afni.BlurToFWHM(), iterfield=['in_file'], name='Blur') #Blur.inputs.in_file = func_files #not needed? Blur.inputs.fwhm = 3 #smoothing width in mm Blur.inputs.automask = True Blur.inputs.num_threads = 2 Blur.inputs.outputtype = 'NIFTI_GZ' psb6351_wf.connect(tshifter, 'out_file', Blur, 'in_file')
intensity or movement. """ art = pe.Node(interface=ra.ArtifactDetect(), name="art") art.inputs.use_differences = [True, False] art.inputs.use_norm = True art.inputs.norm_threshold = 1 art.inputs.zintensity_threshold = 3 art.inputs.mask_type = 'file' art.inputs.parameter_source = 'SPM' """ Use :class:`nipype.interfaces.freesurfer.BBRegister` to coregister the mean functional image generated by realign to the subjects' surfaces. """ surfregister = pe.Node(interface=fs.BBRegister(), name='surfregister') surfregister.inputs.init = 'fsl' surfregister.inputs.contrast_type = 't2' """ Use :class:`nipype.interfaces.io.FreeSurferSource` to retrieve various image files that are automatically generated by the recon-all process. """ FreeSurferSource = pe.Node(interface=nio.FreeSurferSource(), name='fssource') """ Use :class:`nipype.interfaces.freesurfer.ApplyVolTransform` to convert the brainmask generated by freesurfer into the realigned functional space. """ ApplyVolTransform = pe.Node(interface=fs.ApplyVolTransform(), name='applyreg') ApplyVolTransform.inputs.inverse = True
def create_dti(): # main workflow for preprocessing diffusion data # fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # Initiation of a workflow dwi_preproc = Workflow(name="dwi_preproc") # inputnode inputnode = Node(IdentityInterface(fields=[ 'subject_id', 'freesurfer_dir', 'aseg', 'dwi', 'dwi_ap', 'dwi_pa', 'bvals', 'bvecs' ]), name='inputnode') # output node outputnode = Node(IdentityInterface(fields=[ 'dwi_denoised', "dwi_unringed", "topup_corr", "topup_field", "topup_fieldcoef", "eddy_corr", "rotated_bvecs", 'total_movement_rms', 'shell_params', 'cnr_maps', 'residuals', 'outlier_report', 'shell_params', 'dti_fa', 'dti_md', 'dti_l1', 'dti_l2', 'dti_l3', 'dti_v1', 'dti_v2', 'dti_v3', 'fa2anat', 'fa2anat_mat', 'fa2anat_dat' ]), name='outputnode') ''' workflow to run distortion correction ------------------------------------- ''' distor_corr = create_distortion_correct() #'' ## upsampling #TODO: upsample with eddy directly, waiting for Alfred for the method #'' #flirt = Node(fsl.FLIRT(), name='flirt') #flirt.inputs.apply_isoxfm = 1 #TODO: to use this for dtifit, needed to creat another brain mask ''' getting first bval/bvec files ''' get_bvalsvecs = Node(util.Function(input_names=["bvals", "bvecs", "dwi"], output_names=["bval_file", "bvec_file"], function=return_list_element), name="get_bvalsvecs") ''' tensor fitting -------------- ''' dti = Node(fsl.DTIFit(), name='dti') #connecting the nodes dwi_preproc.connect([ (inputnode, distor_corr, [('dwi', 'inputnode.dwi')]), (inputnode, distor_corr, [('dwi_ap', 'inputnode.dwi_ap')]), (inputnode, distor_corr, [('dwi_pa', 'inputnode.dwi_pa')]), (inputnode, get_bvalsvecs, [("bvals", "bvals")]), (inputnode, get_bvalsvecs, [("bvecs", "bvecs")]), (inputnode, get_bvalsvecs, [("dwi", "dwi")]), (get_bvalsvecs, distor_corr, [("bval_file", "inputnode.bvals")]), (get_bvalsvecs, distor_corr, [("bvec_file", "inputnode.bvecs")]), (get_bvalsvecs, dti, [("bval_file", "bvals")]), (distor_corr, outputnode, [('outputnode.bo_brain', 'bo_brain')]), (distor_corr, outputnode, [('outputnode.bo_brainmask', 'bo_brainmask') ]), (distor_corr, outputnode, [('outputnode.noise', 'noise')]), (distor_corr, outputnode, [('outputnode.dwi_denoised', 'dwi_denoised') ]), (distor_corr, outputnode, [('outputnode.dwi_unringed', 'dwi_unringed') ]), (distor_corr, outputnode, [('outputnode.topup_corr', 'topup_corr')]), (distor_corr, outputnode, [('outputnode.topup_field', 'topup_field')]), (distor_corr, outputnode, [('outputnode.topup_fieldcoef', 'topup_fieldcoef')]), (distor_corr, outputnode, [('outputnode.eddy_corr', 'eddy_corr')]), (distor_corr, outputnode, [('outputnode.rotated_bvecs', 'rotated_bvecs')]), (distor_corr, outputnode, [('outputnode.total_movement_rms', 'total_movement_rms')]), (distor_corr, outputnode, [('outputnode.cnr_maps', 'cnr_maps')]), (distor_corr, outputnode, [('outputnode.residuals', 'residuals')]), (distor_corr, outputnode, [('outputnode.shell_params', 'shell_params') ]), (distor_corr, outputnode, [('outputnode.outlier_report', 'outlier_report')]), (distor_corr, dti, [("outputnode.rotated_bvecs", "bvecs")]), (distor_corr, dti, [('outputnode.bo_brainmask', 'mask')]), #(distor_corr, flirt, [('outputnode.eddy_corr', 'in_file')]), #(distor_corr, flirt, [('outputnode.eddy_corr', 'reference')]), #(flirt, dti, [('out_file', 'dwi')]), (distor_corr, dti, [('outputnode.eddy_corr', 'dwi')]), (dti, outputnode, [('FA', 'dti_fa')]), (dti, outputnode, [('MD', 'dti_md')]), (dti, outputnode, [('L1', 'dti_l1')]), (dti, outputnode, [('L2', 'dti_l2')]), (dti, outputnode, [('L3', 'dti_l3')]), (dti, outputnode, [('V1', 'dti_v1')]), (dti, outputnode, [('V2', 'dti_v2')]), (dti, outputnode, [('V3', 'dti_v3')]) ]) ''' coregistration of FA and T1 ------------------------------------ ''' # linear registration with bbregister bbreg = Node(fs.BBRegister(contrast_type='t1', out_fsl_file='fa2anat.mat', out_reg_file='fa2anat.dat', registered_file='fa2anat_bbreg.nii.gz', init='fsl'), name='bbregister') # connecting the nodes dwi_preproc.connect([ (inputnode, bbreg, [('subject_id', 'subject_id')]), (inputnode, bbreg, [('freesurfer_dir', 'subjects_dir')]), (dti, bbreg, [("FA", "source_file")]), (bbreg, outputnode, [('out_fsl_file', 'fa2anat_mat'), ('out_reg_file', 'fa2anat_dat'), ('registered_file', 'fa2anat')]) ]) return dwi_preproc
def create_topup_coreg_pipeline(name='fmap_coreg'): # fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # initiate workflow fmap_coreg = Workflow(name='fmap_coreg') # inputnode inputnode = Node(util.IdentityInterface(fields=[ 'epi_mean', 'ap', 'pa', 'anat_head', 'anat_brain', 'fs_subject_id', 'fs_subjects_dir', 'echo_space', 'pe_dir' ]), name='inputnode') # outputnode outputnode = Node(util.IdentityInterface(fields=[ 'fmap', 'shiftmap', 'unwarpfield_epi2fmap', 'unwarped_mean_epi2fmap', 'epi2anat_mat', 'epi2anat_dat', 'epi2anat_mincost', 'epi2anat', 'epi2fmap', 'fmap_fullwarp' ]), name='outputnode') #### merge epi ap and pa mergeToFilelist = Node(util.Merge(2), infields=['in1', 'in2'], name='mergeToFilelist') merge_appa = Node(fsl.Merge(), name='merge_appa') merge_appa.inputs.dimension = 't' merge_appa.inputs.merged_file = 'cmrr_mbep2d_se_23iso_norm.nii.gz' #use mean file of ap-pa acquisitions as "Mag"-image from fieldmap, only used for coregistration with mean EPI mean_appa = Node(fsl.MeanImage(), name='mean_appa') #### use topup --> creates fieldmap topup_prep = Node(fsl.TOPUP(), name='topup_prep') topup_prep.inputs.encoding_file = '/data/pt_02030/Analysis/Preprocessing/MRI/nipy1.4/functional/aquisition_params.txt' #multiply topup result to convert to rad/s convertHz_rad = Node(fsl.maths.MathsCommand(args='-mul 6.28'), name='convertHz_rad') fmap_coreg.connect([(inputnode, mergeToFilelist, [('ap', 'in1')]), (inputnode, mergeToFilelist, [('pa', 'in2')]), (mergeToFilelist, merge_appa, [('out', 'in_files')]), (merge_appa, mean_appa, [('merged_file', 'in_file')]), (merge_appa, topup_prep, [('merged_file', 'in_file')]), (topup_prep, convertHz_rad, [('out_field', 'in_file')]) ]) #### unmask fieldmap #### is maybe not needed as our fieldmap is already in the whole image space? fmap_mask = Node(fsl.maths.MathsCommand(args='-abs -bin'), name='fmap_mask') # unmask = Node(fsl.FUGUE(save_unmasked_fmap=True), # name='unmask') fmap_coreg.connect([ (convertHz_rad, fmap_mask, [('out_file', 'in_file')]) # (fmap_mask, unmask, [('out_file', 'mask_file')]), # (convertHz_rad, unmask, [('out_file', 'fmap_in_file')]), # (inputnode, unmask, [('pe_dir', 'unwarp_direction')]) ]) #### register epi to fieldmap #### epi2fmap = Node(fsl.FLIRT(dof=6, out_file='rest_mean2fmap.nii.gz', interp='spline'), name='epi2fmap') fmap_coreg.connect([(inputnode, epi2fmap, [('epi_mean', 'in_file')]), (mean_appa, epi2fmap, [('out_file', 'reference')]), (epi2fmap, outputnode, [('out_file', 'epi2fmap')])]) #### unwarp epi with fieldmap #### unwarp = Node(fsl.FUGUE(save_shift=True), name='unwarp') fmap_coreg.connect([ (epi2fmap, unwarp, [('out_file', 'in_file')]), (convertHz_rad, unwarp, [('out_file', 'fmap_in_file')]), (fmap_mask, unwarp, [('out_file', 'mask_file')]), (inputnode, unwarp, [('echo_space', 'dwell_time'), ('pe_dir', 'unwarp_direction')]), (unwarp, outputnode, [('shift_out_file', 'shiftmap')]) ]) #### make warpfield and apply #### convertwarp0 = Node(fsl.utils.ConvertWarp( out_relwarp=True, out_file='rest_mean2fmap_unwarpfield.nii.gz'), name='convertwarp0') applywarp0 = Node(fsl.ApplyWarp(interp='spline', relwarp=True, out_file='rest_mean2fmap_unwarped.nii.gz', datatype='float'), name='applywarp0') fmap_coreg.connect([ (mean_appa, convertwarp0, [('out_file', 'reference')]), (epi2fmap, convertwarp0, [('out_matrix_file', 'premat')]), (unwarp, convertwarp0, [('shift_out_file', 'shift_in_file')]), (inputnode, convertwarp0, [('pe_dir', 'shift_direction')]), (inputnode, applywarp0, [('epi_mean', 'in_file')]), (mean_appa, applywarp0, [('out_file', 'ref_file')]), (convertwarp0, applywarp0, [('out_file', 'field_file')]), (convertwarp0, outputnode, [('out_file', 'unwarpfield_epi2fmap')]), (applywarp0, outputnode, [('out_file', 'unwarped_mean_epi2fmap')]) ]) #### register epi to anatomy ##### # linear registration with bbregister bbregister = Node(fs.BBRegister( contrast_type='t2', out_fsl_file='rest2anat.mat', out_reg_file='rest2anat.dat', registered_file='rest_mean2anat_highres.nii.gz', init='fsl', epi_mask=True), name='bbregister') fmap_coreg.connect([ (applywarp0, bbregister, [('out_file', 'source_file')]), (inputnode, bbregister, [('fs_subjects_dir', 'subjects_dir'), ('fs_subject_id', 'subject_id')]), (bbregister, outputnode, [('out_fsl_file', 'epi2anat_mat'), ('out_reg_file', 'epi2anat_dat'), ('registered_file', 'epi2anat'), ('min_cost_file', 'epi2anat_mincost')]), ]) # make warpfield convertwarp = Node(fsl.utils.ConvertWarp(out_relwarp=True, out_file='fullwarpfield.nii.gz'), name='convertwarp') fmap_coreg.connect([ (inputnode, convertwarp, [('anat_head', 'reference')]), (convertwarp0, convertwarp, [('out_file', 'warp1')]), (bbregister, convertwarp, [('out_fsl_file', 'postmat')]), (convertwarp, outputnode, [('out_file', 'fmap_fullwarp')]) ]) return fmap_coreg
def create_workflow(func_runs, subject_id, subjects_dir, fwhm, slice_times, highpass_frequency, lowpass_frequency, TR, sink_directory, use_fsl_bp, num_components, whichvol, name='wmaze'): wf = pe.Workflow(name=name) datasource = pe.Node(nio.DataGrabber(infields=['subject_id', 'run'], outfields=['func']), name='datasource') datasource.inputs.subject_id = subject_id datasource.inputs.run = func_runs datasource.inputs.template = '/home/data/madlab/data/mri/wmaze/%s/bold/bold_%03d/bold.nii.gz' datasource.inputs.sort_filelist = True # Rename files in case they are named identically name_unique = pe.MapNode(util.Rename(format_string='wmaze_%(run)02d'), iterfield = ['in_file', 'run'], name='rename') name_unique.inputs.keep_ext = True name_unique.inputs.run = func_runs wf.connect(datasource, 'func', name_unique, 'in_file') # Define the outputs for the preprocessing workflow output_fields = ['reference', 'motion_parameters', 'motion_parameters_plusDerivs', 'motionandoutlier_noise_file', 'noise_components', 'realigned_files', 'motion_plots', 'mask_file', 'smoothed_files', 'bandpassed_files', 'reg_file', 'reg_cost', 'reg_fsl_file', 'artnorm_files', 'artoutlier_files', 'artdisplacement_files', 'tsnr_file'] outputnode = pe.Node(util.IdentityInterface(fields=output_fields), name='outputspec') # Convert functional images to float representation img2float = pe.MapNode(fsl.ImageMaths(out_data_type='float', op_string = '', suffix='_dtype'), iterfield=['in_file'], name='img2float') wf.connect(name_unique, 'out_file', img2float, 'in_file') # Run AFNI's despike. This is always run, however, whether this is fed to # realign depends on the input configuration despiker = pe.MapNode(afni.Despike(outputtype='NIFTI_GZ'), iterfield=['in_file'], name='despike') num_threads = 4 despiker.inputs.environ = {'OMP_NUM_THREADS': '%d' % num_threads} despiker.plugin_args = {'bsub_args': '-n %d' % num_threads} despiker.plugin_args = {'bsub_args': '-R "span[hosts=1]"'} wf.connect(img2float, 'out_file', despiker, 'in_file') # Extract the first volume of the first run as the reference extractref = pe.Node(fsl.ExtractROI(t_size=1), iterfield=['in_file'], name = "extractref") wf.connect(despiker, ('out_file', pickfirst), extractref, 'in_file') wf.connect(despiker, ('out_file', pickvol, 0, whichvol), extractref, 't_min') wf.connect(extractref, 'roi_file', outputnode, 'reference') if slice_times is not None: # Simultaneous motion and slice timing correction with Nipy algorithm motion_correct = pe.Node(nipy.SpaceTimeRealigner(), name='motion_correct') motion_correct.inputs.tr = TR motion_correct.inputs.slice_times = slice_times motion_correct.inputs.slice_info = 2 motion_correct.plugin_args = {'bsub_args': '-n %s' %os.environ['MKL_NUM_THREADS']} motion_correct.plugin_args = {'bsub_args': '-R "span[hosts=1]"'} wf.connect(despiker, 'out_file', motion_correct, 'in_file') wf.connect(motion_correct, 'par_file', outputnode, 'motion_parameters') wf.connect(motion_correct, 'out_file', outputnode, 'realigned_files') else: # Motion correct functional runs to the reference (1st volume of 1st run) motion_correct = pe.MapNode(fsl.MCFLIRT(save_mats = True, save_plots = True, interpolation = 'sinc'), name = 'motion_correct', iterfield = ['in_file']) wf.connect(despiker, 'out_file', motion_correct, 'in_file') wf.connect(extractref, 'roi_file', motion_correct, 'ref_file') wf.connect(motion_correct, 'par_file', outputnode, 'motion_parameters') wf.connect(motion_correct, 'out_file', outputnode, 'realigned_files') # Compute TSNR on realigned data regressing polynomials upto order 2 tsnr = pe.MapNode(TSNR(regress_poly=2), iterfield=['in_file'], name='tsnr') wf.connect(motion_correct, 'out_file', tsnr, 'in_file') wf.connect(tsnr, 'tsnr_file', outputnode, 'tsnr_file') # Plot the estimated motion parameters plot_motion = pe.MapNode(fsl.PlotMotionParams(in_source='fsl'), name='plot_motion', iterfield=['in_file']) plot_motion.iterables = ('plot_type', ['rotations', 'translations']) wf.connect(motion_correct, 'par_file', plot_motion, 'in_file') wf.connect(plot_motion, 'out_file', outputnode, 'motion_plots') # Register a source file to fs space and create a brain mask in source space fssource = pe.Node(nio.FreeSurferSource(), name ='fssource') fssource.inputs.subject_id = subject_id fssource.inputs.subjects_dir = subjects_dir # Extract aparc+aseg brain mask and binarize fs_threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'), name ='fs_threshold') wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), fs_threshold, 'in_file') # Calculate the transformation matrix from EPI space to FreeSurfer space # using the BBRegister command fs_register = pe.MapNode(fs.BBRegister(init='fsl'), iterfield=['source_file'], name ='fs_register') fs_register.inputs.contrast_type = 't2' fs_register.inputs.out_fsl_file = True fs_register.inputs.subject_id = subject_id fs_register.inputs.subjects_dir = subjects_dir wf.connect(extractref, 'roi_file', fs_register, 'source_file') wf.connect(fs_register, 'out_reg_file', outputnode, 'reg_file') wf.connect(fs_register, 'min_cost_file', outputnode, 'reg_cost') wf.connect(fs_register, 'out_fsl_file', outputnode, 'reg_fsl_file') # Extract wm+csf, brain masks by eroding freesurfer lables wmcsf = pe.MapNode(fs.Binarize(), iterfield=['match', 'binary_file', 'erode'], name='wmcsfmask') #wmcsf.inputs.wm_ven_csf = True wmcsf.inputs.match = [[2, 41], [4, 5, 14, 15, 24, 31, 43, 44, 63]] wmcsf.inputs.binary_file = ['wm.nii.gz', 'csf.nii.gz'] wmcsf.inputs.erode = [2, 2] #int(np.ceil(slice_thickness)) wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), wmcsf, 'in_file') # Now transform the wm and csf masks to 1st volume of 1st run wmcsftransform = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp='nearest'), iterfield=['target_file'], name='wmcsftransform') wmcsftransform.inputs.subjects_dir = subjects_dir wf.connect(extractref, 'roi_file', wmcsftransform, 'source_file') wf.connect(fs_register, ('out_reg_file', pickfirst), wmcsftransform, 'reg_file') wf.connect(wmcsf, 'binary_file', wmcsftransform, 'target_file') # Transform the binarized aparc+aseg file to the 1st volume of 1st run space fs_voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True), iterfield = ['source_file', 'reg_file'], name='fs_transform') fs_voltransform.inputs.subjects_dir = subjects_dir wf.connect(extractref, 'roi_file', fs_voltransform, 'source_file') wf.connect(fs_register, 'out_reg_file', fs_voltransform, 'reg_file') wf.connect(fs_threshold, 'binary_file', fs_voltransform, 'target_file') # Dilate the binarized mask by 1 voxel that is now in the EPI space fs_threshold2 = pe.MapNode(fs.Binarize(min=0.5, out_type='nii'), iterfield=['in_file'], name='fs_threshold2') fs_threshold2.inputs.dilate = 1 wf.connect(fs_voltransform, 'transformed_file', fs_threshold2, 'in_file') wf.connect(fs_threshold2, 'binary_file', outputnode, 'mask_file') # Use RapidART to detect motion/intensity outliers art = pe.MapNode(ra.ArtifactDetect(use_differences = [True, False], use_norm = True, zintensity_threshold = 3, norm_threshold = 1, bound_by_brainmask=True, mask_type = "file"), iterfield=["realignment_parameters","realigned_files"], name="art") if slice_times is not None: art.inputs.parameter_source = "NiPy" else: art.inputs.parameter_source = "FSL" wf.connect(motion_correct, 'par_file', art, 'realignment_parameters') wf.connect(motion_correct, 'out_file', art, 'realigned_files') wf.connect(fs_threshold2, ('binary_file', pickfirst), art, 'mask_file') wf.connect(art, 'norm_files', outputnode, 'artnorm_files') wf.connect(art, 'outlier_files', outputnode, 'artoutlier_files') wf.connect(art, 'displacement_files', outputnode, 'artdisplacement_files') # Compute motion regressors (save file with 1st and 2nd derivatives) motreg = pe.Node(util.Function(input_names=['motion_params', 'order', 'derivatives'], output_names=['out_files'], function=motion_regressors, imports=imports), name='getmotionregress') wf.connect(motion_correct, 'par_file', motreg, 'motion_params') wf.connect(motreg, 'out_files', outputnode, 'motion_parameters_plusDerivs') # Create a filter text file to remove motion (+ derivatives), art confounds, # and 1st, 2nd, and 3rd order legendre polynomials. createfilter1 = pe.Node(util.Function(input_names=['motion_params', 'comp_norm', 'outliers', 'detrend_poly'], output_names=['out_files'], function=build_filter1, imports=imports), name='makemotionbasedfilter') createfilter1.inputs.detrend_poly = 3 wf.connect(motreg, 'out_files', createfilter1, 'motion_params') wf.connect(art, 'norm_files', createfilter1, 'comp_norm') wf.connect(art, 'outlier_files', createfilter1, 'outliers') wf.connect(createfilter1, 'out_files', outputnode, 'motionandoutlier_noise_file') # Create a filter to remove noise components based on white matter and CSF createfilter2 = pe.MapNode(util.Function(input_names=['realigned_file', 'mask_file', 'num_components', 'extra_regressors'], output_names=['out_files'], function=extract_noise_components, imports=imports), iterfield=['realigned_file', 'extra_regressors'], name='makecompcorrfilter') createfilter2.inputs.num_components = num_components wf.connect(createfilter1, 'out_files', createfilter2, 'extra_regressors') wf.connect(motion_correct, 'out_file', createfilter2, 'realigned_file') wf.connect(wmcsftransform, 'transformed_file', createfilter2, 'mask_file') wf.connect(createfilter2, 'out_files', outputnode, 'noise_components') # Mask the functional runs with the extracted mask maskfunc = pe.MapNode(fsl.ImageMaths(suffix='_bet', op_string='-mas'), iterfield=['in_file'], name = 'maskfunc') wf.connect(motion_correct, 'out_file', maskfunc, 'in_file') wf.connect(fs_threshold2, ('binary_file', pickfirst), maskfunc, 'in_file2') # Smooth each run using SUSAn with the brightness threshold set to 75% # of the median value for each run and a mask constituting the mean functional smooth_median = pe.MapNode(fsl.ImageStats(op_string='-k %s -p 50'), iterfield = ['in_file'], name='smooth_median') wf.connect(maskfunc, 'out_file', smooth_median, 'in_file') wf.connect(fs_threshold2, ('binary_file', pickfirst), smooth_median, 'mask_file') smooth_meanfunc = pe.MapNode(fsl.ImageMaths(op_string='-Tmean', suffix='_mean'), iterfield=['in_file'], name='smooth_meanfunc') wf.connect(maskfunc, 'out_file', smooth_meanfunc, 'in_file') smooth_merge = pe.Node(util.Merge(2, axis='hstack'), name='smooth_merge') wf.connect(smooth_meanfunc, 'out_file', smooth_merge, 'in1') wf.connect(smooth_median, 'out_stat', smooth_merge, 'in2') smooth = pe.MapNode(fsl.SUSAN(), iterfield=['in_file', 'brightness_threshold', 'usans'], name='smooth') smooth.inputs.fwhm=fwhm wf.connect(maskfunc, 'out_file', smooth, 'in_file') wf.connect(smooth_median, ('out_stat', getbtthresh), smooth, 'brightness_threshold') wf.connect(smooth_merge, ('out', getusans), smooth, 'usans') # Mask the smoothed data with the dilated mask maskfunc2 = pe.MapNode(fsl.ImageMaths(suffix='_mask', op_string='-mas'), iterfield=['in_file'], name='maskfunc2') wf.connect(smooth, 'smoothed_file', maskfunc2, 'in_file') wf.connect(fs_threshold2, ('binary_file', pickfirst), maskfunc2, 'in_file2') wf.connect(maskfunc2, 'out_file', outputnode, 'smoothed_files') # Band-pass filter the timeseries if use_fsl_bp == 'True': determine_bp_sigmas = pe.Node(util.Function(input_names=['tr', 'highpass_freq', 'lowpass_freq'], output_names = ['out_sigmas'], function=calc_fslbp_sigmas), name='determine_bp_sigmas') determine_bp_sigmas.inputs.tr = float(TR) determine_bp_sigmas.inputs.highpass_freq = float(highpass_frequency) determine_bp_sigmas.inputs.lowpass_freq = float(lowpass_frequency) bandpass = pe.MapNode(fsl.ImageMaths(suffix='_tempfilt'), iterfield=["in_file"], name="bandpass") wf.connect(determine_bp_sigmas, ('out_sigmas', highpass_operand), bandpass, 'op_string') wf.connect(maskfunc2, 'out_file', bandpass, 'in_file') wf.connect(bandpass, 'out_file', outputnode, 'bandpassed_files') else: bandpass = pe.Node(util.Function(input_names=['files', 'lowpass_freq', 'highpass_freq', 'fs'], output_names=['out_files'], function=bandpass_filter, imports=imports), name='bandpass') bandpass.inputs.fs = 1./TR if highpass_frequency < 0: bandpass.inputs.highpass_freq = -1 else: bandpass.inputs.highpass_freq = highpass_frequency if lowpass_frequency < 0: bandpass.inputs.lowpass_freq = -1 else: bandpass.inputs.lowpass_freq = lowpass_frequency wf.connect(maskfunc2, 'out_file', bandpass, 'files') wf.connect(bandpass, 'out_files', outputnode, 'bandpassed_files') # Save the relevant data into an output directory datasink = pe.Node(nio.DataSink(), name="datasink") datasink.inputs.base_directory = sink_directory datasink.inputs.container = subject_id wf.connect(outputnode, 'reference', datasink, 'ref') wf.connect(outputnode, 'motion_parameters', datasink, 'motion') wf.connect(outputnode, 'realigned_files', datasink, 'func.realigned') wf.connect(outputnode, 'motion_plots', datasink, 'motion.@plots') wf.connect(outputnode, 'mask_file', datasink, 'ref.@mask') wf.connect(outputnode, 'smoothed_files', datasink, 'func.smoothed_fullspectrum') wf.connect(outputnode, 'bandpassed_files', datasink, 'func.smoothed_bandpassed') wf.connect(outputnode, 'reg_file', datasink, 'bbreg.@reg') wf.connect(outputnode, 'reg_cost', datasink, 'bbreg.@cost') wf.connect(outputnode, 'reg_fsl_file', datasink, 'bbreg.@regfsl') wf.connect(outputnode, 'artnorm_files', datasink, 'art.@norm_files') wf.connect(outputnode, 'artoutlier_files', datasink, 'art.@outlier_files') wf.connect(outputnode, 'artdisplacement_files', datasink, 'art.@displacement_files') wf.connect(outputnode, 'motion_parameters_plusDerivs', datasink, 'noise.@motionplusDerivs') wf.connect(outputnode, 'motionandoutlier_noise_file', datasink, 'noise.@motionplusoutliers') wf.connect(outputnode, 'noise_components', datasink, 'compcor') wf.connect(outputnode, 'tsnr_file', datasink, 'tsnr') return wf
func_tstat = pe.MapNode(interface=e_afni.ThreedTstat(), name='func_tstat', iterfield=["in_file"]) func_tstat.inputs.args = "-mean" func_tstat.inputs.out_file = 'rest_ro_mean.nii.gz' func_volreg = pe.MapNode(interface=e_afni.Threedvolreg(), name='func_volreg', iterfield=["in_file", "basefile"]) func_volreg.inputs.other = '-Fourier -twopass' func_volreg.inputs.zpad = '4' func_volreg.inputs.oned_file = 'rest_mc.1D' func_volreg.inputs.out_file = 'rest_mc.nii.gz' func_bbreg = pe.MapNode(interface=fs.BBRegister(init='fsl', contrast_type='t2', registered_file=True, out_fsl_file=True), name='func_bbreg', iterfield=["source_file"]) func_sampler_lh = pe.MapNode(interface=fs.SampleToSurface(hemi="lh"), name='func_sampler_lh', iterfield=["source_file", "reg_file"]) func_sampler_lh.inputs.no_reshape = True func_sampler_lh.inputs.interp_method = 'trilinear' func_sampler_lh.inputs.sampling_method = "point" func_sampler_lh.inputs.sampling_range = 0.5 func_sampler_lh.inputs.sampling_units = "frac" func_sampler_rh = pe.MapNode(interface=fs.SampleToSurface(hemi="rh"), name='func_sampler_rh',
def create_epi_to_T1_workflow(name='epi_to_T1', use_FS=True, do_FAST=True): """Registers session's EPI space to subject's T1 space uses either FLIRT or, when a FS segmentation is present, BBRegister Requires fsl and freesurfer tools Parameters ---------- name : string name of workflow use_FS : bool whether to use freesurfer's segmentation and BBRegister Example ------- >>> epi_to_T1 = create_epi_to_T1_workflow('epi_to_T1', use_FS = True) >>> epi_to_T1.inputs.inputspec.EPI_space_file = 'example_Func.nii.gz' >>> epi_to_T1.inputs.inputspec.T1_file = 'T1.nii.gz' >>> epi_to_T1.inputs.inputspec.freesurfer_subject_ID = 'sub_01' >>> epi_to_T1.inputs.inputspec.freesurfer_subject_dir = '$SUBJECTS_DIR' Inputs:: inputspec.T1_file : T1 anatomy file inputspec.EPI_space_file : EPI session file inputspec.freesurfer_subject_ID : FS subject ID inputspec.freesurfer_subject_dir : $SUBJECTS_DIR Outputs:: outputspec.EPI_T1_register_file : BBRegister registration file that maps EPI space to T1 outputspec.EPI_T1_matrix_file : FLIRT registration file that maps EPI space to T1 outputspec.T1_EPI_matrix_file : FLIRT registration file that maps T1 space to EPI """ input_node = pe.Node(IdentityInterface(fields=[ 'EPI_space_file', 'output_directory', 'freesurfer_subject_ID', 'freesurfer_subject_dir', 'T1_file' ]), name='inputspec') # Idea: also output FAST outputs for later use? output_node = pe.Node(IdentityInterface(fields=('EPI_T1_matrix_file', 'T1_EPI_matrix_file', 'EPI_T1_register_file')), name='outputspec') epi_to_T1_workflow = pe.Workflow(name=name) if use_FS: # do BBRegister bbregister_N = pe.Node(freesurfer.BBRegister(init='fsl', contrast_type='t2', out_fsl_file=True), name='bbregister_N') epi_to_T1_workflow.connect(input_node, 'EPI_space_file', bbregister_N, 'source_file') epi_to_T1_workflow.connect(input_node, 'freesurfer_subject_ID', bbregister_N, 'subject_id') epi_to_T1_workflow.connect(input_node, 'freesurfer_subject_dir', bbregister_N, 'subjects_dir') epi_to_T1_workflow.connect(bbregister_N, 'out_fsl_file', output_node, 'EPI_T1_matrix_file') epi_to_T1_workflow.connect(bbregister_N, 'out_reg_file', output_node, 'EPI_T1_register_file') # the final invert node invert_EPI_N = pe.Node(fsl.ConvertXFM(invert_xfm=True), name='invert_EPI_N') epi_to_T1_workflow.connect(bbregister_N, 'out_fsl_file', invert_EPI_N, 'in_file') epi_to_T1_workflow.connect(invert_EPI_N, 'out_file', output_node, 'T1_EPI_matrix_file') else: # do FAST + FLIRT flirt_e2t = pe.Node(fsl.FLIRT(cost_func='bbr', output_type='NIFTI_GZ', dof=12, interp='sinc'), name='flirt_e2t') epi_to_T1_workflow.connect(input_node, 'EPI_space_file', flirt_e2t, 'in_file') if do_FAST: fast = pe.Node(fsl.FAST(no_pve=True, img_type=1, segments=True), name='fast') epi_to_T1_workflow.connect(input_node, 'T1_file', fast, 'in_files') epi_to_T1_workflow.connect(fast, ('tissue_class_files', pick_last), flirt_e2t, 'wm_seg') elif not do_FAST and flirt_e2t.inputs.cost_func == 'bbr': print( 'You indicated not wanting to do FAST, but still wanting to do a' ' BBR epi-to-T1 registration. That is probably not going to work ...' ) epi_to_T1_workflow.connect(input_node, 'T1_file', flirt_e2t, 'reference') epi_to_T1_workflow.connect(flirt_e2t, 'out_matrix_file', output_node, 'EPI_T1_matrix_file') # the final invert node invert_EPI_N = pe.Node(fsl.ConvertXFM(invert_xfm=True), name='invert_EPI_N') epi_to_T1_workflow.connect(flirt_e2t, 'out_matrix_file', invert_EPI_N, 'in_file') epi_to_T1_workflow.connect(invert_EPI_N, 'out_file', output_node, 'T1_EPI_matrix_file') return epi_to_T1_workflow
def create_workflow(self, flow, inputnode, outputnode): # Extract first volume and resample it to 1x1x1mm3 if self.config.pipeline == "Diffusion": extract_first = pe.Node(interface=fsl.ExtractROI(t_min=0,t_size=1,roi_file='first.nii.gz'),name='extract_first') flow.connect([ (inputnode,extract_first,[("target","in_file")]) ]) fs_mriconvert = pe.Node(interface=fs.MRIConvert(out_file="target_first.nii.gz",vox_size=(1,1,1)),name="target_resample") flow.connect([(extract_first, fs_mriconvert,[('roi_file','in_file')])]) elif self.config.pipeline == "fMRI": fmri_bet = pe.Node(interface=fsl.BET(),name="fMRI_skullstrip") T1_bet = pe.Node(interface=fsl.BET(),name="T1_skullstrip") flow.connect([ (inputnode,fmri_bet,[("target","in_file")]), (inputnode,T1_bet,[("T1","in_file")]) ]) if self.config.registration_mode == 'Linear (FSL)': fsl_flirt = pe.Node(interface=fsl.FLIRT(out_file='T1-TO-TARGET.nii.gz',out_matrix_file='T1-TO-TARGET.mat'),name="linear_registration") fsl_flirt.inputs.uses_qform = self.config.uses_qform fsl_flirt.inputs.dof = self.config.dof fsl_flirt.inputs.cost = self.config.cost fsl_flirt.inputs.no_search = self.config.no_search fsl_flirt.inputs.args = self.config.flirt_args fsl_applyxfm_wm = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="wm_mask_registered.nii.gz"),name="apply_registration_wm") fsl_applyxfm_rois = pe.Node(interface=ApplymultipleXfm(),name="apply_registration_roivs") flow.connect([ (inputnode, fsl_applyxfm_wm, [('wm_mask','in_file')]), (fsl_flirt,outputnode,[("out_file","T1_registered")]), (fsl_flirt, fsl_applyxfm_wm, [('out_matrix_file','in_matrix_file')]), (fsl_applyxfm_wm, outputnode, [('out_file','wm_mask_registered')]), (inputnode, fsl_applyxfm_rois, [('roi_volumes','in_files')]), (fsl_flirt, fsl_applyxfm_rois, [('out_matrix_file','xfm_file')]), (fsl_applyxfm_rois, outputnode, [('out_files','roi_volumes_registered')]) ]) if self.config.pipeline == "fMRI": flow.connect([ (T1_bet, fsl_flirt, [('out_file','in_file')]), (fmri_bet, fsl_flirt, [('out_file','reference')]), (fmri_bet, fsl_applyxfm_wm, [('out_file','reference')]), (fmri_bet, fsl_applyxfm_rois, [('out_file','reference')]) ]) fsl_applyxfm_eroded_wm = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="eroded_wm_registered.nii.gz"),name="apply_registration_wm_eroded") if self.config.apply_to_eroded_csf: fsl_applyxfm_eroded_csf = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="eroded_csf_registered.nii.gz"),name="apply_registration_csf_eroded") flow.connect([ (inputnode, fsl_applyxfm_eroded_csf, [('eroded_csf','in_file')]), (fmri_bet, fsl_applyxfm_eroded_csf, [('out_file','reference')]), (fsl_flirt, fsl_applyxfm_eroded_csf, [('out_matrix_file','in_matrix_file')]), (fsl_applyxfm_eroded_csf, outputnode, [('out_file','eroded_csf_registered')]) ]) if self.config.apply_to_eroded_brain: fsl_applyxfm_eroded_brain = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="eroded_brain_registered.nii.gz"),name="apply_registration_brain_eroded") flow.connect([ (inputnode, fsl_applyxfm_eroded_brain, [('eroded_brain','in_file')]), (fmri_bet, fsl_applyxfm_eroded_brain, [('out_file','reference')]), (fsl_flirt, fsl_applyxfm_eroded_brain, [('out_matrix_file','in_matrix_file')]), (fsl_applyxfm_eroded_brain, outputnode, [('out_file','eroded_brain_registered')]) ]) flow.connect([ (inputnode, fsl_applyxfm_eroded_wm, [('eroded_wm','in_file')]), (fmri_bet, fsl_applyxfm_eroded_wm, [('out_file','reference')]), (fsl_flirt, fsl_applyxfm_eroded_wm, [('out_matrix_file','in_matrix_file')]), (fsl_applyxfm_eroded_wm, outputnode, [('out_file','eroded_wm_registered')]) ]) else: flow.connect([ (inputnode, fsl_flirt, [('T1','in_file')]), (fs_mriconvert, fsl_flirt, [('out_file','reference')]), (fs_mriconvert, fsl_applyxfm_wm, [('out_file','reference')]), (fs_mriconvert, fsl_applyxfm_rois, [('out_file','reference')]), ]) if self.config.registration_mode == 'BBregister (FS)': fs_bbregister = pe.Node(interface=fs.BBRegister(out_fsl_file="target-TO-orig.mat"),name="bbregister") fs_bbregister.inputs.init = self.config.init fs_bbregister.inputs.contrast_type = self.config.contrast_type fsl_invertxfm = pe.Node(interface=fsl.ConvertXFM(invert_xfm=True),name="fsl_invertxfm") fs_source = pe.Node(interface=fs.preprocess.FreeSurferSource(),name="get_fs_files") fs_tkregister2 = pe.Node(interface=Tkregister2(regheader=True,noedit=True),name="fs_tkregister2") fs_tkregister2.inputs.reg_out = 'T1-TO-orig.dat' fs_tkregister2.inputs.fslreg_out = 'T1-TO-orig.mat' fsl_concatxfm = pe.Node(interface=fsl.ConvertXFM(concat_xfm=True),name="fsl_concatxfm") fsl_applyxfm = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,out_file="T1-TO-TARGET.nii.gz"),name="linear_registration") fsl_applyxfm_wm = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="wm_mask_registered.nii.gz"),name="apply_registration_wm") fsl_applyxfm_rois = pe.Node(interface=ApplymultipleXfm(),name="apply_registration_roivs") flow.connect([ (inputnode, fs_bbregister, [(('subjects_dir',unicode2str),'subjects_dir'),(('subject_id',os.path.basename),'subject_id')]), (fs_bbregister, fsl_invertxfm, [('out_fsl_file','in_file')]), (fsl_invertxfm, fsl_concatxfm, [('out_file','in_file2')]), (inputnode,fs_source,[("subjects_dir","subjects_dir"),(("subject_id",os.path.basename),"subject_id")]), (inputnode, fs_tkregister2, [('subjects_dir','subjects_dir'),(('subject_id',os.path.basename),'subject_id')]), (fs_source,fs_tkregister2,[("orig","target_file"),("rawavg","in_file")]), (fs_tkregister2, fsl_concatxfm, [('fslregout_file','in_file')]), (inputnode, fsl_applyxfm, [('T1','in_file')]), (fsl_concatxfm, fsl_applyxfm, [('out_file','in_matrix_file')]), (fsl_applyxfm,outputnode,[("out_file","T1_registered")]), (inputnode, fsl_applyxfm_wm, [('wm_mask','in_file')]), (fsl_concatxfm, fsl_applyxfm_wm, [('out_file','in_matrix_file')]), (fsl_applyxfm_wm, outputnode, [('out_file','wm_mask_registered')]), (inputnode, fsl_applyxfm_rois, [('roi_volumes','in_files')]), (fsl_concatxfm, fsl_applyxfm_rois, [('out_file','xfm_file')]), (fsl_applyxfm_rois, outputnode, [('out_files','roi_volumes_registered')]) ]) if self.config.pipeline == "fMRI": flow.connect([ (inputnode, fs_bbregister, [('target','source_file')]), (inputnode, fsl_applyxfm, [('target','reference')]), (inputnode, fsl_applyxfm_wm, [('target','reference')]), (inputnode, fsl_applyxfm_rois, [('target','reference')]), ]) fsl_applyxfm_eroded_wm = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="eroded_wm_registered.nii.gz"),name="apply_registration_wm_eroded") if self.config.apply_to_eroded_csf: fsl_applyxfm_eroded_csf = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="eroded_csf_registered.nii.gz"),name="apply_registration_csf_eroded") flow.connect([ (inputnode, fsl_applyxfm_eroded_csf, [('eroded_csf','in_file')]), (inputnode, fsl_applyxfm_eroded_csf, [('target','reference')]), (fsl_concatxfm, fsl_applyxfm_eroded_csf, [('out_file','in_matrix_file')]), (fsl_applyxfm_eroded_csf, outputnode, [('out_file','eroded_csf_registered')]) ]) if self.config.apply_to_eroded_brain: fsl_applyxfm_eroded_brain = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True,interp="nearestneighbour",out_file="eroded_brain_registered.nii.gz"),name="apply_registration_brain_eroded") flow.connect([ (inputnode, fsl_applyxfm_eroded_brain, [('eroded_brain','in_file')]), (inputnode, fsl_applyxfm_eroded_brain, [('target','reference')]), (fsl_concatxfm, fsl_applyxfm_eroded_brain, [('out_file','in_matrix_file')]), (fsl_applyxfm_eroded_brain, outputnode, [('out_file','eroded_brain_registered')]) ]) flow.connect([ (inputnode, fsl_applyxfm_eroded_wm, [('eroded_wm','in_file')]), (inputnode, fsl_applyxfm_eroded_wm, [('target','reference')]), (fsl_concatxfm, fsl_applyxfm_eroded_wm, [('out_file','in_matrix_file')]), (fsl_applyxfm_eroded_wm, outputnode, [('out_file','eroded_wm_registered')]) ]) else: flow.connect([ (fs_mriconvert, fs_bbregister, [('out_file','source_file')]), (fs_mriconvert, fsl_applyxfm, [('out_file','reference')]), (fs_mriconvert, fsl_applyxfm_wm, [('out_file','reference')]), (fs_mriconvert, fsl_applyxfm_rois, [('out_file','reference')]), ]) if self.config.registration_mode == 'Nonlinear (FSL)': # [SUB-STEP 1] LINEAR register "T2" onto "Target_resampled # [1.1] linear register "T1" onto "T2" fsl_flirt_1 = pe.Node(interface=fsl.FLIRT(out_file='T1-TO-T2.nii.gz',out_matrix_file='T1-TO-T2.mat'),name="t1tot2_lin_registration") fsl_flirt_1.inputs.dof = 6 fsl_flirt_1.inputs.cost = "mutualinfo" fsl_flirt_1.inputs.no_search = True #[1.2] -> linear register "T2" onto "target_resampled" fsl_flirt_2 = pe.Node(interface=fsl.FLIRT(out_file='T2-TO-TARGET.nii.gz',out_matrix_file='T2-TO-TARGET.mat'),name="t2totarget_lin_registration") fsl_flirt_2.inputs.dof = 12 fsl_flirt_2.inputs.cost = "normmi" fsl_flirt_2.inputs.no_search = True #[1.3] -> apply the linear registration "T1" --> "target" (for comparison) fsl_concatxfm = pe.Node(interface=fsl.ConvertXFM(concat_xfm=True),name="fsl_concatxfm") fsl_applyxfm = pe.Node(interface=fsl.ApplyXfm(apply_xfm=True, interp="sinc",out_file='T1-TO-target.nii.gz',out_matrix_file='T1-TO-TARGET.mat'),name="linear_registration") #"[SUB-STEP 2] Create BINARY MASKS for nonlinear registration" # [2.1] -> create a T2 brain mask fsl_bet_1 = pe.Node(interface=fsl.BET(out_file='T2-brain',mask=True,no_output=True,robust=True),name="t2_brain_mask") fsl_bet_1.inputs.frac = 0.35 fsl_bet_1.inputs.vertical_gradient = 0.15 #[2.2] -> create a DSI_target brain mask fsl_bet_2 = pe.Node(interface=fsl.BET(out_file='target-brain',mask=True,no_output=True,robust=True),name="target_brain_mask") fsl_bet_2.inputs.frac = 0.2 fsl_bet_2.inputs.vertical_gradient = 0.2 # [SUB-STEP 3] NONLINEAR register "T2" onto "target_resampled" # [3.1] 'Started FNIRT to find 'T2 --> target' nonlinear transformation at fsl_fnirt = pe.Node(interface=fsl.FNIRT(field_file='T2-TO-target_warp.nii.gz'),name="t2totarget_nlin_registration") fsl_fnirt.inputs.subsampling_scheme = [8,4,2,2] fsl_fnirt.inputs.max_nonlin_iter = [5,5,5,5] fsl_fnirt.inputs.regularization_lambda = [240,120,90,30] fsl_fnirt.inputs.spline_order = 3 fsl_fnirt.inputs.apply_inmask = [0,0,1,1] fsl_fnirt.inputs.apply_refmask = [0,0,1,1] #[3.2] -> apply the warp found for "T2" also onto "T1" fsl_applywarp = pe.Node(interface=fsl.ApplyWarp(out_file='T1_warped.nii.gz'),name="nonlinear_registration") fsl_applywarp_wm = pe.Node(interface=fsl.ApplyWarp(interp="nn",out_file="wm_mask_registered.nii.gz"),name="apply_registration_wm") fsl_applywarp_rois = pe.Node(interface=Applynlinmultiplewarps(),name="apply_registration_roivs") # TO FIX: Applynlinmultiplewarps() done because applying MapNode to fsl.ApplyWarp crashes #fsl_applywarp_rois = pe.MapNode(interface=fsl.ApplyWarp(interp="nn"),name="apply_registration_roivs",iterfield=["in_file"]) flow.connect([ (inputnode,fsl_flirt_1,[('T1','in_file'),('T2','reference')]), (inputnode,fsl_flirt_2,[('T2','in_file')]), (fsl_flirt_1,fsl_concatxfm,[('out_matrix_file','in_file')]), (fsl_flirt_2,fsl_concatxfm,[('out_matrix_file','in_file2')]), (inputnode,fsl_applyxfm,[('T1','in_file')]), (fsl_concatxfm,fsl_applyxfm,[('out_file','in_matrix_file')]), (inputnode,fsl_bet_1,[('T2','in_file')]), (inputnode,fsl_fnirt,[('T2','in_file')]), (fsl_flirt_2,fsl_fnirt,[('out_matrix_file','affine_file')]), (fsl_bet_1,fsl_fnirt,[('mask_file','inmask_file')]), (fsl_bet_2,fsl_fnirt,[('mask_file','refmask_file')]), (inputnode,fsl_applywarp,[('T1','in_file')]), (fsl_flirt_1,fsl_applywarp,[('out_matrix_file','premat')]), (fsl_fnirt,fsl_applywarp,[('field_file','field_file')]), (inputnode, fsl_applywarp_wm, [('wm_mask','in_file')]), (fsl_flirt_1, fsl_applywarp_wm, [('out_matrix_file','premat')]), (fsl_fnirt,fsl_applywarp_wm,[('field_file','field_file')]), (fsl_applywarp_wm, outputnode, [('out_file','wm_mask_registered')]), (inputnode, fsl_applywarp_rois, [('roi_volumes','in_files')]), (fsl_flirt_1, fsl_applywarp_rois, [('out_matrix_file','premat_file')]), (fsl_fnirt,fsl_applywarp_rois,[('field_file','field_file')]), (fsl_applywarp_rois, outputnode, [('warped_files','roi_volumes_registered')]) ]) if self.config.pipeline == "fMRI": flow.connect([ (inputnode,fsl_flirt_2,[('target','reference')]), (inputnode,fsl_applyxfm,[('target','reference')]), (inputnode,fsl_bet_2,[('target','in_file')]), (inputnode,fsl_fnirt,[('target','ref_file')]), (inputnode,fsl_applywarp,[('target','ref_file')]), (inputnode, fsl_applywarp_wm, [('target','ref_file')]), (inputnode, fsl_applywarp_rois, [('target','ref_file')]), ]) fsl_applywarp_eroded_wm = pe.Node(interface=fsl.ApplyWarp(interp="nn",out_file="eroded_wm_registered.nii.gz"),name="apply_registration_eroded_wm") if self.config.apply_to_eroded_csf: fsl_applywarp_eroded_csf = pe.Node(interface=fsl.ApplyWarp(interp="nn",out_file="eroded_csf_registered.nii.gz"),name="apply_registration_eroded_csf") flow.connect([ (inputnode, fsl_applywarp_eroded_csf, [('eroded_csf','in_file')]), (inputnode, fsl_applywarp_eroded_csf, [('target','ref_file')]), (fsl_flirt_1, fsl_applywarp_eroded_csf, [('out_matrix_file','premat')]), (fsl_fnirt,fsl_applywarp_eroded_csf,[('field_file','field_file')]), (fsl_applywarp_eroded_csf, outputnode, [('out_file','eroded_csf_registered')]) ]) if self.config.apply_to_eroded_brain: fsl_applywarp_eroded_brain = pe.Node(interface=fsl.ApplyWarp(interp="nn",out_file="eroded_brain_registered.nii.gz"),name="apply_registration_eroded_brain") flow.connect([ (inputnode, fsl_applywarp_eroded_brain, [('eroded_brain','in_file')]), (inputnode, fsl_applywarp_eroded_brain, [('target','ref_file')]), (fsl_flirt_1, fsl_applywarp_eroded_brain, [('out_matrix_file','premat')]), (fsl_fnirt,fsl_applywarp_eroded_brain,[('field_file','field_file')]), (fsl_applywarp_eroded_brain, outputnode, [('out_file','eroded_brain_registered')]) ]) flow.connect([ (inputnode, fsl_applywarp_eroded_wm, [('eroded_wm','in_file')]), (inputnode, fsl_applywarp_eroded_wm, [('target','ref_file')]), (fsl_flirt_1, fsl_applywarp_eroded_wm, [('out_matrix_file','premat')]), (fsl_fnirt,fsl_applywarp_eroded_wm,[('field_file','field_file')]), (fsl_applywarp_eroded_wm, outputnode, [('out_file','eroded_wm_registered')]) ]) else: flow.connect([ (fs_mriconvert,fsl_flirt_2,[('out_file','reference')]), (fs_mriconvert,fsl_applyxfm,[('out_file','reference')]), (fs_mriconvert,fsl_bet_2,[('out_file','in_file')]), (fs_mriconvert,fsl_fnirt,[('out_file','ref_file')]), (fs_mriconvert,fsl_applywarp,[('out_file','ref_file')]), (fs_mriconvert, fsl_applywarp_wm, [('out_file','ref_file')]), (fs_mriconvert, fsl_applywarp_rois, [('out_file','ref_file')]), ])
def create_fmap_coreg_pipeline(name='fmap_coreg'): # fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # initiate workflow fmap_coreg = Workflow(name='fmap_coreg') #inputnode inputnode = Node(util.IdentityInterface(fields=[ 'epi_mean', 'mag', 'phase', 'anat_head', 'anat_brain', 'fs_subject_id', 'fs_subjects_dir', 'echo_space', 'te_diff', 'pe_dir' ]), name='inputnode') # outputnode outputnode = Node(util.IdentityInterface(fields=[ 'fmap', 'shiftmap', 'unwarpfield_epi2fmap', 'unwarped_mean_epi2fmap', 'epi2anat_mat', 'epi2anat_dat', 'epi2anat_mincost', 'epi2anat', 'epi2fmap', 'fmap_fullwarp' ]), name='outputnode') #### prepare fieldmap #### # split first magnitude image from mag input split = Node(fsl.ExtractROI(t_min=0, t_size=1), name='split') fmap_coreg.connect(inputnode, 'mag', split, 'in_file') # strip magnitude image and erode even further bet = Node(fsl.BET(frac=0.5, mask=True), name='bet') fmap_coreg.connect(split, 'roi_file', bet, 'in_file') erode = Node(fsl.maths.ErodeImage(kernel_shape='sphere', kernel_size=3, args=''), name='erode') fmap_coreg.connect(bet, 'out_file', erode, 'in_file') # prepare fieldmap prep_fmap = Node(fsl.epi.PrepareFieldmap(), name='prep_fmap') fmap_coreg.connect([(erode, prep_fmap, [('out_file', 'in_magnitude')]), (inputnode, prep_fmap, [('phase', 'in_phase'), ('te_diff', 'delta_TE')]), (prep_fmap, outputnode, [('out_fieldmap', 'fmap')])]) #### unmask fieldmap #### fmap_mask = Node(fsl.maths.MathsCommand(args='-abs -bin'), name='fmap_mask') unmask = Node(fsl.FUGUE(save_unmasked_fmap=True), name='unmask') fmap_coreg.connect([(prep_fmap, fmap_mask, [('out_fieldmap', 'in_file')]), (fmap_mask, unmask, [('out_file', 'mask_file')]), (prep_fmap, unmask, [('out_fieldmap', 'fmap_in_file') ]), (inputnode, unmask, [('pe_dir', 'unwarp_direction')])]) #### register epi to fieldmap #### epi2fmap = Node(fsl.FLIRT(dof=6, out_file='rest_mean2fmap.nii.gz', interp='spline'), name='epi2fmap') fmap_coreg.connect([(inputnode, epi2fmap, [('epi_mean', 'in_file')]), (split, epi2fmap, [('roi_file', 'reference')]), (epi2fmap, outputnode, [('out_file', 'epi2fmap')])]) #### unwarp epi with fieldmap #### unwarp = Node(fsl.FUGUE(save_shift=True), name='unwarp') fmap_coreg.connect([(epi2fmap, unwarp, [('out_file', 'in_file')]), (unmask, unwarp, [('fmap_out_file', 'fmap_in_file')]), (fmap_mask, unwarp, [('out_file', 'mask_file')]), (inputnode, unwarp, [('echo_space', 'dwell_time'), ('pe_dir', 'unwarp_direction')]), (unwarp, outputnode, [('shift_out_file', 'shiftmap')]) ]) #### make warpfield and apply #### convertwarp0 = Node(fsl.utils.ConvertWarp( out_relwarp=True, out_file='rest_mean2fmap_unwarpfield.nii.gz'), name='convertwarp0') applywarp0 = Node(fsl.ApplyWarp(interp='spline', relwarp=True, out_file='rest_mean2fmap_unwarped.nii.gz', datatype='float'), name='applywarp0') fmap_coreg.connect([ (split, convertwarp0, [('roi_file', 'reference')]), (epi2fmap, convertwarp0, [('out_matrix_file', 'premat')]), (unwarp, convertwarp0, [('shift_out_file', 'shift_in_file')]), (inputnode, convertwarp0, [('pe_dir', 'shift_direction')]), (inputnode, applywarp0, [('epi_mean', 'in_file')]), (split, applywarp0, [('roi_file', 'ref_file')]), (convertwarp0, applywarp0, [('out_file', 'field_file')]), (convertwarp0, outputnode, [('out_file', 'unwarpfield_epi2fmap')]), (applywarp0, outputnode, [('out_file', 'unwarped_mean_epi2fmap')]) ]) #### register epi to anatomy ##### # linear registration with bbregister bbregister = Node(fs.BBRegister( contrast_type='t2', out_fsl_file='rest2anat.mat', out_reg_file='rest2anat.dat', registered_file='rest_mean2anat_highres.nii.gz', init='fsl', epi_mask=True), name='bbregister') fmap_coreg.connect([ (applywarp0, bbregister, [('out_file', 'source_file')]), (inputnode, bbregister, [('fs_subjects_dir', 'subjects_dir'), ('fs_subject_id', 'subject_id')]), (bbregister, outputnode, [('out_fsl_file', 'epi2anat_mat'), ('out_reg_file', 'epi2anat_dat'), ('registered_file', 'epi2anat'), ('min_cost_file', 'epi2anat_mincost')]), ]) # make warpfield convertwarp = Node(fsl.utils.ConvertWarp(out_relwarp=True, out_file='fullwarpfield.nii.gz'), name='convertwarp') fmap_coreg.connect([ (inputnode, convertwarp, [('anat_head', 'reference')]), (convertwarp0, convertwarp, [('out_file', 'warp1')]), (bbregister, convertwarp, [('out_fsl_file', 'postmat')]), (convertwarp, outputnode, [('out_file', 'fmap_fullwarp')]) ]) return fmap_coreg
def create_epi_t1_nonlinear_pipeline(name='epi_t1_nonlinear'): """Creates a pipeline that performs nonlinear EPI to T1 registration using the antsRegistration tool. Beforehand, the T1 image has to be processed in freesurfer and the EPI timeseries should be realigned. Example ------- >>> nipype_epi_t1_nonlin = create_epi_t1_nonlinear_pipeline('nipype_epi_t1_nonlin') >>> nipype_epi_t1_nonlin.inputs.inputnode.fs_subject_id = '123456' >>> nipype_epi_t1_nonlin.inputs.inputnode.fs_subjects_dir = '/project/data/freesurfer' >>> nipype_epi_t1_nonlin.inputs.inputnode.realigned_epi = 'mcflirt.nii.gz' >>> nipype_epi_t1_nonlin.run() Inputs:: inputnode.fs_subject_id # subject id used in freesurfer inputnode.fs_subjects_dir # path to freesurfer output inputnode.realigned_epi # realigned EPI timeseries Outputs:: outputnode.lin_epi2anat # ITK format outputnode.lin_anat2epi # ITK format outputnode.nonlin_epi2anat # ANTs specific 5D deformation field outputnode.nonlin_anat2epi # ANTs specific 5D deformation field """ nonreg = Workflow(name='epi_t1_nonlinear') # input inputnode = Node(interface=util.IdentityInterface( fields=['fs_subject_id', 'fs_subjects_dir', 'realigned_epi']), name='inputnode') # calculate the temporal mean image of the realigned timeseries tmean = Node(interface=fsl.maths.MeanImage(dimension='T', output_type='NIFTI_GZ'), name='tmean') nonreg.connect(inputnode, 'realigned_epi', tmean, 'in_file') # import brain.mgz and ribbon.mgz from freesurfer directory fs_import = Node(interface=nio.FreeSurferSource(), name='freesurfer_import') nonreg.connect(inputnode, 'fs_subjects_dir', fs_import, 'subjects_dir') nonreg.connect(inputnode, 'fs_subject_id', fs_import, 'subject_id') # convert brain.mgz to niigz mriconvert = Node(interface=fs.MRIConvert(out_type='niigz'), name='mriconvert') nonreg.connect(fs_import, 'brain', mriconvert, 'in_file') # calculate rigid transformation of mean epi to t1 with bbregister bbregister = Node(interface=fs.BBRegister(init='fsl', contrast_type='t2', out_fsl_file=True), name='bbregister') nonreg.connect(inputnode, 'fs_subjects_dir', bbregister, 'subjects_dir') nonreg.connect(inputnode, 'fs_subject_id', bbregister, 'subject_id') nonreg.connect(tmean, 'out_file', bbregister, 'source_file') # convert linear transformation to itk format compatible with ants itk = Node(interface=c3.C3dAffineTool(fsl2ras=True, itk_transform='epi2anat_affine.txt'), name='itk') nonreg.connect(tmean, 'out_file', itk, 'source_file') nonreg.connect(mriconvert, 'out_file', itk, 'reference_file') nonreg.connect(bbregister, 'out_fsl_file', itk, 'transform_file') # get aparc aseg mask # create brainmask from aparc+aseg def get_aparc_aseg(files): for name in files: if 'aparc+aseg' in name: return name aparc_aseg_mask = Node(fs.Binarize(min=0.1, dilate=10, erode=7, out_type='nii.gz', binary_file='aparc_aseg_mask.nii.gz'), name='aparc_aseg_mask') # fill holes in mask fillholes = Node(fsl.maths.MathsCommand(args='-fillh'), name='fillholes') nonreg.connect([(fs_import, aparc_aseg_mask, [ (('aparc_aseg', get_aparc_aseg), 'in_file') ]), (aparc_aseg_mask, fillholes, [('binary_file', 'in_file')])]) #create bounding box mask and rigidly transform into anatomical (fs) space fov = Node(interface=fs.model.Binarize(min=0.0, out_type='nii.gz'), name='fov') nonreg.connect(tmean, 'out_file', fov, 'in_file') fov_trans = Node(interface=ants.resampling.ApplyTransforms( dimension=3, interpolation='NearestNeighbor'), name='fov_trans') nonreg.connect(itk, ('itk_transform', filename_to_list), fov_trans, 'transforms') nonreg.connect(fov, 'binary_file', fov_trans, 'input_image') nonreg.connect(fillholes, 'out_file', fov_trans, 'reference_image') #nonreg.connect(ribbon, 'binary_file', fov_trans, 'reference_image') # intersect both masks intersect = Node(interface=fsl.maths.BinaryMaths(operation='mul'), name='intersect') nonreg.connect(fillholes, 'out_file', intersect, 'in_file') #nonreg.connect(ribbon, 'binary_file', intersect, 'in_file') nonreg.connect(fov_trans, 'output_image', intersect, 'operand_file') # inversly transform mask and mask original epi mask_trans = Node(interface=ants.resampling.ApplyTransforms( dimension=3, interpolation='NearestNeighbor', invert_transform_flags=[True]), name='mask_trans') nonreg.connect(itk, ('itk_transform', filename_to_list), mask_trans, 'transforms') nonreg.connect(intersect, 'out_file', mask_trans, 'input_image') nonreg.connect(tmean, 'out_file', mask_trans, 'reference_image') maskepi = Node(interface=fs.utils.ApplyMask(), name='maskepi') nonreg.connect(mask_trans, 'output_image', maskepi, 'mask_file') nonreg.connect(tmean, 'out_file', maskepi, 'in_file') # mask anatomical image (brain) maskanat = Node(interface=fs.utils.ApplyMask(), name='maskanat') nonreg.connect(intersect, 'out_file', maskanat, 'mask_file') nonreg.connect(mriconvert, 'out_file', maskanat, 'in_file') # invert masked anatomical image anat_min_max = Node(interface=fsl.utils.ImageStats(op_string='-R'), name='anat_min_max') epi_min_max = Node(interface=fsl.utils.ImageStats(op_string='-r'), name='epi_min_max') nonreg.connect(maskanat, 'out_file', anat_min_max, 'in_file') nonreg.connect(tmean, 'out_file', epi_min_max, 'in_file') def calc_inversion(anat_min_max, epi_min_max): mul = -(epi_min_max[1] - epi_min_max[0]) / (anat_min_max[1] - anat_min_max[0]) add = abs(anat_min_max[1] * mul) + epi_min_max[0] return mul, add calcinv = Node(interface=Function( input_names=['anat_min_max', 'epi_min_max'], output_names=['mul', 'add'], function=calc_inversion), name='calcinv') nonreg.connect(anat_min_max, 'out_stat', calcinv, 'anat_min_max') nonreg.connect(epi_min_max, 'out_stat', calcinv, 'epi_min_max') mulinv = Node(interface=fsl.maths.BinaryMaths(operation='mul'), name='mulinv') addinv = Node(interface=fsl.maths.BinaryMaths(operation='add'), name='addinv') nonreg.connect(maskanat, 'out_file', mulinv, 'in_file') nonreg.connect(calcinv, 'mul', mulinv, 'operand_value') nonreg.connect(mulinv, 'out_file', addinv, 'in_file') nonreg.connect(calcinv, 'add', addinv, 'operand_value') # nonlinear transformation of masked anat to masked epi with ants antsreg = Node(interface=ants.registration.Registration( dimension=3, invert_initial_moving_transform=True, metric=['CC'], metric_weight=[1.0], radius_or_number_of_bins=[4], sampling_strategy=['None'], transforms=['SyN'], args='-g .1x1x.1', transform_parameters=[(0.10, 3, 0)], number_of_iterations=[[10, 5]], convergence_threshold=[1e-06], convergence_window_size=[10], shrink_factors=[[2, 1]], smoothing_sigmas=[[1, 0.5]], sigma_units=['vox'], use_estimate_learning_rate_once=[True], use_histogram_matching=[True], collapse_output_transforms=True, output_inverse_warped_image=True, output_warped_image=True), name='antsreg') nonreg.connect(itk, 'itk_transform', antsreg, 'initial_moving_transform') nonreg.connect(maskepi, 'out_file', antsreg, 'fixed_image') nonreg.connect(addinv, 'out_file', antsreg, 'moving_image') # output def second_element(file_list): return file_list[1] def first_element(file_list): return file_list[0] outputnode = Node(interface=util.IdentityInterface(fields=[ 'lin_epi2anat', 'lin_anat2epi', 'nonlin_epi2anat', 'nonlin_anat2epi' ]), name='outputnode') nonreg.connect(itk, 'itk_transform', outputnode, 'lin_epi2anat') nonreg.connect(antsreg, ('forward_transforms', first_element), outputnode, 'lin_anat2epi') nonreg.connect(antsreg, ('forward_transforms', second_element), outputnode, 'nonlin_anat2epi') nonreg.connect(antsreg, ('reverse_transforms', second_element), outputnode, 'nonlin_epi2anat') return nonreg
def create_fmap_coreg_pipeline(name='fmap_coreg'): # fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # initiate workflow fmap_coreg = Workflow(name='fmap_coreg') # inputnode inputnode = Node(util.IdentityInterface(fields=[ 'epi_mean', 'ap', 'pa', 'anat_head', 'anat_brain', 'fs_subject_id', 'fs_subjects_dir', 'echo_space', 'pe_dir' ]), name='inputnode') # outputnode outputnode = Node(util.IdentityInterface(fields=[ 'fmap', 'shiftmap', 'unwarpfield_epi2fmap', 'unwarped_mean_epi2fmap', 'epi2anat_mat', 'epi2anat_dat', 'epi2anat_mincost', 'epi2anat', 'epi2fmap', 'fmap_fullwarp' ]), name='outputnode') #### merge epi ap and pa merge_appa = Node(fsl.Merge(), name='merge_appa') merge_appa.inputs.dimension = 't' #use mean file of ap-pa acquisitions as "Mag"-image from fieldmap mean_appa = Node(fsl.MeanImage()) #### use topup --> creates fieldmap topup_prep = Node(fsl.TOPUP(), name='topup_prep') topup_prep.inputs.encoding_file = '/home/raid1/fbeyer/Documents/Scripts/rs_preprocessing/RSV/topup-version/topup_file.txt' #multiply topup result to convert to rad/s convertHz_rad = Node(fsl.maths.MathsCommand(args='-mul 6.28'), name='convertHz_rad') fmap_coreg.connect([(inputnode, merge_appa, [('ap', 'in_files')]), (inputnode, merge_appa, [('pa', 'in_files')]), (merge_appa, mean_appa, [('merged_file', 'in_file')]), (merge_appa, topup_prep, [ ('merged_file', 'in_files') ])(topup_prep, convertHz_rad, [('out_field', 'in_file')])]) #only needed when using PrepareFieldmap() command # split first magnitude image from mag input #split = Node(fsl.ExtractROI(t_min=0, t_size=1), name='split') #fmap_coreg.connect(inputnode, 'mag', split, 'in_file') # strip magnitude image and erode even further #bet = Node(fsl.BET(frac=0.5, mask=True), name='bet') #fmap_coreg.connect(split, 'roi_file', bet, 'in_file') #erode = Node(fsl.maths.ErodeImage(kernel_shape='sphere', kernel_size=3, args=''), name='erode') #fmap_coreg.connect(bet, 'out_file', erode, 'in_file') # prepare fieldmap #prep_fmap = Node(fsl.epi.PrepareFieldmap(), name='prep_fmap') #fmap_coreg.connect([(erode, prep_fmap, [('out_file', 'in_magnitude')]), # (inputnode, prep_fmap, [('phase', 'in_phase'), ('te_diff', 'delta_TE')]), # (prep_fmap, outputnode, [('out_fieldmap', 'fmap')]) # ]) #### unmask fieldmap #### fmap_mask = Node(fsl.maths.MathsCommand(args='-abs -bin'), name='fmap_mask') unmask = Node(fsl.FUGUE(save_unmasked_fmap=True), name='unmask') fmap_coreg.connect([(convertHz_rad, fmap_mask, [('out_file', 'in_file')]), (fmap_mask, unmask, [('out_file', 'mask_file')]), (convertHz_rad, unmask, [('out_file', 'fmap_in_file') ]), (inputnode, unmask, [('pe_dir', 'unwarp_direction')])]) #### register epi to fieldmap #### epi2fmap = Node(fsl.FLIRT(dof=6, out_file='rest_mean2fmap.nii.gz', interp='spline'), name='epi2fmap') fmap_coreg.connect([(inputnode, epi2fmap, [('epi_mean', 'in_file')]), (mean_appa, epi2fmap, [('out_file', 'reference')]), (epi2fmap, outputnode, [('out_file', 'epi2fmap')])]) #### unwarp epi with fieldmap #### unwarp = Node(fsl.FUGUE(save_shift=True), name='unwarp') fmap_coreg.connect([(epi2fmap, unwarp, [('out_file', 'in_file')]), (unmask, unwarp, [('fmap_out_file', 'fmap_in_file')]), (fmap_mask, unwarp, [('out_file', 'mask_file')]), (inputnode, unwarp, [('echo_space', 'dwell_time'), ('pe_dir', 'unwarp_direction')]), (unwarp, outputnode, [('shift_out_file', 'shiftmap')]) ]) #### make warpfield and apply #### convertwarp0 = Node(fsl.utils.ConvertWarp( out_relwarp=True, out_file='rest_mean2fmap_unwarpfield.nii.gz'), name='convertwarp0') applywarp0 = Node(fsl.ApplyWarp(interp='spline', relwarp=True, out_file='rest_mean2fmap_unwarped.nii.gz', datatype='float'), name='applywarp0') fmap_coreg.connect([ (mean_appa, convertwarp0, [('roi_file', 'reference')]), (epi2fmap, convertwarp0, [('out_matrix_file', 'premat')]), (unwarp, convertwarp0, [('shift_out_file', 'shift_in_file')]), (inputnode, convertwarp0, [('pe_dir', 'shift_direction')]), (inputnode, applywarp0, [('epi_mean', 'in_file')]), (mean_appa, applywarp0, [('roi_file', 'ref_file')]), (convertwarp0, applywarp0, [('out_file', 'field_file')]), (convertwarp0, outputnode, [('out_file', 'unwarpfield_epi2fmap')]), (applywarp0, outputnode, [('out_file', 'unwarped_mean_epi2fmap')]) ]) #### register epi to anatomy ##### # linear registration with bbregister bbregister = Node(fs.BBRegister( contrast_type='t2', out_fsl_file='rest2anat.mat', out_reg_file='rest2anat.dat', registered_file='rest_mean2anat_highres.nii.gz', init='fsl', epi_mask=True), name='bbregister') fmap_coreg.connect([ (applywarp0, bbregister, [('out_file', 'source_file')]), (inputnode, bbregister, [('fs_subjects_dir', 'subjects_dir'), ('fs_subject_id', 'subject_id')]), (bbregister, outputnode, [('out_fsl_file', 'epi2anat_mat'), ('out_reg_file', 'epi2anat_dat'), ('registered_file', 'epi2anat'), ('min_cost_file', 'epi2anat_mincost')]), ]) # make warpfield convertwarp = Node(fsl.utils.ConvertWarp(out_relwarp=True, out_file='fullwarpfield.nii.gz'), name='convertwarp') fmap_coreg.connect([ (inputnode, convertwarp, [('anat_head', 'reference')]), (convertwarp0, convertwarp, [('out_file', 'warp1')]), (bbregister, convertwarp, [('out_fsl_file', 'postmat')]), (convertwarp, outputnode, [('out_file', 'fmap_fullwarp')]) ]) return fmap_coreg
't_min') preproc_wf.connect(extractref, 'roi_file', outputspec, 'reference') # Motion correction with Nipy algorithm motion_correct = pe.Node(nipy.SpaceTimeRealigner(), name='motion_correct') motion_correct.plugin_args = {'bsub_args': '-n 12'} motion_correct.plugin_args = {'bsub_args': '-R "span[hosts=1]"'} preproc_wf.connect(datasource, 'mri_files', motion_correct, 'in_file') preproc_wf.connect(motion_correct, 'par_file', outputspec, 'motion_parameters') preproc_wf.connect(motion_correct, 'out_file', outputspec, 'motion_corrected_files') # Calculate the transformation matrix from EPI space to FreeSurfer space # using the BBRegister command coregister = pe.Node(fs.BBRegister(subjects_dir=subjects_dir, contrast_type='t2', init='fsl', out_fsl_file=True), name='coregister') preproc_wf.connect(subj_iterable, 'subject_id', coregister, 'subject_id') preproc_wf.connect(motion_correct, ('out_file', pickfirst), coregister, 'source_file') preproc_wf.connect(coregister, 'out_reg_file', outputspec, 'reg_file') preproc_wf.connect(coregister, 'out_fsl_file', outputspec, 'fsl_reg_file') preproc_wf.connect(coregister, 'min_cost_file', outputspec, 'reg_cost') # Register a source file to fs space fssource = pe.Node(nio.FreeSurferSource(subjects_dir=subjects_dir), name='fssource') preproc_wf.connect(subj_iterable, 'subject_id', fssource, 'subject_id') # Extract aparc+aseg brain mask and binarize
def create_bbregister_workflow(name="bbregister", contrast_type="t2"): # Define the workflow inputs inputnode = pe.Node( util.IdentityInterface(fields=["subject_id", "source_file"]), name="inputs") # Estimate the registration to Freesurfer conformed space func2anat = pe.MapNode(fs.BBRegister(contrast_type=contrast_type, init="fsl", epi_mask=True, registered_file=True, out_fsl_file=True), iterfield=["source_file"], name="func2anat") # Set up a node to grab the target from the subjects directory fssource = pe.Node(io.FreeSurferSource(subjects_dir=fs.Info.subjectsdir()), name="fssource") # Always overwrite the grab; shouldn't cascade unless the underlying image changes fssource.overwrite = True # Convert the target to nifti convert = pe.Node(fs.MRIConvert(out_type="niigz"), name="convertbrain") # Swap dimensions so stuff looks nice in the report flipbrain = pe.Node(fsl.SwapDimensions(new_dims=("RL", "PA", "IS")), name="flipbrain") flipfunc = pe.MapNode(fsl.SwapDimensions(new_dims=("RL", "PA", "IS")), iterfield=["in_file"], name="flipfunc") # Slice up the registration func2anatpng = pe.MapNode(fsl.Slicer(middle_slices=True, show_orientation=False, scaling=.6, label_slices=False), iterfield=["in_file"], name="func2anatpng") # Rename some files pngname = pe.MapNode(util.Rename(format_string="func2anat.png"), iterfield=["in_file"], name="pngname") costname = pe.MapNode(util.Rename(format_string="func2anat_cost.dat"), iterfield=["in_file"], name="costname") tkregname = pe.MapNode(util.Rename(format_string="func2anat_tkreg.dat"), iterfield=["in_file"], name="tkregname") flirtname = pe.MapNode(util.Rename(format_string="func2anat_flirt.mat"), iterfield=["in_file"], name="flirtname") # Merge the slicer png and cost file into a report list report = pe.Node(util.Merge(2, axis="hstack"), name="report") # Define the workflow outputs outputnode = pe.Node( util.IdentityInterface(fields=["tkreg_mat", "flirt_mat", "report"]), name="outputs") bbregister = pe.Workflow(name=name) # Connect the registration bbregister.connect([ (inputnode, func2anat, [("subject_id", "subject_id"), ("source_file", "source_file")]), (inputnode, fssource, [("subject_id", "subject_id")]), (func2anat, flipfunc, [("registered_file", "in_file")]), (flipfunc, func2anatpng, [("out_file", "in_file")]), (fssource, convert, [("brain", "in_file")]), (convert, flipbrain, [("out_file", "in_file")]), (flipbrain, func2anatpng, [("out_file", "image_edges")]), (func2anatpng, pngname, [("out_file", "in_file")]), (func2anat, tkregname, [("out_reg_file", "in_file")]), (func2anat, flirtname, [("out_fsl_file", "in_file")]), (func2anat, costname, [("min_cost_file", "in_file")]), (costname, report, [("out_file", "in1")]), (pngname, report, [("out_file", "in2")]), (tkregname, outputnode, [("out_file", "tkreg_mat")]), (flirtname, outputnode, [("out_file", "flirt_mat")]), (report, outputnode, [("out", "report")]), ]) return bbregister
def create_surface_registration(wf_name='surface_registration'): """ Workflow to generate surface from anatomical data and register the structural data to FreeSurfer anatomical and assign it to a surface vertex. Parameters ---------- wf_name : string name of the workflow Returns ------- wflow : workflow object workflow object Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/timeseries/timeseries_analysis.py>`_ Workflow Inputs:: inputspec.rest : string (nifti file) path to input functional data inputspec.brain : string (nifti file) path to skull stripped anatomical image inputspec.recon_subjects : string path to subjects directory inputspec.subject_id : string subject id Workflow Outputs:: outputspec.reconall_subjects_dir : string freesurfer subjects directory outputspec.reconall_subjects_id : string subject id for which anatomical data is taken outputspec.out_reg_file : string path to bbregister output registration file outputspec.lh_surface_file : string (mgz file) path to left hemisphere cortical surface file outputspec.rh_surface_file : string (mgz file) path to right hemisphere cortical surface file Order of commands: - Generate surfaces and rois of structural data from T1 anatomical Image using FreeSurfer's reconall . For details see `ReconAll <https://surfer.nmr.mgh.harvard.edu/fswiki/recon-all>`_:: recon-all -all -subjid 0010001 -sd working_dir/SurfaceRegistration/anat_reconall - Register input volume to the FreeSurfer anatomical using FreeSurfer's bbregister. The input is the output of the recon-all command. For details see `BBRegister <http://surfer.nmr.mgh.harvard.edu/fswiki/bbregister>`_:: bbregister --t2 --init -fsl --reg structural_bbreg_me.dat --mov structural.nii --s 0010001 - Assign values from a volume to each surface vertex using FreeSurfer's mri_vol2surf . For details see `mri_vol2surf <http://surfer.nmr.mgh.harvard.edu/fswiki/mri_vol2surf>`_:: For left hemisphere mri_vol2surf --mov structural.nii --reg structural_bbreg_me.dat --interp trilin --projfrac 0.5 --hemi lh --o surface_file.nii.gz For right hemisphere mri_vol2surf --mov structural.nii --reg structural_bbreg_me.dat --interp trilin --projfrac 0.5 --hemi rh --o surface_file.nii.gz High Level Workflow Graph: .. image:: ../images/surface_registration.dot.png :width: 1000 Detailed Workflow Graph: .. image:: ../images/surface_registration_detailed.dot.png :width: 1000 Example ------- >>> import CPAC.timeseries.timeseries_analysis as t >>> wf = t.create_surface_registration() >>> wf.inputs.inputspec.rest = '/home/data/sub001/rest.nii.gz' >>> wf.inputs.inputspec.brain = '/home/data/sub001/anat.nii.gz' >>> wf.inputs.inputspec.recon_subjects = '/home/data/working_dir/SurfaceRegistration/anat_reconall' >>> wf.inputs.inputspec.subject_id = 'sub001' >>> wf.base_dir = './' >>> wf.run() """ wflow = pe.Workflow(name=wf_name) inputNode = pe.Node(util.IdentityInterface(fields=['recon_subjects', 'brain', 'subject_id', 'rest']), name='inputspec') outputNode = pe.Node(util.IdentityInterface(fields=['reconall_subjects_dir', 'reconall_subjects_id', 'out_reg_file', 'lh_surface_file', 'rh_surface_file']), name='outputspec') reconall = pe.Node(interface=fs.ReconAll(), name="reconall") reconall.inputs.directive = 'all' wflow.connect(inputNode, 'brain', reconall, 'T1_files') wflow.connect(inputNode, 'subject_id', reconall, 'subject_id') wflow.connect(inputNode, 'recon_subjects', reconall, 'subjects_dir') wflow.connect(reconall, 'subjects_dir', outputNode, 'reconall_subjects_dir') wflow.connect(reconall, 'subject_id', outputNode, 'reconall_subjects_id') bbregister = pe.Node(interface=fs.BBRegister(init='fsl', contrast_type='t2', registered_file=True, out_fsl_file=True), name='bbregister') wflow.connect(inputNode, 'rest', bbregister, 'source_file') wflow.connect(reconall, 'subjects_dir', bbregister, 'subjects_dir') wflow.connect(reconall, 'subject_id', bbregister, 'subject_id') wflow.connect(bbregister, 'out_reg_file', outputNode, 'out_reg_file') sample_to_surface_lh = pe.Node(interface=fs.SampleToSurface(hemi="lh"), name='sample_to_surface_lh') sample_to_surface_lh.inputs.no_reshape = True sample_to_surface_lh.inputs.interp_method = 'trilinear' sample_to_surface_lh.inputs.sampling_method = "point" sample_to_surface_lh.inputs.sampling_range = 0.5 sample_to_surface_lh.inputs.sampling_units = "frac" wflow.connect(bbregister, 'out_reg_file', sample_to_surface_lh, 'reg_file') wflow.connect(inputNode, 'rest', sample_to_surface_lh, 'source_file') wflow.connect(sample_to_surface_lh, 'out_file', outputNode, 'lh_surface_file') sample_to_surface_rh = pe.Node(interface=fs.SampleToSurface(hemi="rh"), name='sample_to_surface_rh') sample_to_surface_rh.inputs.no_reshape = True sample_to_surface_rh.inputs.interp_method = 'trilinear' sample_to_surface_rh.inputs.sampling_method = "point" sample_to_surface_rh.inputs.sampling_range = 0.5 sample_to_surface_rh.inputs.sampling_units = "frac" wflow.connect(bbregister, 'out_reg_file', sample_to_surface_rh, 'reg_file') wflow.connect(inputNode, 'rest', sample_to_surface_rh, 'source_file') wflow.connect(sample_to_surface_rh, 'out_file', outputNode, 'rh_surface_file') return wflow
def get_dmriprep_pe_workflow(): """Return the dmriprep (phase encoded) nipype workflow Parameters ---------- Returns ------- wf : nipype.pipeline.engine.Workflow Nipype dmriprep workflow Notes ----- This assumes that there are scans with phase-encode directions AP/PA for topup. """ import nipype.interfaces.freesurfer as fs import nipype.interfaces.fsl as fsl import nipype.interfaces.io as nio import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe from nipype.interfaces.dipy import DTI from nipype.workflows.dmri.fsl.artifacts import all_fsl_pipeline inputspec = pe.Node(niu.IdentityInterface(fields=[ 'subject_id', 'dwi_file', 'dwi_file_ap', 'dwi_file_pa', 'bvec_file', 'bval_file', 'subjects_dir', 'out_dir', 'eddy_niter', 'slice_outlier_threshold' ]), name="inputspec") # AK: watch out, other datasets might be encoded LR epi_ap = {'echospacing': 66.5e-3, 'enc_dir': 'y-'} epi_pa = {'echospacing': 66.5e-3, 'enc_dir': 'y'} prep = all_fsl_pipeline(epi_params=epi_ap, altepi_params=epi_pa) # initialize an overall workflow wf = pe.Workflow(name="dmriprep") wf.connect(inputspec, 'dwi_file', prep, 'inputnode.in_file') wf.connect(inputspec, 'bvec_file', prep, 'inputnode.in_bvec') wf.connect(inputspec, 'bval_file', prep, 'inputnode.in_bval') wf.connect(inputspec, 'eddy_niter', prep, 'fsl_eddy.niter') eddy = prep.get_node('fsl_eddy') eddy.inputs.repol = True eddy.inputs.cnr_maps = True eddy.inputs.residuals = True import multiprocessing eddy.inputs.num_threads = multiprocessing.cpu_count() topup = prep.get_node('peb_correction.topup') topup.inputs.checksize = True applytopup = prep.get_node('peb_correction.unwarp') applytopup.inputs.checksize = True eddy.inputs.checksize = True eddy_quad = pe.Node(fsl.EddyQuad(verbose=True, checksize=True), name="eddy_quad") get_path = lambda x: x.split('.nii.gz')[0].split('_fix')[0] wf.connect(prep, ('fsl_eddy.out_corrected', get_path), eddy_quad, "base_name") wf.connect(inputspec, 'bval_file', eddy_quad, 'bval_file') wf.connect(prep, 'Rotate_Bvec.out_file', eddy_quad, 'bvec_file') wf.connect(prep, 'peb_correction.topup.out_field', eddy_quad, 'field') wf.connect(prep, 'gen_index.out_file', eddy_quad, 'idx_file') wf.connect(prep, 'peb_correction.topup.out_enc_file', eddy_quad, 'param_file') # need a mask file for eddy_quad. lets get it from the B0. def get_b0_mask_fn(b0_file): import nibabel as nib from nipype.utils.filemanip import fname_presuffix from dipy.segment.mask import median_otsu import os mask_file = fname_presuffix(b0_file, suffix="_mask", newpath=os.path.abspath('.')) img = nib.load(b0_file) data, aff = img.get_data(), img.affine _, mask = median_otsu(data, 2, 1) nib.Nifti1Image(mask.astype(float), aff).to_filename(mask_file) return mask_file def id_outliers_fn(outlier_report, threshold, dwi_file): """Get list of scans that exceed threshold for number of outliers Parameters ---------- outlier_report: string Path to the fsl_eddy outlier report threshold: int or float If threshold is an int, it is treated as number of allowed outlier slices. If threshold is a float between 0 and 1 (exclusive), it is treated the fraction of allowed outlier slices before we drop the whole volume. dwi_file: string Path to nii dwi file to determine total number of slices Returns ------- drop_scans: numpy.ndarray List of scan indices to drop """ import nibabel as nib import numpy as np import os.path as op import parse with open(op.abspath(outlier_report), 'r') as fp: lines = fp.readlines() p = parse.compile( "Slice {slice:d} in scan {scan:d} is an outlier with " "mean {mean_sd:f} standard deviations off, and mean " "squared {mean_sq_sd:f} standard deviations off.") outliers = [p.parse(l).named for l in lines] scans = {d['scan'] for d in outliers} def num_outliers(scan, outliers): return len([d for d in outliers if d['scan'] == scan]) if 0 < threshold < 1: img = nib.load(dwi_file) try: threshold *= img.header.get_n_slices() except nib.spatialimages.HeaderDataError: print( 'WARNING. We are not sure which dimension has the ' 'slices in this image. So we are using the 3rd dim.', img.shape) threshold *= img.shape[2] drop_scans = np.array( [s for s in scans if num_outliers(s, outliers) > threshold]) outpath = op.abspath("dropped_scans.txt") np.savetxt(outpath, drop_scans, fmt="%d") return drop_scans, outpath id_outliers_node = pe.Node(niu.Function( input_names=["outlier_report", "threshold", "dwi_file"], output_names=["drop_scans", "outpath"], function=id_outliers_fn), name="id_outliers_node") wf.connect(inputspec, 'dwi_file', id_outliers_node, 'dwi_file') wf.connect(inputspec, 'slice_outlier_threshold', id_outliers_node, 'threshold') wf.connect(prep, "fsl_eddy.out_outlier_report", id_outliers_node, "outlier_report") list_merge = pe.Node(niu.Merge(numinputs=2), name="list_merge") wf.connect(inputspec, 'dwi_file_ap', list_merge, 'in1') wf.connect(inputspec, 'dwi_file_pa', list_merge, 'in2') merge = pe.Node(fsl.Merge(dimension='t'), name="mergeAPPA") wf.connect(merge, 'merged_file', prep, 'inputnode.alt_file') wf.connect(list_merge, 'out', merge, 'in_files') fslroi = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="fslroi") wf.connect(prep, "outputnode.out_file", fslroi, "in_file") b0mask_node = pe.Node(niu.Function(input_names=['b0_file'], output_names=['mask_file'], function=get_b0_mask_fn), name="getB0Mask") wf.connect(fslroi, 'roi_file', b0mask_node, 'b0_file') wf.connect(b0mask_node, 'mask_file', eddy_quad, 'mask_file') bbreg = pe.Node( fs.BBRegister( contrast_type="t2", init="coreg", out_fsl_file=True, # subjects_dir=subjects_dir, epi_mask=True), name="bbreg") bbreg.inputs.subject_id = 'freesurfer' # bids_sub_name wf.connect(fslroi, "roi_file", bbreg, "source_file") wf.connect(inputspec, 'subjects_dir', bbreg, 'subjects_dir') def drop_outliers_fn(in_file, in_bval, in_bvec, drop_scans): """Drop outlier volumes from dwi file Parameters ---------- in_file: string Path to nii dwi file to drop outlier volumes from in_bval: string Path to bval file to drop outlier volumes from in_bvec: string Path to bvec file to drop outlier volumes from drop_scans: numpy.ndarray List of scan indices to drop Returns ------- out_file: string Path to "thinned" output dwi file out_bval: string Path to "thinned" output bval file out_bvec: string Path to "thinned" output bvec file """ import nibabel as nib import numpy as np import os.path as op from nipype.utils.filemanip import fname_presuffix img = nib.load(op.abspath(in_file)) img_data = img.get_data() img_data_thinned = np.delete(img_data, drop_scans, axis=3) if isinstance(img, nib.nifti1.Nifti1Image): img_thinned = nib.Nifti1Image(img_data_thinned.astype(np.float64), img.affine, header=img.header) elif isinstance(img, nib.nifti2.Nifti2Image): img_thinned = nib.Nifti2Image(img_data_thinned.astype(np.float64), img.affine, header=img.header) else: raise TypeError("in_file does not contain Nifti image datatype.") out_file = fname_presuffix(in_file, suffix="_thinned", newpath=op.abspath('.')) nib.save(img_thinned, op.abspath(out_file)) bval = np.loadtxt(in_bval) bval_thinned = np.delete(bval, drop_scans, axis=0) out_bval = fname_presuffix(in_bval, suffix="_thinned", newpath=op.abspath('.')) np.savetxt(out_bval, bval_thinned) bvec = np.loadtxt(in_bvec) bvec_thinned = np.delete(bvec, drop_scans, axis=1) out_bvec = fname_presuffix(in_bvec, suffix="_thinned", newpath=op.abspath('.')) np.savetxt(out_bvec, bvec_thinned) return out_file, out_bval, out_bvec drop_outliers_node = pe.Node(niu.Function( input_names=["in_file", "in_bval", "in_bvec", "drop_scans"], output_names=["out_file", "out_bval", "out_bvec"], function=drop_outliers_fn), name="drop_outliers_node") # Align the output of drop_outliers_node & also the eddy corrected version to the anatomical space # without resampling. and then for aparc+aseg & the mask, resample to the larger voxel size of the B0 image from # fslroi. Also we need to apply the transformation to both bvecs (dropped & eddied) and I think we can just load # the affine from bbreg (sio.loadmat) and np.dot(coord, aff) for each coord in bvec def get_orig(subjects_dir, sub='freesurfer'): import os.path as op return op.join(subjects_dir, sub, "mri", "orig.mgz") def get_aparc_aseg(subjects_dir, sub='freesurfer'): import os.path as op return op.join(subjects_dir, sub, "mri", "aparc+aseg.mgz") # transform the dropped volume version to anat space w/ out resampling voltransform = pe.Node(fs.ApplyVolTransform(no_resample=True), iterfield=['source_file', 'reg_file'], name='transform') wf.connect(inputspec, 'subjects_dir', voltransform, 'subjects_dir') wf.connect(inputspec, ('subjects_dir', get_aparc_aseg), voltransform, 'target_file') wf.connect(prep, "outputnode.out_file", voltransform, "source_file") wf.connect(bbreg, "out_reg_file", voltransform, "reg_file") def apply_transform_to_bvecs_fn(bvec_file, reg_mat_file): import numpy as np import nipype.utils.filemanip as fm import os aff = np.loadtxt(reg_mat_file) bvecs = np.loadtxt(bvec_file) bvec_trans = [] for bvec in bvecs.T: coord = np.hstack((bvec, [1])) coord_trans = np.dot(coord, aff)[:-1] bvec_trans.append(coord_trans) out_bvec = fm.fname_presuffix(bvec_file, suffix="anat_space", newpath=os.path.abspath('.')) np.savetxt(out_bvec, np.asarray(bvec_trans).T) return out_bvec apply_transform_to_bvecs_node = pe.Node(niu.Function( input_names=['bvec_file', 'reg_mat_file'], output_names=['out_bvec'], function=apply_transform_to_bvecs_fn), name="applyTransformToBvecs") wf.connect(bbreg, 'out_fsl_file', apply_transform_to_bvecs_node, 'reg_mat_file') wf.connect(prep, 'outputnode.out_bvec', apply_transform_to_bvecs_node, 'bvec_file') # ok cool, now lets do the thresholding. wf.connect(id_outliers_node, "drop_scans", drop_outliers_node, "drop_scans") wf.connect(voltransform, "transformed_file", drop_outliers_node, "in_file") wf.connect(inputspec, 'bval_file', drop_outliers_node, 'in_bval') wf.connect(apply_transform_to_bvecs_node, "out_bvec", drop_outliers_node, "in_bvec") # lets compute the tensor on both the dropped volume scan # and also the original, eddy corrected one. get_tensor = pe.Node(DTI(), name="dipy_tensor") wf.connect(drop_outliers_node, "out_file", get_tensor, "in_file") wf.connect(drop_outliers_node, "out_bval", get_tensor, "in_bval") wf.connect(drop_outliers_node, "out_bvec", get_tensor, "in_bvec") get_tensor_eddy = get_tensor.clone('dipy_tensor_eddy') wf.connect(voltransform, 'transformed_file', get_tensor_eddy, "in_file") wf.connect(apply_transform_to_bvecs_node, 'out_bvec', get_tensor_eddy, "in_bvec") wf.connect(inputspec, 'bval_file', get_tensor_eddy, 'in_bval') # AK: What is this, some vestigal node from a previous workflow? # I'm not sure why the tensor gets scaled. but i guess lets scale it for # both the dropped & eddy corrected versions. scale_tensor = pe.Node(name='scale_tensor', interface=fsl.BinaryMaths()) scale_tensor.inputs.operation = 'mul' scale_tensor.inputs.operand_value = 1000 wf.connect(get_tensor, 'out_file', scale_tensor, 'in_file') scale_tensor_eddy = scale_tensor.clone('scale_tensor_eddy') wf.connect(get_tensor_eddy, 'out_file', scale_tensor_eddy, 'in_file') # OK now that anatomical stuff (segmentation & mask) # We'll need: # 1. the B0 image in anat space (fslroi the 'transformed file' of voltransform # 2. the aparc aseg resampled-like the B0 image (mri_convert) # 3. the resample aparc_aseg binarized to be the mask image. def binarize_aparc(aparc_aseg): import nibabel as nib from nipype.utils.filemanip import fname_presuffix import os.path as op img = nib.load(aparc_aseg) data, aff = img.get_data(), img.affine outfile = fname_presuffix(aparc_aseg, suffix="bin.nii.gz", newpath=op.abspath("."), use_ext=False) nib.Nifti1Image((data > 0).astype(float), aff).to_filename(outfile) return outfile create_mask = pe.Node(niu.Function(input_names=["aparc_aseg"], output_names=["outfile"], function=binarize_aparc), name="bin_aparc") get_b0_anat = fslroi.clone('get_b0_anat') wf.connect(voltransform, 'transformed_file', get_b0_anat, 'in_file') # reslice the anat-space aparc+aseg to the DWI resolution reslice_to_dwi = pe.Node(fs.MRIConvert(resample_type="nearest"), name="reslice_to_dwi") wf.connect(get_b0_anat, 'roi_file', reslice_to_dwi, 'reslice_like') wf.connect(inputspec, ('subjects_dir', get_aparc_aseg), reslice_to_dwi, 'in_file') # also reslice the orig i suppose reslice_orig_to_dwi = reslice_to_dwi.clone('resliceT1wToDwi') wf.connect(inputspec, ('subjects_dir', get_orig), reslice_orig_to_dwi, 'in_file') # reslice_orig_to_dwi.inputs.in_file = get_orig(subjects_dir, 'freesurfer') reslice_orig_to_dwi.inputs.out_type = 'niigz' wf.connect(get_b0_anat, 'roi_file', reslice_orig_to_dwi, 'reslice_like') # we assume the freesurfer is the output of BIDS # so the freesurfer output is in /path/to/derivatives/sub-whatever/freesurfer # which means the subject_dir is /path/to/derivatives/sub-whatever # reslice_to_dwi.inputs.in_file = get_aparc_aseg(subjects_dir, 'freesurfer') # now we have a nice aparc+aseg still in anat space but resliced like the dwi file # lets create a mask file from it. wf.connect(reslice_to_dwi, 'out_file', create_mask, 'aparc_aseg') # save all the things datasink = pe.Node(nio.DataSink(), name="sinker") wf.connect(inputspec, 'out_dir', datasink, 'base_directory') wf.connect(inputspec, 'subject_id', datasink, 'container') wf.connect(drop_outliers_node, "out_file", datasink, "dmriprep.dwi.@thinned") wf.connect(drop_outliers_node, "out_bval", datasink, "dmriprep.dwi.@bval_thinned") wf.connect(drop_outliers_node, "out_bvec", datasink, "dmriprep.dwi.@bvec_thinned") # eddy corrected files wf.connect(prep, "outputnode.out_file", datasink, "dmriprep.dwi_eddy.@corrected") wf.connect(prep, "outputnode.out_bvec", datasink, "dmriprep.dwi_eddy.@rotated") wf.connect(inputspec, 'bval_file', datasink, 'dmriprep.dwi_eddy.@bval') # all the eddy stuff except the corrected files wf.connect(prep, "fsl_eddy.out_movement_rms", datasink, "dmriprep.qc.@eddyparamsrms") wf.connect(prep, "fsl_eddy.out_outlier_report", datasink, "dmriprep.qc.@eddyparamsreport") wf.connect(prep, "fsl_eddy.out_restricted_movement_rms", datasink, "dmriprep.qc.@eddyparamsrestrictrms") wf.connect(prep, "fsl_eddy.out_shell_alignment_parameters", datasink, "dmriprep.qc.@eddyparamsshellalign") wf.connect(prep, "fsl_eddy.out_parameter", datasink, "dmriprep.qc.@eddyparams") wf.connect(prep, "fsl_eddy.out_cnr_maps", datasink, "dmriprep.qc.@eddycndr") wf.connect(prep, "fsl_eddy.out_residuals", datasink, "dmriprep.qc.@eddyresid") # the file that told us which volumes to drop wf.connect(id_outliers_node, "outpath", datasink, "dmriprep.qc.@droppedscans") # the tensors of the dropped volumes dwi wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@tensor") wf.connect(get_tensor, "fa_file", datasink, "dmriprep.dti.@fa") wf.connect(get_tensor, "md_file", datasink, "dmriprep.dti.@md") wf.connect(get_tensor, "ad_file", datasink, "dmriprep.dti.@ad") wf.connect(get_tensor, "rd_file", datasink, "dmriprep.dti.@rd") wf.connect(get_tensor, "color_fa_file", datasink, "dmriprep.dti.@colorfa") wf.connect(scale_tensor, "out_file", datasink, "dmriprep.dti.@scaled_tensor") # the tensors of the eddied volumes dwi wf.connect(get_tensor_eddy, "out_file", datasink, "dmriprep.dti_eddy.@tensor") wf.connect(get_tensor_eddy, "fa_file", datasink, "dmriprep.dti_eddy.@fa") wf.connect(get_tensor_eddy, "md_file", datasink, "dmriprep.dti_eddy.@md") wf.connect(get_tensor_eddy, "ad_file", datasink, "dmriprep.dti_eddy.@ad") wf.connect(get_tensor_eddy, "rd_file", datasink, "dmriprep.dti_eddy.@rd") wf.connect(get_tensor_eddy, "color_fa_file", datasink, "dmriprep.dti_eddy.@colorfa") wf.connect(scale_tensor_eddy, "out_file", datasink, "dmriprep.dti_eddy.@scaled_tensor") # all the eddy_quad stuff wf.connect(eddy_quad, 'out_qc_json', datasink, "dmriprep.qc.@eddyquad_json") wf.connect(eddy_quad, 'out_qc_pdf', datasink, "dmriprep.qc.@eddyquad_pdf") wf.connect(eddy_quad, 'out_avg_b_png', datasink, "dmriprep.qc.@eddyquad_bpng") wf.connect(eddy_quad, 'out_avg_b0_pe_png', datasink, "dmriprep.qc.@eddyquad_b0png") wf.connect(eddy_quad, 'out_cnr_png', datasink, "dmriprep.qc.@eddyquad_cnr") wf.connect(eddy_quad, 'out_vdm_png', datasink, "dmriprep.qc.@eddyquad_vdm") wf.connect(eddy_quad, 'out_residuals', datasink, 'dmriprep.qc.@eddyquad_resid') # anatomical registration stuff wf.connect(bbreg, "min_cost_file", datasink, "dmriprep.reg.@mincost") wf.connect(bbreg, "out_fsl_file", datasink, "dmriprep.reg.@fslfile") wf.connect(bbreg, "out_reg_file", datasink, "dmriprep.reg.@reg") # anatomical files resliced wf.connect(reslice_to_dwi, 'out_file', datasink, 'dmriprep.anat.@segmentation') wf.connect(create_mask, 'outfile', datasink, 'dmriprep.anat.@mask') wf.connect(reslice_orig_to_dwi, 'out_file', datasink, 'dmriprep.anat.@T1w') def report_fn(dwi_corrected_file, eddy_rms, eddy_report, color_fa_file, anat_mask_file, outlier_indices, eddy_qc_file): from dmriprep.qc import create_report_json report = create_report_json(dwi_corrected_file, eddy_rms, eddy_report, color_fa_file, anat_mask_file, outlier_indices, eddy_qc_file) return report report_node = pe.Node(niu.Function(input_names=[ 'dwi_corrected_file', 'eddy_rms', 'eddy_report', 'color_fa_file', 'anat_mask_file', 'outlier_indices', 'eddy_qc_file' ], output_names=['report'], function=report_fn), name="reportJSON") # for the report, lets show the eddy corrected (full volume) image wf.connect(voltransform, "transformed_file", report_node, 'dwi_corrected_file') wf.connect(eddy_quad, 'out_qc_json', report_node, 'eddy_qc_file') # add the rms movement output from eddy wf.connect(prep, "fsl_eddy.out_movement_rms", report_node, 'eddy_rms') wf.connect(prep, "fsl_eddy.out_outlier_report", report_node, 'eddy_report') wf.connect(id_outliers_node, 'drop_scans', report_node, 'outlier_indices') # the mask file to check our registration, and the colorFA file go in the report wf.connect(create_mask, "outfile", report_node, 'anat_mask_file') wf.connect(get_tensor, "color_fa_file", report_node, 'color_fa_file') # save that report! wf.connect(report_node, 'report', datasink, 'dmriprep.report.@report') # this part is done last, to get the filenames *just right* # its super annoying. def name_files_nicely(dwi_file, subject_id): import os.path as op dwi_fname = op.split(dwi_file)[1].split(".nii.gz")[0] substitutions = [ ("vol0000_flirt_merged.nii.gz", dwi_fname + '.nii.gz'), ("stats.vol0000_flirt_merged.txt", dwi_fname + ".art.json"), ("motion_parameters.par", dwi_fname + ".motion.txt"), ("_rotated.bvec", ".bvec"), ("art.vol0000_flirt_merged_outliers.txt", dwi_fname + ".outliers.txt"), ("vol0000_flirt_merged", dwi_fname), ("_roi_bbreg_freesurfer", "_register"), ("dwi/eddy_corrected", "dwi/%s" % dwi_fname), ("dti/eddy_corrected", "dti/%s" % dwi_fname.replace("_dwi", "")), ("reg/eddy_corrected", "reg/%s" % dwi_fname.replace("_dwi", "")), ("aparc+aseg_outbin", dwi_fname.replace("_dwi", "_mask")), ("aparc+aseg_out", dwi_fname.replace("_dwi", "_aparc+aseg")), ("art.eddy_corrected_outliers", dwi_fname.replace("dwi", "outliers")), ("color_fa", "colorfa"), ("orig_out", dwi_fname.replace("_dwi", "_T1w")), ("stats.eddy_corrected", dwi_fname.replace("dwi", "artStats")), ("eddy_corrected.eddy_parameters", dwi_fname + ".eddy_parameters"), ("qc/eddy_corrected", "qc/" + dwi_fname), ("derivatives/dmriprep", "derivatives/{}/dmriprep".format(subject_id)), ("_rotatedanat_space_thinned", ""), ("_thinned", ""), ("eddy_corrected", dwi_fname), ("_warped", ""), ("_maths", "_scaled"), ("dropped_scans", dwi_fname.replace("_dwi", "_dwi_dropped_scans")), ("report.json", dwi_fname.replace("_dwi", "_dwi_report.json")) ] return substitutions node_name_files_nicely = pe.Node(niu.Function( input_names=['dwi_file', 'subject_id'], output_names=['substitutions'], function=name_files_nicely), name="name_files_nicely") wf.connect(inputspec, 'dwi_file', node_name_files_nicely, 'dwi_file') wf.connect(inputspec, 'subject_id', node_name_files_nicely, 'subject_id') wf.connect(node_name_files_nicely, 'substitutions', datasink, 'substitutions') return wf
def define_preproc_workflow(info, subjects, sessions, qc=True): # --- Workflow parameterization and data input scan_info = info.scan_info experiment = info.experiment_name iterables = generate_iterables(scan_info, experiment, subjects, sessions) subject_iterables, session_iterables, run_iterables = iterables subject_iterables = subjects subject_source = Node(IdentityInterface(["subject"]), name="subject_source", iterables=("subject", subject_iterables)) session_source = Node(IdentityInterface(["subject", "session"]), name="session_source", itersource=("subject_source", "subject"), iterables=("session", session_iterables)) run_source = Node(IdentityInterface(["subject", "session", "run"]), name="run_source", itersource=("session_source", "session"), iterables=("run", run_iterables)) session_input = Node(SessionInput(data_dir=info.data_dir, proc_dir=info.proc_dir, fm_template=info.fm_template, phase_encoding=info.phase_encoding), "session_input") run_input = Node(RunInput(experiment=experiment, data_dir=info.data_dir, proc_dir=info.proc_dir, sb_template=info.sb_template, ts_template=info.ts_template, crop_frames=info.crop_frames), name="run_input") # --- Warpfield estimation using topup # Distortion warpfield estimation # TODO figure out how to parameterize for testing # topup_config = op.realpath(op.join(__file__, "../../../topup_fast.cnf")) topup_config = "b02b0.cnf" estimate_distortions = Node(fsl.TOPUP(config=topup_config), "estimate_distortions") # Post-process the TOPUP outputs finalize_unwarping = Node(FinalizeUnwarping(), "finalize_unwarping") # --- Registration of SE-EPI (without distortions) to Freesurfer anatomy fm2anat = Node(fs.BBRegister(init="fsl", contrast_type="t2", registered_file=True, out_fsl_file="sess2anat.mat", out_reg_file="sess2anat.dat"), "fm2anat") fm2anat_qc = Node(AnatRegReport(data_dir=info.data_dir), "fm2anat_qc") # --- Registration of SBRef to SE-EPI (with distortions) sb2fm = Node(fsl.FLIRT(dof=6, interp="spline"), "sb2fm") sb2fm_qc = Node(CoregGIF(out_file="coreg.gif"), "sb2fm_qc") # --- Motion correction of time series to SBRef (with distortions) ts2sb = Node(fsl.MCFLIRT(save_mats=True, save_plots=True), "ts2sb") ts2sb_qc = Node(RealignmentReport(), "ts2sb_qc") # --- Combined motion correction, unwarping, and template registration # Combine pre-and post-warp linear transforms combine_premats = MapNode(fsl.ConvertXFM(concat_xfm=True), "in_file", "combine_premats") combine_postmats = Node(fsl.ConvertXFM(concat_xfm=True), "combine_postmats") # Transform Jacobian images into the template space transform_jacobian = Node(fsl.ApplyWarp(relwarp=True), "transform_jacobian") # Apply rigid transforms and nonlinear warpfield to time series frames restore_timeseries = MapNode(fsl.ApplyWarp(interp="spline", relwarp=True), ["in_file", "premat"], "restore_timeseries") # Apply rigid transforms and nonlinear warpfield to template frames restore_template = MapNode(fsl.ApplyWarp(interp="spline", relwarp=True), ["in_file", "premat", "field_file"], "restore_template") # Perform final preprocessing operations on timeseries finalize_timeseries = Node(FinalizeTimeseries(experiment=experiment), "finalize_timeseries") # Perform final preprocessing operations on template finalize_template = JoinNode(FinalizeTemplate(experiment=experiment), name="finalize_template", joinsource="run_source", joinfield=["mean_files", "tsnr_files", "mask_files", "noise_files"]) # --- Workflow ouptut save_info = Node(SaveInfo(info_dict=info.trait_get()), "save_info") template_output = Node(DataSink(base_directory=info.proc_dir, parameterization=False), "template_output") timeseries_output = Node(DataSink(base_directory=info.proc_dir, parameterization=False), "timeseries_output") # === Assemble pipeline cache_base = op.join(info.cache_dir, info.experiment_name) workflow = Workflow(name="preproc", base_dir=cache_base) # Connect processing nodes processing_edges = [ (subject_source, session_source, [("subject", "subject")]), (subject_source, run_source, [("subject", "subject")]), (session_source, run_source, [("session", "session")]), (session_source, session_input, [("session", "session")]), (run_source, run_input, [("run", "run")]), # Phase-encode distortion estimation (session_input, estimate_distortions, [("fm_file", "in_file"), ("phase_encoding", "encoding_direction"), ("readout_times", "readout_times")]), (session_input, finalize_unwarping, [("fm_file", "raw_file"), ("phase_encoding", "phase_encoding")]), (estimate_distortions, finalize_unwarping, [("out_corrected", "corrected_file"), ("out_warps", "warp_files"), ("out_jacs", "jacobian_files")]), # Registration of corrected SE-EPI to anatomy (session_input, fm2anat, [("subject", "subject_id")]), (finalize_unwarping, fm2anat, [("corrected_file", "source_file")]), # Registration of each frame to SBRef image (run_input, ts2sb, [("ts_file", "in_file"), ("sb_file", "ref_file")]), (ts2sb, finalize_timeseries, [("par_file", "mc_file")]), # Registration of SBRef volume to SE-EPI fieldmap (run_input, sb2fm, [("sb_file", "in_file")]), (finalize_unwarping, sb2fm, [("raw_file", "reference"), ("mask_file", "ref_weight")]), # Single-interpolation spatial realignment and unwarping (ts2sb, combine_premats, [("mat_file", "in_file")]), (sb2fm, combine_premats, [("out_matrix_file", "in_file2")]), (fm2anat, combine_postmats, [("out_fsl_file", "in_file")]), (session_input, combine_postmats, [("reg_file", "in_file2")]), (run_input, transform_jacobian, [("anat_file", "ref_file")]), (finalize_unwarping, transform_jacobian, [("jacobian_file", "in_file")]), (combine_postmats, transform_jacobian, [("out_file", "premat")]), (run_input, restore_timeseries, [("ts_frames", "in_file")]), (run_input, restore_timeseries, [("anat_file", "ref_file")]), (combine_premats, restore_timeseries, [("out_file", "premat")]), (finalize_unwarping, restore_timeseries, [("warp_file", "field_file")]), (combine_postmats, restore_timeseries, [("out_file", "postmat")]), (run_input, finalize_timeseries, [("run_tuple", "run_tuple"), ("anat_file", "anat_file"), ("seg_file", "seg_file"), ("mask_file", "mask_file")]), (transform_jacobian, finalize_timeseries, [("out_file", "jacobian_file")]), (restore_timeseries, finalize_timeseries, [("out_file", "in_files")]), (session_input, restore_template, [("fm_frames", "in_file"), ("anat_file", "ref_file")]), (estimate_distortions, restore_template, [("out_mats", "premat"), ("out_warps", "field_file")]), (combine_postmats, restore_template, [("out_file", "postmat")]), (session_input, finalize_template, [("session_tuple", "session_tuple"), ("seg_file", "seg_file"), ("anat_file", "anat_file")]), (transform_jacobian, finalize_template, [("out_file", "jacobian_file")]), (restore_template, finalize_template, [("out_file", "in_files")]), (finalize_timeseries, finalize_template, [("mean_file", "mean_files"), ("tsnr_file", "tsnr_files"), ("mask_file", "mask_files"), ("noise_file", "noise_files")]), # --- Persistent data storage # Ouputs associated with each scanner run (finalize_timeseries, timeseries_output, [("output_path", "container"), ("out_file", "@func"), ("mean_file", "@mean"), ("mask_file", "@mask"), ("tsnr_file", "@tsnr"), ("noise_file", "@noise"), ("mc_file", "@mc")]), # Ouputs associated with the session template (finalize_template, template_output, [("output_path", "container"), ("out_file", "@func"), ("mean_file", "@mean"), ("tsnr_file", "@tsnr"), ("mask_file", "@mask"), ("noise_file", "@noise")]), ] workflow.connect(processing_edges) # Optionally connect QC nodes qc_edges = [ # Registration of each frame to SBRef image (run_input, ts2sb_qc, [("sb_file", "target_file")]), (ts2sb, ts2sb_qc, [("par_file", "realign_params")]), # Registration of corrected SE-EPI to anatomy (session_input, fm2anat_qc, [("subject", "subject_id")]), (fm2anat, fm2anat_qc, [("registered_file", "in_file"), ("min_cost_file", "cost_file")]), # Registration of SBRef volume to SE-EPI fieldmap (sb2fm, sb2fm_qc, [("out_file", "in_file")]), (finalize_unwarping, sb2fm_qc, [("raw_file", "ref_file")]), # Ouputs associated with each scanner run (run_source, save_info, [("run", "parameterization")]), (save_info, timeseries_output, [("info_file", "qc.@info_json")]), (run_input, timeseries_output, [("ts_plot", "qc.@raw_gif")]), (sb2fm_qc, timeseries_output, [("out_file", "qc.@sb2fm_gif")]), (ts2sb_qc, timeseries_output, [("params_plot", "qc.@params_plot"), ("target_plot", "qc.@target_plot")]), (finalize_timeseries, timeseries_output, [("out_gif", "qc.@ts_gif"), ("out_png", "qc.@ts_png"), ("mask_plot", "qc.@mask_plot"), ("mean_plot", "qc.@ts_mean_plot"), ("tsnr_plot", "qc.@ts_tsnr_plot"), ("noise_plot", "qc.@noise_plot")]), # Outputs associated with the session template (finalize_unwarping, template_output, [("warp_plot", "qc.@warp_png"), ("unwarp_gif", "qc.@unwarp_gif")]), (fm2anat_qc, template_output, [("out_file", "qc.@reg_png")]), (finalize_template, template_output, [("out_plot", "qc.@func_png"), ("mean_plot", "qc.@mean"), ("tsnr_plot", "qc.@tsnr"), ("mask_plot", "qc.@mask"), ("noise_plot", "qc.@noise")]), ] if qc: workflow.connect(qc_edges) return workflow
def run_dmriprep(dwi_file, bvec_file, bval_file, subjects_dir, working_dir, out_dir): """ Runs dmriprep for acquisitions with just one PE direction. """ from glob import glob import nibabel as nib import nipype.interfaces.freesurfer as fs import nipype.interfaces.fsl as fsl import nipype.interfaces.io as nio import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe import numpy as np from nipype.algorithms.rapidart import ArtifactDetect from nipype.interfaces.dipy import DTI from nipype.interfaces.fsl.utils import AvScale from nipype.utils.filemanip import fname_presuffix from nipype.workflows.dmri.fsl.epi import create_dmri_preprocessing wf = create_dmri_preprocessing(name='dmriprep', use_fieldmap=False, fieldmap_registration=False) wf.inputs.inputnode.ref_num = 0 wf.inputs.inputnode.in_file = dwi_file wf.inputs.inputnode.in_bvec = bvec_file dwi_fname = op.split(dwi_file)[1].split(".nii.gz")[0] bids_sub_name = dwi_fname.split("_")[0] assert bids_sub_name.startswith("sub-") # inputnode = wf.get_node("inputnode") outputspec = wf.get_node("outputnode") # QC: FLIRT translation and rotation parameters flirt = wf.get_node("motion_correct.coregistration") # flirt.inputs.save_mats = True get_tensor = pe.Node(DTI(), name="dipy_tensor") wf.connect(outputspec, "dmri_corrected", get_tensor, "in_file") # wf.connect(inputspec2,"bvals", get_tensor, "in_bval") get_tensor.inputs.in_bval = bval_file wf.connect(outputspec, "bvec_rotated", get_tensor, "in_bvec") scale_tensor = pe.Node(name='scale_tensor', interface=fsl.BinaryMaths()) scale_tensor.inputs.operation = 'mul' scale_tensor.inputs.operand_value = 1000 wf.connect(get_tensor, 'out_file', scale_tensor, 'in_file') fslroi = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="fslroi") wf.connect(outputspec, "dmri_corrected", fslroi, "in_file") bbreg = pe.Node(fs.BBRegister(contrast_type="t2", init="fsl", out_fsl_file=True, subjects_dir=subjects_dir, epi_mask=True), name="bbreg") # wf.connect(inputspec2,"fsid", bbreg,"subject_id") bbreg.inputs.subject_id = 'freesurfer' # bids_sub_name wf.connect(fslroi, "roi_file", bbreg, "source_file") voltransform = pe.Node(fs.ApplyVolTransform(inverse=True), iterfield=['source_file', 'reg_file'], name='transform') voltransform.inputs.subjects_dir = subjects_dir vt2 = voltransform.clone("transform_aparcaseg") vt2.inputs.interp = "nearest" def binarize_aparc(aparc_aseg): img = nib.load(aparc_aseg) data, aff = img.get_data(), img.affine outfile = fname_presuffix(aparc_aseg, suffix="bin.nii.gz", newpath=op.abspath("."), use_ext=False) nib.Nifti1Image((data > 0).astype(float), aff).to_filename(outfile) return outfile # wf.connect(inputspec2, "mask_nii", voltransform, "target_file") create_mask = pe.Node(niu.Function(input_names=["aparc_aseg"], output_names=["outfile"], function=binarize_aparc), name="bin_aparc") def get_aparc_aseg(subjects_dir, sub): return op.join(subjects_dir, sub, "mri", "aparc+aseg.mgz") create_mask.inputs.aparc_aseg = get_aparc_aseg(subjects_dir, 'freesurfer') wf.connect(create_mask, "outfile", voltransform, "target_file") wf.connect(fslroi, "roi_file", voltransform, "source_file") wf.connect(bbreg, "out_reg_file", voltransform, "reg_file") vt2.inputs.target_file = get_aparc_aseg(subjects_dir, 'freesurfer') # wf.connect(inputspec2, "aparc_aseg", vt2, "target_file") wf.connect(fslroi, "roi_file", vt2, "source_file") wf.connect(bbreg, "out_reg_file", vt2, "reg_file") # AK (2017): THIS NODE MIGHT NOT BE NECESSARY # AK (2018) doesn't know why she said that above.. threshold2 = pe.Node(fs.Binarize(min=0.5, out_type='nii.gz', dilate=1), iterfield=['in_file'], name='threshold2') wf.connect(voltransform, "transformed_file", threshold2, "in_file") # wf.connect(getmotion, "motion_params", datasink, "dti.@motparams") def get_flirt_motion_parameters(flirt_out_mats): def get_params(A): """This is a copy of spm's spm_imatrix where we already know the rotations and translations matrix, shears and zooms (as outputs from fsl FLIRT/avscale) Let A = the 4x4 rotation and translation matrix R = [ c5*c6, c5*s6, s5] [-s4*s5*c6-c4*s6, -s4*s5*s6+c4*c6, s4*c5] [-c4*s5*c6+s4*s6, -c4*s5*s6-s4*c6, c4*c5] """ def rang(b): a = min(max(b, -1), 1) return a Ry = np.arcsin(A[0, 2]) # Rx = np.arcsin(A[1, 2] / np.cos(Ry)) # Rz = np.arccos(A[0, 1] / np.sin(Ry)) if (abs(Ry) - np.pi / 2)**2 < 1e-9: Rx = 0 Rz = np.arctan2(-rang(A[1, 0]), rang(-A[2, 0] / A[0, 2])) else: c = np.cos(Ry) Rx = np.arctan2(rang(A[1, 2] / c), rang(A[2, 2] / c)) Rz = np.arctan2(rang(A[0, 1] / c), rang(A[0, 0] / c)) rotations = [Rx, Ry, Rz] translations = [A[0, 3], A[1, 3], A[2, 3]] return rotations, translations motion_params = open(op.abspath('motion_parameters.par'), 'w') for mat in flirt_out_mats: res = AvScale(mat_file=mat).run() A = np.asarray(res.outputs.rotation_translation_matrix) rotations, translations = get_params(A) for i in rotations + translations: motion_params.write('%f ' % i) motion_params.write('\n') motion_params.close() motion_params = op.abspath('motion_parameters.par') return motion_params getmotion = pe.Node(niu.Function(input_names=["flirt_out_mats"], output_names=["motion_params"], function=get_flirt_motion_parameters), name="get_motion_parameters", iterfield="flirt_out_mats") wf.connect(flirt, "out_matrix_file", getmotion, "flirt_out_mats") art = pe.Node(interface=ArtifactDetect(), name="art") art.inputs.use_differences = [True, True] art.inputs.save_plot = False art.inputs.use_norm = True art.inputs.norm_threshold = 3 art.inputs.zintensity_threshold = 9 art.inputs.mask_type = 'spm_global' art.inputs.parameter_source = 'FSL' wf.connect(getmotion, "motion_params", art, "realignment_parameters") wf.connect(outputspec, "dmri_corrected", art, "realigned_files") datasink = pe.Node(nio.DataSink(), name="sinker") datasink.inputs.base_directory = out_dir datasink.inputs.substitutions = [ ("vol0000_flirt_merged.nii.gz", dwi_fname + '.nii.gz'), ("stats.vol0000_flirt_merged.txt", dwi_fname + ".art.json"), ("motion_parameters.par", dwi_fname + ".motion.txt"), ("_rotated.bvec", ".bvec"), ("aparc+aseg_warped_out", dwi_fname.replace("_dwi", "_aparc+aseg")), ("art.vol0000_flirt_merged_outliers.txt", dwi_fname + ".outliers.txt"), ("vol0000_flirt_merged", dwi_fname), ("_roi_bbreg_freesurfer", "_register"), ("aparc+asegbin_warped_thresh", dwi_fname.replace("_dwi", "_mask")), ("derivatives/dmriprep", "derivatives/{}/dmriprep".format(bids_sub_name)) ] wf.connect(art, "statistic_files", datasink, "dmriprep.art.@artstat") wf.connect(art, "outlier_files", datasink, "dmriprep.art.@artoutlier") wf.connect(outputspec, "dmri_corrected", datasink, "dmriprep.dwi.@corrected") wf.connect(outputspec, "bvec_rotated", datasink, "dmriprep.dwi.@rotated") wf.connect(getmotion, "motion_params", datasink, "dmriprep.art.@motion") wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@tensor") wf.connect(get_tensor, "fa_file", datasink, "dmriprep.dti.@fa") wf.connect(get_tensor, "md_file", datasink, "dmriprep.dti.@md") wf.connect(get_tensor, "ad_file", datasink, "dmriprep.dti.@ad") wf.connect(get_tensor, "rd_file", datasink, "dmriprep.dti.@rd") wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@scaled_tensor") wf.connect(bbreg, "min_cost_file", datasink, "dmriprep.reg.@mincost") wf.connect(bbreg, "out_fsl_file", datasink, "dmriprep.reg.@fslfile") wf.connect(bbreg, "out_reg_file", datasink, "dmriprep.reg.@reg") wf.connect(threshold2, "binary_file", datasink, "dmriprep.anat.@mask") # wf.connect(vt2, "transformed_file", datasink, "dwi.@aparc_aseg") convert = pe.Node(fs.MRIConvert(out_type="niigz"), name="convert2nii") wf.connect(vt2, "transformed_file", convert, "in_file") wf.connect(convert, "out_file", datasink, "dmriprep.anat.@aparc_aseg") wf.base_dir = working_dir wf.run() copyfile( bval_file, op.join(out_dir, bids_sub_name, "dmriprep", "dwi", op.split(bval_file)[1])) dmri_corrected = glob(op.join(out_dir, '*/dmriprep/dwi', '*.nii.gz'))[0] bvec_rotated = glob(op.join(out_dir, '*/dmriprep/dwi', '*.bvec'))[0] bval_file = glob(op.join(out_dir, '*/dmriprep/dwi', '*.bval'))[0] art_file = glob(op.join(out_dir, '*/dmriprep/art', '*.art.json'))[0] motion_file = glob(op.join(out_dir, '*/dmriprep/art', '*.motion.txt'))[0] outlier_file = glob(op.join(out_dir, '*/dmriprep/art', '*.outliers.txt'))[0] return dmri_corrected, bvec_rotated, art_file, motion_file, outlier_file
def create_coreg_pipeline(name='coreg'): # fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # initiate workflow coreg = Workflow(name='coreg') #inputnode inputnode = Node(util.IdentityInterface(fields=[ 'epi_median', 'fs_subjects_dir', 'fs_subject_id', 'uni_highres', ]), name='inputnode') # outputnode outputnode = Node(util.IdentityInterface(fields=[ 'uni_lowres', 'epi2lowres', 'epi2lowres_mat', 'epi2lowres_dat', 'highres2lowres', 'highres2lowres_mat', 'highres2lowres_dat', 'epi2highres_lin', 'epi2highres_lin_mat', 'epi2highres_lin_itk' ]), name='outputnode') # convert mgz head file for reference fs_import = Node(interface=nio.FreeSurferSource(), name='fs_import') brain_convert = Node(fs.MRIConvert(out_type='niigz', out_file='uni_lowres.nii.gz'), name='brain_convert') coreg.connect([(inputnode, fs_import, [('fs_subjects_dir', 'subjects_dir'), ('fs_subject_id', 'subject_id')]), (fs_import, brain_convert, [('brain', 'in_file')]), (brain_convert, outputnode, [('out_file', 'uni_lowres')])]) # linear registration epi median to lowres mp2rage with bbregister bbregister_epi = Node(fs.BBRegister(contrast_type='t2', out_fsl_file='epi2lowres.mat', out_reg_file='epi2lowres.dat', registered_file='epi2lowres.nii.gz', init='fsl', epi_mask=True), name='bbregister_epi') coreg.connect([ (inputnode, bbregister_epi, [('fs_subjects_dir', 'subjects_dir'), ('fs_subject_id', 'subject_id'), ('epi_median', 'source_file')]), (bbregister_epi, outputnode, [('out_fsl_file', 'epi2lowres_mat'), ('out_reg_file', 'epi2lowres_dat'), ('registered_file', 'epi2lowres')]) ]) # linear register highres mp2rage to lowres mp2rage bbregister_anat = Node(fs.BBRegister( contrast_type='t1', out_fsl_file='highres2lowres.mat', out_reg_file='highres2lowres.dat', registered_file='highres2lowres.nii.gz', init='fsl'), name='bbregister_anat') coreg.connect([ (inputnode, bbregister_anat, [('fs_subjects_dir', 'subjects_dir'), ('fs_subject_id', 'subject_id'), ('uni_highres', 'source_file')]), (bbregister_anat, outputnode, [('out_fsl_file', 'highres2lowres_mat'), ('out_reg_file', 'highres2lowres_dat'), ('registered_file', 'highres2lowres')]) ]) # invert highres2lowres transform invert = Node(fsl.ConvertXFM(invert_xfm=True), name='invert') coreg.connect([(bbregister_anat, invert, [('out_fsl_file', 'in_file')])]) # concatenate epi2highres transforms concat = Node(fsl.ConvertXFM(concat_xfm=True, out_file='epi2highres_lin.mat'), name='concat') coreg.connect([(bbregister_epi, concat, [('out_fsl_file', 'in_file')]), (invert, concat, [('out_file', 'in_file2')]), (concat, outputnode, [('out_file', 'epi2higres_lin_mat')])]) # convert epi2highres transform into itk format itk = Node(interface=c3.C3dAffineTool(fsl2ras=True, itk_transform='epi2highres_lin.txt'), name='itk') coreg.connect([(inputnode, itk, [('epi_median', 'source_file'), ('uni_highres', 'reference_file')]), (concat, itk, [('out_file', 'transform_file')]), (itk, outputnode, [('itk_transform', 'epi2highres_lin_itk') ])]) # transform epi to highres epi2highres = Node(ants.ApplyTransforms( dimension=3, output_image='epi2highres_lin.nii.gz', interpolation='BSpline', ), name='epi2highres') coreg.connect([ (inputnode, epi2highres, [('uni_highres', 'reference_image'), ('epi_median', 'input_image')]), (itk, epi2highres, [('itk_transform', 'transforms')]), (epi2highres, outputnode, [('output_image', 'epi2highres_lin')]) ]) return coreg
def create_dti(): # main workflow for preprocessing diffusion data # fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # Initiation of a workflow dwi_preproc = Workflow(name="dwi_preproc") # inputnode inputnode = Node(IdentityInterface(fields=[ 'subject_id', 'freesurfer_dir', 'aseg', 'dwi', 'dwi_ap', 'dwi_pa', 'bvals', 'bvecs' ]), name='inputnode') # output node outputnode = Node(IdentityInterface(fields=[ 'dwi_denoised', "dwi_unringed", "topup_corr", "topup_field", "bo_brain", "bo_brainmask", "topup_fieldcoef", "eddy_corr", "eddy_params", "rotated_bvecs", "total_movement_rms", "shell_alignment_parameters", 'outlier_report', "cnr_maps", "residuals", 'dti_fa', 'dti_md', 'dti_l1', 'dti_l2', 'dti_l3', 'dti_v1', 'dti_v2', 'dti_v3', 'fa2anat', 'fa2anat_mat', 'fa2anat_dat' ]), name='outputnode') ''' workflow to run distortion correction ------------------------------------- ''' distor_corr = create_distortion_correct() ''' tensor fitting -------------- ''' dti = Node(fsl.DTIFit(), name='dti') #connecting the nodes dwi_preproc.connect([ (inputnode, distor_corr, [('dwi', 'inputnode.dwi')]), (inputnode, distor_corr, [('dwi_ap', 'inputnode.dwi_ap')]), (inputnode, distor_corr, [('dwi_pa', 'inputnode.dwi_pa')]), (inputnode, distor_corr, [("bvals", "inputnode.bvals")]), (inputnode, distor_corr, [("bvecs", "inputnode.bvecs")]), (inputnode, dti, [("bvals", "bvals")]), (distor_corr, outputnode, [('outputnode.bo_brain', 'bo_brain')]), (distor_corr, outputnode, [('outputnode.bo_brainmask', 'bo_brainmask')]), (distor_corr, outputnode, [('outputnode.noise', 'noise')]), (distor_corr, outputnode, [('outputnode.dwi_denoised', 'dwi_denoised')]), (distor_corr, outputnode, [('outputnode.dwi_unringed', 'dwi_unringed')]), (distor_corr, outputnode, [('outputnode.topup_corr', 'topup_corr')]), (distor_corr, outputnode, [('outputnode.topup_field', 'topup_field')]), (distor_corr, outputnode, [('outputnode.topup_fieldcoef', 'topup_fieldcoef')]), (distor_corr, outputnode, [('outputnode.eddy_corr', 'eddy_corr')]), (distor_corr, outputnode, [('outputnode.rotated_bvecs', 'rotated_bvecs')]), (distor_corr, outputnode, [('outputnode.total_movement_rms', 'total_movement_rms')]), (distor_corr, outputnode, [('outputnode.outlier_report', 'outlier_report')]), (distor_corr, outputnode, [('outputnode.shell_params', "shell_alignment_parameters",)]), (distor_corr, outputnode, [('outputnode.cnr_maps', 'cnr_maps')]), (distor_corr, outputnode, [('outputnode.residuals', 'residuals')]), (distor_corr, outputnode, [('outputnode.eddy_params', 'eddy_params')]), (distor_corr, dti, [("outputnode.rotated_bvecs", "bvecs")]), (distor_corr, dti, [('outputnode.bo_brainmask', 'mask')]), #(distor_corr, flirt, [('outputnode.eddy_corr', 'in_file')]), #(distor_corr, flirt, [('outputnode.eddy_corr', 'reference')]), #(flirt, dti, [('out_file', 'dwi')]), (distor_corr, dti, [('outputnode.eddy_corr', 'dwi')]), (dti, outputnode, [('FA', 'dti_fa')]), (dti, outputnode, [('MD', 'dti_md')]), (dti, outputnode, [('L1', 'dti_l1')]), (dti, outputnode, [('L2', 'dti_l2')]), (dti, outputnode, [('L3', 'dti_l3')]), (dti, outputnode, [('V1', 'dti_v1')]), (dti, outputnode, [('V2', 'dti_v2')]), (dti, outputnode, [('V3', 'dti_v3')]) ]) ''' coregistration of FA and T1 ------------------------------------ ''' #have to rename subject for fu (but now structural wf is connected to dwi #and its not necessary to rename again.) #def rename_subject_for_fu(input_id): # output_id=input_id+"_fu" # return output_id #modify subject name so it can be saved in the same folder as other LIFE- freesurfer data #rename=Node(util.Function(input_names=['input_id'], # output_names=['output_id'], # function = rename_subject_for_fu), name="rename") # linear registration with bbregister bbreg = Node(fs.BBRegister(contrast_type='t1', out_fsl_file='fa2anat.mat', out_reg_file='fa2anat.dat', registered_file='fa2anat_bbreg.nii.gz', init='fsl' ), name='bbregister') # connecting the nodes dwi_preproc.connect([ (inputnode, bbreg, [('subject_id', 'subject_id')]), (inputnode, bbreg, [('freesurfer_dir', 'subjects_dir')]), (dti, bbreg, [("FA", "source_file")]), (bbreg, outputnode, [('out_fsl_file', 'fa2anat_mat'), ('out_reg_file', 'fa2anat_dat'), ('registered_file', 'fa2anat')]) ]) return dwi_preproc
def create_reg_workflow(name='registration'): """Create a FEAT preprocessing workflow together with freesurfer Parameters ---------- name : name of workflow (default: 'registration') Inputs:: inputspec.source_files : files (filename or list of filenames to register) inputspec.mean_image : reference image to use inputspec.anatomical_image : anatomical image to coregister to inputspec.target_image : registration target Outputs:: outputspec.func2anat_transform : FLIRT transform outputspec.anat2target_transform : FLIRT+FNIRT transform outputspec.transformed_files : transformed files in target space outputspec.transformed_mean : mean image in target space """ register = Workflow(name=name) inputnode = Node(interface=IdentityInterface(fields=[ 'source_files', 'mean_image', 'subject_id', 'subjects_dir', 'target_image' ]), name='inputspec') outputnode = Node(interface=IdentityInterface(fields=[ 'func2anat_transform', 'out_reg_file', 'anat2target_transform', 'transforms', 'transformed_mean', 'segmentation_files', 'anat2target', 'aparc' ]), name='outputspec') # Get the subject's freesurfer source directory fssource = Node(FreeSurferSource(), name='fssource') fssource.run_without_submitting = True register.connect(inputnode, 'subject_id', fssource, 'subject_id') register.connect(inputnode, 'subjects_dir', fssource, 'subjects_dir') convert = Node(freesurfer.MRIConvert(out_type='nii'), name="convert") register.connect(fssource, 'T1', convert, 'in_file') # Coregister the median to the surface bbregister = Node(freesurfer.BBRegister(), name='bbregister') bbregister.inputs.init = 'fsl' bbregister.inputs.contrast_type = 't2' bbregister.inputs.out_fsl_file = True bbregister.inputs.epi_mask = True register.connect(inputnode, 'subject_id', bbregister, 'subject_id') register.connect(inputnode, 'mean_image', bbregister, 'source_file') register.connect(inputnode, 'subjects_dir', bbregister, 'subjects_dir') """ Estimate the tissue classes from the anatomical image. But use spm's segment as FSL appears to be breaking. """ stripper = Node(fsl.BET(), name='stripper') register.connect(convert, 'out_file', stripper, 'in_file') fast = Node(fsl.FAST(), name='fast') register.connect(stripper, 'out_file', fast, 'in_files') """ Binarize the segmentation """ binarize = MapNode(fsl.ImageMaths(op_string='-nan -thr 0.9 -ero -bin'), iterfield=['in_file'], name='binarize') register.connect(fast, 'partial_volume_files', binarize, 'in_file') """ Apply inverse transform to take segmentations to functional space """ applyxfm = MapNode(freesurfer.ApplyVolTransform(inverse=True, interp='nearest'), iterfield=['target_file'], name='inverse_transform') register.connect(inputnode, 'subjects_dir', applyxfm, 'subjects_dir') register.connect(bbregister, 'out_reg_file', applyxfm, 'reg_file') register.connect(binarize, 'out_file', applyxfm, 'target_file') register.connect(inputnode, 'mean_image', applyxfm, 'source_file') """ Apply inverse transform to aparc file """ aparcxfm = Node(freesurfer.ApplyVolTransform(inverse=True, interp='nearest'), name='aparc_inverse_transform') register.connect(inputnode, 'subjects_dir', aparcxfm, 'subjects_dir') register.connect(bbregister, 'out_reg_file', aparcxfm, 'reg_file') register.connect(fssource, ('aparc_aseg', get_aparc_aseg), aparcxfm, 'target_file') register.connect(inputnode, 'mean_image', aparcxfm, 'source_file') """ Convert the BBRegister transformation to ANTS ITK format """ convert2itk = Node(C3dAffineTool(), name='convert2itk') convert2itk.inputs.fsl2ras = True convert2itk.inputs.itk_transform = True register.connect(bbregister, 'out_fsl_file', convert2itk, 'transform_file') register.connect(inputnode, 'mean_image', convert2itk, 'source_file') register.connect(stripper, 'out_file', convert2itk, 'reference_file') """ Compute registration between the subject's structural and MNI template This is currently set to perform a very quick registration. However, the registration can be made significantly more accurate for cortical structures by increasing the number of iterations All parameters are set using the example from: #https://github.com/stnava/ANTs/blob/master/Scripts/newAntsExample.sh """ reg = Node(ants.Registration(), name='antsRegister') reg.inputs.output_transform_prefix = "output_" reg.inputs.transforms = ['Rigid', 'Affine', 'SyN'] reg.inputs.transform_parameters = [(0.1, ), (0.1, ), (0.2, 3.0, 0.0)] reg.inputs.number_of_iterations = [[10000, 11110, 11110]] * 2 + [[ 100, 30, 20 ]] reg.inputs.dimension = 3 reg.inputs.write_composite_transform = True reg.inputs.collapse_output_transforms = True reg.inputs.initial_moving_transform_com = True reg.inputs.metric = ['Mattes'] * 2 + [['Mattes', 'CC']] reg.inputs.metric_weight = [1] * 2 + [[0.5, 0.5]] reg.inputs.radius_or_number_of_bins = [32] * 2 + [[32, 4]] reg.inputs.sampling_strategy = ['Regular'] * 2 + [[None, None]] reg.inputs.sampling_percentage = [0.3] * 2 + [[None, None]] reg.inputs.convergence_threshold = [1.e-8] * 2 + [-0.01] reg.inputs.convergence_window_size = [20] * 2 + [5] reg.inputs.smoothing_sigmas = [[4, 2, 1]] * 2 + [[1, 0.5, 0]] reg.inputs.sigma_units = ['vox'] * 3 reg.inputs.shrink_factors = [[3, 2, 1]] * 2 + [[4, 2, 1]] reg.inputs.use_estimate_learning_rate_once = [True] * 3 reg.inputs.use_histogram_matching = [False] * 2 + [True] reg.inputs.winsorize_lower_quantile = 0.005 reg.inputs.winsorize_upper_quantile = 0.995 reg.inputs.float = True reg.inputs.output_warped_image = 'output_warped_image.nii.gz' reg.inputs.num_threads = 4 reg.plugin_args = {'qsub_args': '-l nodes=1:ppn=4'} register.connect(stripper, 'out_file', reg, 'moving_image') register.connect(inputnode, 'target_image', reg, 'fixed_image') """ Concatenate the affine and ants transforms into a list """ merge = Node(Merge(2), iterfield=['in2'], name='mergexfm') register.connect(convert2itk, 'itk_transform', merge, 'in2') register.connect(reg, 'composite_transform', merge, 'in1') """ Transform the mean image. First to anatomical and then to target """ warpmean = Node(ants.ApplyTransforms(), name='warpmean') warpmean.inputs.input_image_type = 3 warpmean.inputs.interpolation = 'Linear' warpmean.inputs.invert_transform_flags = [False, False] warpmean.inputs.terminal_output = 'file' warpmean.inputs.args = '--float' warpmean.inputs.num_threads = 4 register.connect(inputnode, 'target_image', warpmean, 'reference_image') register.connect(inputnode, 'mean_image', warpmean, 'input_image') register.connect(merge, 'out', warpmean, 'transforms') """ Assign all the output files """ register.connect(reg, 'warped_image', outputnode, 'anat2target') register.connect(warpmean, 'output_image', outputnode, 'transformed_mean') register.connect(applyxfm, 'transformed_file', outputnode, 'segmentation_files') register.connect(aparcxfm, 'transformed_file', outputnode, 'aparc') register.connect(bbregister, 'out_fsl_file', outputnode, 'func2anat_transform') register.connect(bbregister, 'out_reg_file', outputnode, 'out_reg_file') register.connect(reg, 'composite_transform', outputnode, 'anat2target_transform') register.connect(merge, 'out', outputnode, 'transforms') return register
def make_fs_fieldmap(name='make_fs_fieldmap'): inputnode = pe.Node(utility.IdentityInterface(fields=[ 'complex_image', 'magnitude_image', 'subject_id', 'freesurfer_subject_dir', 't1_mask', 'delta_TE' ]), run_without_submitting=True, name='inputspec') outputnode = pe.Node( utility.IdentityInterface(fields=['fieldmap', 'fieldmap_mask']), run_without_submitting=True, name='outputspec') n_fieldmap_to_t1_bbr = pe.Node(freesurfer.BBRegister(init='header', reg_frame=0, out_fsl_file=True, registered_file=True, contrast_type='t1'), name='fieldmap_to_t1_bbr') """ n_fieldmap_to_t1 = pe.Node( fsl.FLIRT(cost='mutualinfo', dof=6, no_search=True, uses_qform=True), name='fieldmap_to_t1') """ n_reg_to_mni = pe.Node(freesurfer.preprocess.Tkregister( no_edit=True, xfm_out='%s_xfm.mat'), run_without_submitting=True, name='reg_to_mni') n_resamp_complex = pe.Node(utility.Function( input_names=['mat_file', 'cplx_file', 'ref_file'], output_names=['out_file'], function=fs_resamp_complex), name='resamp_complex') n_phase_mag = pe.Node(utility.Function( input_names=['complex_in_file', 'mask_file'], output_names=['magnitude_out_file', 'phase_out_file'], function=complex_to_mag_phase), name='phase_mag') n_unwrap_phases = pe.Node(fsl.PRELUDE(process3d=True), name='unwrap_phases') n_make_fieldmap = pe.Node( fsl.FUGUE(smooth3d=3, unwarp_direction='z'), iterfield=['fmap_out_file', 'mask_file', 'fmap_in_file'], name='make_fieldmap') w = pe.Workflow(name=name) w.connect([ # (inputnode, n_fieldmap_to_t1, [('magnitude_image','in_file'), # ('t1_mag','reference')]), #(n_fieldmap_to_t1, n_flirt_complex, [('out_matrix_file','mat_file'),]), (inputnode, n_fieldmap_to_t1_bbr, [('magnitude_image', 'source_file'), ('freesurfer_subject_dir', 'subjects_dir'), ('subject_id', 'subject_id')]), (n_fieldmap_to_t1_bbr, n_reg_to_mni, [('out_reg_file', 'reg_file')]), (inputnode, n_reg_to_mni, [ ('magnitude_image', 'mov'), ('freesurfer_subject_dir', 'subjects_dir'), ]), (n_reg_to_mni, n_resamp_complex, [ ('xfm_out', 'mat_file'), ]), (inputnode, n_resamp_complex, [('complex_image', 'cplx_file'), ('t1_mask', 'ref_file')]), (n_resamp_complex, n_phase_mag, [('out_file', 'complex_in_file')]), (inputnode, n_phase_mag, [('t1_mask', 'mask_file')]), (n_phase_mag, n_unwrap_phases, [('phase_out_file', 'phase_file')]), (n_phase_mag, n_unwrap_phases, [('magnitude_out_file', 'magnitude_file')]), (inputnode, n_unwrap_phases, [('t1_mask', 'mask_file')]), (n_unwrap_phases, n_make_fieldmap, [('unwrapped_phase_file', 'phasemap_file')]), (inputnode, n_make_fieldmap, [('delta_TE', 'asym_se_time'), ('t1_mask', 'mask_file'), (('complex_image', fname_presuffix_basename, '', '_fieldmap'), 'fmap_out_file')]), ]) return w
datasource = pe.Node(nio.DataGrabber(infields=['subject_id'], outfields=['filtered_func', 'mean_image']), name='datasource') datasource.inputs.base_directory = datadir datasource.inputs.template = '%s/*%s.nii.gz' datasource.inputs.template_args = dict( filtered_func=[['subject_id', 'filtered']], mean_image=[['subject_id', 'mean']]) roiproc.connect(inputnode, 'subject_id', datasource, 'subject_id') fssource = pe.Node(nio.FreeSurferSource(), name='fssource') fssource.inputs.subjects_dir = surfacedir register = pe.Node(fs.BBRegister(init='fsl', contrast_type='t2'), name='register') register.inputs.subjects_dir = surfacedir voltransform = pe.Node(fs.ApplyVolTransform(inverse=True, interp='nearest'), name='transform') voltransform.inputs.subjects_dir = surfacedir def choose_aseg(aparc_files): from glob import glob import os all_files = glob(os.path.join(aparc_files[0].split('aparc')[0], '*yeo*')) for fname in all_files: if 'aparc+yeo17' in fname: return fname
def create_dti(): # main workflow for preprocessing diffusion data # fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # Initiation of a workflow dwi_preproc = Workflow(name="dwi_preproc") # inputnode inputnode = Node(IdentityInterface(fields=[ 'subject_id', 'freesurfer_dir', 'aseg', 'dwi', 'dwi_b0', 'dwi_mag', 'dwi_ph', 'bvals', 'bvecs', 'dwi_dwelltime', 'te_diff' ]), name='inputnode') # output node outputnode = Node(IdentityInterface(fields=[ 'bo_brain', "bo_brainmask", 'dwi_denoised', 'dwi_unringed', "mag2b0mat", "mag2b0", "fmap", "eddy_corr", "rotated_bvecs", "total_movement_rms", "outlier_report", "cnr_maps", "residuals", "shell_params", "eddy_params", 'dti_fa', 'dti_md', 'dti_l1', 'dti_l2', 'dti_l3', 'dti_v1', 'dti_v2', 'dti_v3', 'fa2anat', 'fa2anat_mat', 'fa2anat_dat' ]), name='outputnode') ''' workflow to run distortion correction ------------------------------------- ''' distor_corr = create_distortion_correct() ''' tensor fitting -------------- ''' dti = Node(fsl.DTIFit(), name='dti') #connecting the nodes dwi_preproc.connect([ (inputnode, distor_corr, [('dwi', 'inputnode.dwi')]), (inputnode, distor_corr, [('dwi_b0', 'inputnode.dwi_b0')]), (inputnode, distor_corr, [('dwi_mag', 'inputnode.dwi_mag')]), (inputnode, distor_corr, [('dwi_ph', 'inputnode.dwi_ph')]), (inputnode, distor_corr, [("bvals", "inputnode.bvals")]), (inputnode, distor_corr, [("bvecs", "inputnode.bvecs")]), (inputnode, distor_corr, [("dwi_dwelltime", "inputnode.dwi_dwelltime") ]), (inputnode, distor_corr, [("te_diff", "inputnode.te_diff")]), (distor_corr, outputnode, [('outputnode.bo_brain', 'bo_brain')]), (distor_corr, outputnode, [('outputnode.bo_brainmask', 'bo_brainmask') ]), (distor_corr, outputnode, [('outputnode.dwi_denoised', 'dwi_denoised') ]), (distor_corr, outputnode, [('outputnode.dwi_unringed', 'dwi_unringed') ]), (distor_corr, outputnode, [('outputnode.fmap', 'fmap')]), (distor_corr, outputnode, [('outputnode.mag2b0mat', 'mag2b0mat')]), (distor_corr, outputnode, [('outputnode.mag2b0', 'mag2b0')]), (distor_corr, outputnode, [('outputnode.eddy_corr', 'eddy_corr')]), (distor_corr, outputnode, [('outputnode.rotated_bvecs', 'rotated_bvecs')]), (distor_corr, outputnode, [('outputnode.total_movement_rms', 'total_movement_rms')]), (distor_corr, outputnode, [('outputnode.cnr_maps', 'cnr_maps')]), (distor_corr, outputnode, [('outputnode.residuals', 'residuals')]), (distor_corr, outputnode, [('outputnode.shell_params', 'shell_params') ]), (distor_corr, outputnode, [('outputnode.eddy_params', 'eddy_params')]), (distor_corr, outputnode, [('outputnode.outlier_report', 'outlier_report')]), (distor_corr, dti, [("outputnode.rotated_bvecs", "bvecs")]), (distor_corr, dti, [('outputnode.bo_brainmask', 'mask')]), (distor_corr, dti, [('outputnode.eddy_corr', 'dwi')]), (distor_corr, dti, [("outputnode.bvals", "bvals")]), (dti, outputnode, [('FA', 'dti_fa')]), (dti, outputnode, [('MD', 'dti_md')]), (dti, outputnode, [('L1', 'dti_l1')]), (dti, outputnode, [('L2', 'dti_l2')]), (dti, outputnode, [('L3', 'dti_l3')]), (dti, outputnode, [('V1', 'dti_v1')]), (dti, outputnode, [('V2', 'dti_v2')]), (dti, outputnode, [('V3', 'dti_v3')]) ]) ''' coregistration of FA and T1 ------------------------------------ ''' # linear registration with bbregister bbreg = Node(fs.BBRegister(contrast_type='t1', out_fsl_file='fa2anat.mat', out_reg_file='fa2anat.dat', registered_file='fa2anat_bbreg.nii.gz', init='fsl'), name='bbregister') # connecting the nodes dwi_preproc.connect([ (inputnode, bbreg, [('subject_id', 'subject_id')]), (inputnode, bbreg, [('freesurfer_dir', 'subjects_dir')]), (dti, bbreg, [("FA", "source_file")]), (bbreg, outputnode, [('out_fsl_file', 'fa2anat_mat'), ('out_reg_file', 'fa2anat_dat'), ('registered_file', 'fa2anat')]) ]) return dwi_preproc