def create_nuisance_evs_workflow(freesurfer_dir, fwhm, name="nuisance_evs"): ##### # Setup workflow ##### wf = pe.Workflow(name=name) ##### # Setup input node ##### input_fields = [ # segment "subject_id", # required "freesurfer_dir", "orientation", # mask creation "brain_mask", # required "reg_dir", # required "csf_prior", "csf_erode", "csf_threshold", "wm_prior", "wm_erode", "wm_threshold", # ts extraction "func", # required ] inputnode = pe.Node(interface=util.IdentityInterface(fields=input_fields), name="inputspec") # defaults inputnode.inputs.freesurfer_dir = freesurfer_dir inputnode.inputs.orientation = 'RPI' inputnode.inputs.csf_prior = fsl_prior_path("csf") inputnode.inputs.csf_erode = 0 inputnode.inputs.csf_threshold = 0.75 inputnode.inputs.wm_prior = fsl_prior_path("white") inputnode.inputs.wm_erode = 2 inputnode.inputs.wm_threshold = 0.75 ##### # Setup output node ##### # Outputs output_fields_highres = [ # segmentation "csf", "wm", "gm", "csf_pic", "wm_pic", "gm_pic" ] outputnode_highres = pe.Node(util.IdentityInterface(fields=output_fields_highres), name="outputspec_highres") output_fields_func = [ # masks "mask_global", "mask_csf", "mask_wm", "mask_global_pic", "mask_csf_pic", "mask_wm_pic", # ts "ts_global", "ts_csf", "ts_wm", "tsplot_global_pic", "tsplot_csf_pic", "tsplot_wm_pic", "tsplot_all_pic", ] outputnode_func = pe.Node(util.IdentityInterface(fields=output_fields_func), name="outputspec_func") # renaming renamer_highres = SimpleOutputConnector(wf, outputnode_highres) renamer_func = SimpleOutputConnector(wf, outputnode_func) ##### # COMMANDS ##### # Segment Brain segment = create_tissue_masks(freesurfer_dir, name="01_segment") wf.connect([ (inputnode, segment, [('subject_id', 'inputspec.subject_id'), ('freesurfer_dir', 'inputspec.freesurfer_dir'), ('orientation', 'inputspec.orientation')]), (segment, outputnode_highres, [('outputspec.csf', 'csf'), ('outputspec.wm', 'wm'), ('outputspec.gm', 'gm'), ('outputspec.csf_pic', 'csf_pic'), ('outputspec.wm_pic', 'wm_pic'), ('outputspec.gm_pic', 'gm_pic')]) ]) # Create CSF mask csfmask = create_nuisance_mask_workflow(name="02_mask_csf", fwhm=fwhm, mask_fprefix='mask_csf', freesurfer_dir=freesurfer_dir) wf.connect([ (segment, csfmask, [('outputspec.csf', 'inputspec.mask_file')]), (inputnode, csfmask, [('brain_mask', 'inputspec.brain_mask_file'), ('csf_prior', 'inputspec.prior_file'), ('reg_dir', 'inputspec.reg_dir'), ('freesurfer_dir', 'inputspec.freesurfer_dir'), ('csf_erode', 'inputspec.erode'), ('csf_threshold', 'inputspec.threshold')]), (csfmask, outputnode_func, [('outputspec.mask', 'mask_csf'), ('outputspec.mask_pic', 'mask_csf_pic')]) ]) # Create WM mask wmmask = create_nuisance_mask_workflow(name="02_mask_wm", fwhm=fwhm, mask_fprefix='mask_wm', freesurfer_dir=freesurfer_dir) wf.connect([ (segment, wmmask, [('outputspec.wm', 'inputspec.mask_file')]), (inputnode, wmmask, [('brain_mask', 'inputspec.brain_mask_file'), ('wm_prior', 'inputspec.prior_file'), ('reg_dir', 'inputspec.reg_dir'), ('freesurfer_dir', 'inputspec.freesurfer_dir'), ('wm_erode', 'inputspec.erode'), ('wm_threshold', 'inputspec.threshold')]), (wmmask, outputnode_func, [('outputspec.mask', 'mask_wm'), ('outputspec.mask_pic', 'mask_wm_pic')]) ]) # Global mask (copy and pic) slicer_global = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), name='02_mask_global') wf.connect(inputnode, ('reg_dir', regpath, 'func.*'), slicer_global, 'in_file') wf.connect(inputnode, ('brain_mask', get_overlay_args), slicer_global, 'overlay1') renamer_func.connect(slicer_global, 'out_file', 'mask_global_pic') renamer_func.connect(inputnode, 'brain_mask', 'mask_global') # Extract TS for global meants_global = pe.Node(fsl.ImageMeants(), name="03_meants_global") wf.connect([ (inputnode, meants_global, [('func', 'in_file'), ('brain_mask', 'mask')]) ]) renamer_func.connect(meants_global, 'out_file', 'ts_global') # Extract TS for csf meants_csf = pe.Node(fsl.ImageMeants(), name="03_meants_csf") wf.connect([ (inputnode, meants_csf, [('func', 'in_file')]), (csfmask, meants_csf, [('outputspec.mask', 'mask')]), ]) renamer_func.connect(meants_csf, 'out_file', 'ts_csf') # Extract TS for wm meants_wm = pe.Node(fsl.ImageMeants(), name="03_meants_wm") wf.connect([ (inputnode, meants_wm, [('func', 'in_file')]), (wmmask, meants_wm, [('outputspec.mask', 'mask')]), ]) renamer_func.connect(meants_wm, 'out_file', 'ts_wm') # Create plot ## concat concatnode = pe.Node(interface=util.Merge(3), name='04_concat') wf.connect(meants_global, ('out_file', tolist), concatnode, 'in1') wf.connect(meants_csf, ('out_file', tolist), concatnode, 'in2') wf.connect(meants_wm, ('out_file', tolist), concatnode, 'in3') ## plot tsplot_all = pe.Node(interface=fsl.PlotTimeSeries(title='Nuisance Time-Series', labels=['global', 'csf', 'wm']), name="04_tsplot_all") wf.connect(concatnode, 'out', tsplot_all, 'in_file') renamer_func.connect(tsplot_all, 'out_file', 'tsplot_all_pic') # Independent plots! ## global tsplot_global = pe.Node(interface=fsl.PlotTimeSeries(title='Global Time-Series'), name="04_tsplot_global") wf.connect(meants_global, 'out_file', tsplot_global, 'in_file') renamer_func.connect(tsplot_global, 'out_file', 'tsplot_global_pic') ## csf tsplot_csf = pe.Node(interface=fsl.PlotTimeSeries(title='CSF Time-Series'), name="04_tsplot_csf") wf.connect(meants_csf, 'out_file', tsplot_csf, 'in_file') renamer_func.connect(tsplot_csf, 'out_file', 'tsplot_csf_pic') ## wm tsplot_wm = pe.Node(interface=fsl.PlotTimeSeries(title='White-Matter Time-Series'), name="04_tsplot_wm") wf.connect(meants_wm, 'out_file', tsplot_wm, 'in_file') renamer_func.connect(tsplot_wm, 'out_file', 'tsplot_wm_pic') return wf
def create_tissue_masks(freesurfer_dir, name="segmentation"): """Generates masks of each tissue type (GM, WM, and CSF) using freesurfer. PNG images of each tissue type is also created for QC. """ ##### # Setup workflow ##### ctissues = pe.Workflow(name=name) ##### # Setup input node ##### input_fields = [ "subject_id", "freesurfer_dir", # $SUBJECTS_DIR "orientation" ] inputnode = pe.Node(interface=util.IdentityInterface(fields=input_fields), name="inputspec") # defaults inputnode.inputs.orientation = "RPI" # fsl's standard brain ##### # Setup output node ##### # Outputs output_fields = [ "aseg", "csf", "wm", "gm", "csf_pic", "wm_pic", "gm_pic" ] outputnode = pe.Node(util.IdentityInterface(fields=output_fields), name="outputspec") # renaming renamer = SimpleOutputConnector(ctissues, outputnode) ###### # Commands ###### # First call a function that may or may not run autorecon1 segment = pe.Node(run_freesurfer, name="segment") segment.inputs.directive = 'autorecon2' segment.inputs.subjects_dir = freesurfer_dir ctissues.connect([ (inputnode, segment, [('subject_id', 'subject_id'), ('freesurfer_dir', 'subjects_dir')]) ]) # Now get inputs getfree = pe.Node(nio.FreeSurferSource(subjects_dir=freesurfer_dir), name="getfree") ctissues.connect([ (inputnode, getfree, [('freesurfer_dir', 'subjects_dir')]), (segment, getfree, [('subject_id', 'subject_id')]) ]) # Save head => nii.gz convert_aseg = pe.Node(fs.MRIConvert(out_type="niigz", subjects_dir=freesurfer_dir), name="convert_orig") ctissues.connect(getfree, 'aseg', convert_aseg, 'in_file') ctissues.connect(inputnode, 'orientation', convert_aseg, 'out_orientation') ## reorient for sure reorient_aseg = pe.Node(interface=afni.Threedresample(), name='reorient_aseg') ctissues.connect(convert_aseg, 'out_file', reorient_aseg, 'in_file') ctissues.connect(inputnode, 'orientation', reorient_aseg, 'orientation') renamer(reorient_aseg, 'out_file', 'aseg') # Save brain => nii.gz convert_brain = pe.Node(fs.MRIConvert(out_type="niigz", subjects_dir=freesurfer_dir), name="convert_brain") ctissues.connect(getfree, 'brainmask', convert_brain, 'in_file') ctissues.connect(inputnode, 'orientation', convert_brain, 'out_orientation') ## reorient for sure reorient_brain = pe.Node(interface=afni.Threedresample(), name='reorient_brain') ctissues.connect(convert_brain, 'out_file', reorient_brain, 'in_file') ctissues.connect(inputnode, 'orientation', reorient_brain, 'orientation') # Extract and erode a mask of the deep cerebral white matter extractwm = pe.Node(fs.Binarize(match=[2, 41], subjects_dir=freesurfer_dir, out_type="nii.gz"), name="extractwm") ctissues.connect([ (inputnode, extractwm, [('freesurfer_dir', 'subjects_dir')]), (reorient_aseg, extractwm, [('out_file', 'in_file')]) ]) renamer.connect(extractwm, 'binary_file', 'wm') ## pic slicer_wm = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), name='slicer_wm') ctissues.connect(reorient_brain, 'out_file', slicer_wm, 'in_file') ctissues.connect(extractwm, ('binary_file', get_overlay_args), slicer_wm, 'overlay1') renamer.connect(slicer_wm, 'out_file', 'wm_pic') # Extract and erode a mask of the ventricles and CSF extractcsf = pe.Node(fs.Binarize(match=[4, 5, 14, 15, 24, 31, 43, 44, 63], subjects_dir=freesurfer_dir, out_type="nii.gz"), name="extractcsf") ctissues.connect([ (inputnode, extractcsf, [('freesurfer_dir', 'subjects_dir')]), (reorient_aseg, extractcsf, [('out_file', 'in_file')]) ]) renamer.connect(extractcsf, 'binary_file', 'csf') ## pic slicer_csf = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), name='slicer_csf') ctissues.connect(reorient_brain, 'out_file', slicer_csf, 'in_file') ctissues.connect(extractcsf, ('binary_file', get_overlay_args), slicer_csf, 'overlay1') renamer.connect(slicer_csf, 'out_file', 'csf_pic') # Extract a mask of the grey matter and subcortical areas and brainstem extractgm = pe.Node( fs.Binarize(match=[3,8,10,11,12,13,16,17,18,26,28,42,47,49,50,51,52,54,58,60], subjects_dir=freesurfer_dir, out_type="nii.gz"), name="extractgm" ) ctissues.connect([ (inputnode, extractgm, [('freesurfer_dir', 'subjects_dir')]), (reorient_aseg, extractgm, [('out_file', 'in_file')]) ]) renamer.connect(extractgm, 'binary_file', 'gm') ## pic slicer_gm = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), name='slicer_gm') ctissues.connect(reorient_brain, 'out_file', slicer_gm, 'in_file') ctissues.connect(extractgm, ('binary_file', get_overlay_args), slicer_gm, 'overlay1') renamer.connect(slicer_gm, 'out_file', 'gm_pic') return ctissues
def create_nuisance_mask_workflow(fwhm, mask_fprefix, freesurfer_dir, name="nuisance_mask"): """Transforms a csf/wm/gm mask from anatomical to functional space and then some. """ ##### # Setup workflow ##### nuisance = pe.Workflow(name=name) ##### # Setup input node ##### input_fields = [ "mask_file", "prior_file", "reg_dir", "brain_mask_file", "erode", "threshold", "freesurfer_dir" ] inputnode = pe.Node(interface=util.IdentityInterface(fields=input_fields), name="inputspec") inputnode.inputs.threshold = 0.75 ##### # Setup output node ##### # Outputs output_fields = [ "mask", "mask_pic" ] outputnode = pe.Node(util.IdentityInterface(fields=output_fields), name="outputspec") # renaming renamer = SimpleOutputConnector(nuisance, outputnode) ##### # Commands ##### # 1. erode erode = pe.Node(fs.Binarize(match=[1], subjects_dir=freesurfer_dir), name="01_erode") nuisance.connect([ (inputnode, erode, [('mask_file', 'in_file'), ('erode', 'erode'), ('freesurfer_dir', 'subjects_dir')]) ]) # 2. anat space => func space mask2func = pe.Node(fsl.ApplyXfm(apply_xfm=True, interp="trilinear"), name="02_mask2func") nuisance.connect([ (erode, mask2func, [('binary_file', 'in_file')]), (inputnode, mask2func, [(('reg_dir', regpath, 'func.*'), 'reference'), (('reg_dir', regpath, 'highres2func.mat'), 'in_matrix_file')]) ]) # 3. smooth if fwhm > 0: smooth = pe.Node(fsl.IsotropicSmooth(fwhm=fwhm), name="03_smooth") nuisance.connect([ (mask2func, smooth, [('out_file', 'in_file')]) ]) nextnode = smooth else: nextnode = anat2func # 4. prior: std space => func space prior2func = pe.Node(fsl.ApplyXfm(apply_xfm=True, interp="nearestneighbour"), name="04_prior2func") nuisance.connect([ (inputnode, prior2func, [('prior_file', 'in_file'), (('reg_dir', regpath, 'func.*'), 'reference'), (('reg_dir', regpath, 'standard2func.mat'), 'in_matrix_file')]) ]) # 5. mask by prior prior_masked = pe.Node(fsl.ApplyMask(), name="05_prior_masked") nuisance.connect([ (nextnode, prior_masked, [('out_file', 'in_file')]), (prior2func, prior_masked, [('out_file', 'mask_file')]) ]) # 6. threshold threshold = pe.Node(fsl.Threshold(direction="below"), name="06_threshold") nuisance.connect(inputnode, 'threshold', threshold, 'thresh') nuisance.connect(prior_masked, 'out_file', threshold, 'in_file') # 7. binarize binarize = pe.Node(fsl.UnaryMaths(operation="bin"), name="07_binarize") nuisance.connect(threshold, 'out_file', binarize, 'in_file') # 8. mask by brain brain_masked = pe.Node(fsl.ApplyMask(), name="08_brain_masked") nuisance.connect([ (binarize, brain_masked, [('out_file', 'in_file')]), (inputnode, brain_masked, [('brain_mask_file', 'mask_file')]) ]) renamer.connect(brain_masked, 'out_file', 'mask', format_string=mask_fprefix) # 9. picture of mask over func slicer_mask = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), name='09_slicer_mask') nuisance.connect(inputnode, ('reg_dir', regpath, 'func.*'), slicer_mask, 'in_file') nuisance.connect(brain_masked, ('out_file', get_overlay_args), slicer_mask, 'overlay1') renamer.connect(slicer_mask, 'out_file', 'mask_pic', format_string=mask_fprefix) return nuisance