def dilF(input_file): output_file = os.path.join(os.path.dirname(input_file), 'mask.nii.gz') mydilf = fsl.DilateImage(in_file=input_file, operation='max', out_file=output_file) print(mydilf.cmdline) mydilf.run() return output_file
def __init__(self, name, base_dir=None): super(BrainExtractionWorkflow, self).__init__(name, base_dir) # Segmentation # ============ seg_node = npe.MapNode(name="Segmentation", iterfield="data", interface=spm.Segment()) seg_node.inputs.gm_output_type = [False, False, True] seg_node.inputs.wm_output_type = [False, False, True] seg_node.inputs.csf_output_type = [False, False, True] add1_node = npe.MapNode(name="AddGMWM", iterfield=["in_file", "operand_file"], interface=fsl.BinaryMaths()) add1_node.inputs.operation = 'add' add2_node = npe.MapNode(name="AddGMWMCSF", iterfield=["in_file", "operand_file"], interface=fsl.BinaryMaths()) add2_node.inputs.operation = 'add' dil_node = npe.MapNode(name="Dilate", iterfield="in_file", interface=fsl.DilateImage()) dil_node.inputs.operation = 'mean' ero_node = npe.MapNode(name="Erode", iterfield="in_file", interface=fsl.ErodeImage()) thre_node = npe.MapNode(name="Threshold", iterfield="in_file", interface=fsl.Threshold()) thre_node.inputs.thresh = 0.5 fill_node = npe.MapNode(name="Fill", iterfield="in_file", interface=fsl.UnaryMaths()) fill_node.inputs.operation = 'fillh' mask_node = npe.MapNode(name="ApplyMask", iterfield=["in_file", "mask_file"], interface=fsl.ApplyMask()) mask_node.inputs.output_type = str("NIFTI") self.connect([ (seg_node, add1_node, [('native_gm_image', 'in_file')]), (seg_node, add1_node, [('native_wm_image', 'operand_file')]), (seg_node, add2_node, [('native_csf_image', 'in_file')]), (add1_node, add2_node, [('out_file', 'operand_file')]), (add2_node, dil_node, [('out_file', 'in_file')]), (dil_node, ero_node, [('out_file', 'in_file')]), (ero_node, thre_node, [('out_file', 'in_file')]), (thre_node, fill_node, [('out_file', 'in_file')]), (fill_node, mask_node, [('out_file', 'mask_file')]), ])
def ants_getmask(name): import nipype.interfaces.fsl as fsl import nipype.pipeline.engine as pe import nipype.interfaces.utility as niu import nipype.interfaces.ants as ants import nipype.interfaces.freesurfer as fs wf = pe.Workflow(name=name) inputspec = pe.Node( niu.IdentityInterface(fields=['functional', 'structural']), name='inputspec') bet = pe.Node(fsl.BET(mask=True, remove_eyes=True), name='bet') applymask = pe.Node(fs.ApplyMask(), name='applymask') #flirt = pe.Node(fsl.FLIRT(),name='flirt') #applyxfm_mask = pe.Node(fsl.ApplyXfm(interp='nearestneighbour',apply_xfm=True),name='applyxfm_mask') #applyxfm_seg = pe.MapNode(fsl.ApplyXfm(interp='nearestneighbour',apply_xfm=True),name='applyxfm_seg',iterfield=['in_file']) dilate = pe.Node(fsl.DilateImage(operation='mean'), name='dilate') atropos = pe.Node(ants.Atropos(initialization='KMeans', number_of_tissue_classes=3, dimension=3), name='atropos') n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='n4corrections') outputspec = pe.Node(niu.IdentityInterface( fields=['mask', 'reg_file', 'segments', 'warped_struct']), name='outputspec') #create brain mask wf.connect(inputspec, "structural", bet, "in_file") #dilate bets mask a bit for atropos wf.connect(bet, "mask_file", dilate, "in_file") # apply dilated mask to img wf.connect(dilate, 'out_file', applymask, 'mask_file') wf.connect(inputspec, 'structural', applymask, 'in_file') #N4 bias correction wf.connect(applymask, "out_file", n4, 'input_image') # atropos it wf.connect(n4, "output_image", atropos, 'intensity_images') wf.connect(dilate, 'out_file', atropos, 'mask_image') return wf
def create_skullstrip_workflow(name="skullstrip"): # Define the workflow inputs inputnode = pe.Node(util.IdentityInterface(fields=["timeseries"]), name="inputs") # Mean the timeseries across the fourth dimension meanfunc1 = pe.MapNode(fsl.MeanImage(), iterfield=["in_file"], name="meanfunc1") # Skullstrip the mean functional image stripmean = pe.MapNode(fsl.BET(mask=True, no_output=True, frac=0.3), iterfield=["in_file"], name="stripmean") # Use the mask from skullstripping to strip each timeseries maskfunc1 = pe.MapNode(fsl.ApplyMask(), iterfield=["in_file", "mask_file"], name="maskfunc1") # Determine the 2nd and 98th percentile intensities of each run getthresh = pe.MapNode(fsl.ImageStats(op_string="-p 2 -p 98"), iterfield=["in_file"], name="getthreshold") # Threshold functional data at 10% of the 98th percentile threshold = pe.MapNode(fsl.ImageMaths(out_data_type="char", suffix="_thresh"), iterfield=["in_file"], name="threshold") # Dilate the mask dilatemask = pe.MapNode(fsl.DilateImage(operation="max"), iterfield=["in_file"], name="dilatemask") # Mask the runs again with this new mask maskfunc2 = pe.MapNode(fsl.ApplyMask(), iterfield=["in_file", "mask_file"], name="maskfunc2") # Get a new mean image from each functional run meanfunc2 = pe.MapNode(fsl.MeanImage(), iterfield=["in_file"], name="meanfunc2") # Slice the mean func for reporting meanslice = pe.MapNode(fsl.Slicer(image_width=800, label_slices=False), iterfield=["in_file", "image_edges"], name="meanslice") meanslice.inputs.sample_axial = 2 # Rename the outputs meanname = pe.MapNode(util.Rename(format_string="mean_func", keep_ext=True), iterfield=["in_file"], name="meanname") maskname = pe.MapNode(util.Rename(format_string="functional_mask", keep_ext=True), iterfield=["in_file"], name="maskname") pngname = pe.MapNode(util.Rename(format_string="mean_func.png"), iterfield=["in_file"], name="pngname") # Define the workflow outputs outputnode = pe.Node(util.IdentityInterface( fields=["timeseries", "mean_func", "mask_file", "report_png"]), name="outputs") # Define and connect the workflow skullstrip = pe.Workflow(name=name) skullstrip.connect([ (inputnode, meanfunc1, [("timeseries", "in_file")]), (meanfunc1, stripmean, [("out_file", "in_file")]), (inputnode, maskfunc1, [("timeseries", "in_file")]), (stripmean, maskfunc1, [("mask_file", "mask_file")]), (maskfunc1, getthresh, [("out_file", "in_file")]), (getthresh, threshold, [(("out_stat", get_thresh_op), "op_string")]), (maskfunc1, threshold, [("out_file", "in_file")]), (threshold, dilatemask, [("out_file", "in_file")]), (inputnode, maskfunc2, [("timeseries", "in_file")]), (dilatemask, maskfunc2, [("out_file", "mask_file")]), (maskfunc2, meanfunc2, [("out_file", "in_file")]), (meanfunc2, meanslice, [("out_file", "in_file")]), (dilatemask, meanslice, [("out_file", "image_edges")]), (meanslice, pngname, [("out_file", "in_file")]), (meanfunc2, meanname, [("out_file", "in_file")]), (dilatemask, maskname, [("out_file", "in_file")]), (maskfunc2, outputnode, [("out_file", "timeseries")]), (pngname, outputnode, [("out_file", "report_png")]), (maskname, outputnode, [("out_file", "mask_file")]), (meanname, outputnode, [("out_file", "mean_func")]), ]) return skullstrip
zeroing = pe.Node(interface=fsl.BinaryMaths(in_file=TemplateBrain, operation='mul', operand_value=0), name='zeroing') # Node for creating a point at the center of the ROI addPoint = pe.Node( interface=fsl.maths.MathsCommand( # Find a way to RegEx this # args = '-add 1 -roi 45 1 74 1 51 1 0 1' ), iterables=('args', ROIs), name='addPoint') # node for expanding the point dilatePoint = pe.Node(interface=fsl.DilateImage(operation='mean', kernel_shape='sphere', kernel_size=5), name='dilatePoint') #DataSink --- stores important outputs dataSink = pe.Node( interface=nio.DataSink( base_directory=ROIDir, parameterization= True # This line keeps the DataSink from adding an aditional level to the directory, I have no Idea why this works. ), name="dataSink") ''' ############### ##Connections## ###############
def create_mask_from_seg_pipe(params={}, name="mask_from_seg_pipe"): """ Description: mask from segmentation tissues #TODO To be added if required (was in old_segment before) Function: - Compute union of those 3 tissues; - Apply morphological opening on the union mask - Fill holes Inputs: mask_gm, mask_wm: binary mask for grey matter and white matter Outputs: fill_holes.out_file: filled mask after erode fill_holes_dil.out_file filled mask after dilate """ # creating pipeline seg_pipe = pe.Workflow(name=name) # Creating inputnode inputnode = pe.Node(niu.IdentityInterface( fields=['mask_gm', 'mask_wm', 'mask_csf', 'indiv_params']), name='inputnode') # bin_gm bin_gm = pe.Node(interface=fsl.UnaryMaths(), name="bin_gm") bin_gm.inputs.operation = "fillh" seg_pipe.connect(inputnode, 'mask_gm', bin_gm, 'in_file') # bin_csf bin_csf = pe.Node(interface=fsl.UnaryMaths(), name="bin_csf") bin_csf.inputs.operation = "fillh" seg_pipe.connect(inputnode, 'mask_csf', bin_csf, 'in_file') # bin_wm bin_wm = pe.Node(interface=fsl.UnaryMaths(), name="bin_wm") bin_wm.inputs.operation = "fillh" seg_pipe.connect(inputnode, 'mask_wm', bin_wm, 'in_file') # Compute union of the 3 tissues # Done with 2 fslmaths as it seems to hard to do it wmgm_union = pe.Node(fsl.BinaryMaths(), name="wmgm_union") wmgm_union.inputs.operation = "add" seg_pipe.connect(bin_gm, 'out_file', wmgm_union, 'in_file') seg_pipe.connect(bin_wm, 'out_file', wmgm_union, 'operand_file') tissues_union = pe.Node(fsl.BinaryMaths(), name="tissues_union") tissues_union.inputs.operation = "add" seg_pipe.connect(wmgm_union, 'out_file', tissues_union, 'in_file') seg_pipe.connect(bin_csf, 'out_file', tissues_union, 'operand_file') # Opening (dilating) mask dilate_mask = NodeParams(fsl.DilateImage(), params=parse_key(params, "dilate_mask"), name="dilate_mask") dilate_mask.inputs.operation = "mean" # Arbitrary operation seg_pipe.connect(tissues_union, 'out_file', dilate_mask, 'in_file') # fill holes of dilate_mask fill_holes_dil = pe.Node(BinaryFillHoles(), name="fill_holes_dil") seg_pipe.connect(dilate_mask, 'out_file', fill_holes_dil, 'in_file') # Eroding mask erode_mask = NodeParams(fsl.ErodeImage(), params=parse_key(params, "erode_mask"), name="erode_mask") seg_pipe.connect(tissues_union, 'out_file', erode_mask, 'in_file') # fill holes of erode_mask fill_holes = pe.Node(BinaryFillHoles(), name="fill_holes") seg_pipe.connect(erode_mask, 'out_file', fill_holes, 'in_file') # merge to index merge_indexed_mask = NodeParams( interface=niu.Function(input_names=[ "mask_csf_file", "mask_wm_file", "mask_gm_file", "index_csf", "index_gm", "index_wm" ], output_names=['indexed_mask'], function=merge_masks), params=parse_key(params, "merge_indexed_mask"), name="merge_indexed_mask") seg_pipe.connect(bin_gm, 'out_file', merge_indexed_mask, "mask_gm_file") seg_pipe.connect(bin_wm, 'out_file', merge_indexed_mask, "mask_wm_file") seg_pipe.connect(bin_csf, 'out_file', merge_indexed_mask, "mask_csf_file") return seg_pipe
NodeHash_20695ac0.inputs.percentage = 0.1 #Wraps command **fslmaths** NodeHash_10ff9c60 = pe.MapNode(interface = fsl.Threshold(), name = 'NodeName_10ff9c60', iterfield = ['in_file', 'thresh']) #Wraps command **fslmaths** NodeHash_843b4a0 = pe.MapNode(interface = fsl.MinImage(), name = 'NodeName_843b4a0', iterfield = ['in_file']) NodeHash_843b4a0.inputs.args = '-bin' NodeHash_843b4a0.inputs.dimension = 'T' #Wraps command **fslmaths** NodeHash_2b6977b0 = pe.MapNode(interface = fsl.ChangeDataType(), name = 'NodeName_2b6977b0', iterfield = ['in_file']) NodeHash_2b6977b0.inputs.output_datatype = 'char' #Wraps command **fslmaths** NodeHash_258767c0 = pe.MapNode(interface = fsl.DilateImage(), name = 'NodeName_258767c0', iterfield = ['in_file']) NodeHash_258767c0.inputs.operation = 'max' #Wraps command **fslstats** NodeHash_2fd0bda0 = pe.MapNode(interface = fsl.ImageStats(), name = 'NodeName_2fd0bda0', iterfield = ['in_file', 'mask_file']) NodeHash_2fd0bda0.inputs.op_string = '-p 50' #Wraps command **fslmaths** NodeHash_ffd7a90 = pe.MapNode(interface = fsl.ApplyMask(), name = 'NodeName_ffd7a90', iterfield = ['in_file', 'mask_file']) #Wraps command **fslmaths** NodeHash_255ee520 = pe.MapNode(interface = fsl.MeanImage(), name = 'NodeName_255ee520', iterfield = ['in_file']) #Custom interface wrapping function Getusan NodeHash_12d6d9d0 = pe.MapNode(interface = firstlevelhelpers.Getusan, name = 'NodeName_12d6d9d0', iterfield = ['brightness_thresh', 'in_file'])
def skullstrip_functional(skullstrip_tool='afni', anatomical_mask_dilation=False, wf_name='skullstrip_functional'): skullstrip_tool = skullstrip_tool.lower() if skullstrip_tool != 'afni' and skullstrip_tool != 'fsl' and skullstrip_tool != 'fsl_afni' and skullstrip_tool != 'anatomical_refined': raise Exception( "\n\n[!] Error: The 'tool' parameter of the " "'skullstrip_functional' workflow must be either " "'afni' or 'fsl' or 'fsl_afni' or 'anatomical_refined'.\n\nTool input: " "{0}\n\n".format(skullstrip_tool)) wf = pe.Workflow(name=wf_name) input_node = pe.Node(util.IdentityInterface( fields=['func', 'anatomical_brain_mask', 'anat_skull']), name='inputspec') output_node = pe.Node( util.IdentityInterface(fields=['func_brain', 'func_brain_mask']), name='outputspec') if skullstrip_tool == 'afni': func_get_brain_mask = pe.Node(interface=preprocess.Automask(), name='func_get_brain_mask_AFNI') func_get_brain_mask.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_get_brain_mask, 'in_file') wf.connect(func_get_brain_mask, 'out_file', output_node, 'func_brain_mask') elif skullstrip_tool == 'fsl': func_get_brain_mask = pe.Node(interface=fsl.BET(), name='func_get_brain_mask_BET') func_get_brain_mask.inputs.mask = True func_get_brain_mask.inputs.functional = True erode_one_voxel = pe.Node(interface=fsl.ErodeImage(), name='erode_one_voxel') erode_one_voxel.inputs.kernel_shape = 'box' erode_one_voxel.inputs.kernel_size = 1.0 wf.connect(input_node, 'func', func_get_brain_mask, 'in_file') wf.connect(func_get_brain_mask, 'mask_file', erode_one_voxel, 'in_file') wf.connect(erode_one_voxel, 'out_file', output_node, 'func_brain_mask') elif skullstrip_tool == 'fsl_afni': skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True, functional=True), name='skullstrip_first_pass') bet_dilate = pe.Node(fsl.DilateImage(operation='max', kernel_shape='sphere', kernel_size=6.0, internal_datatype='char'), name='skullstrip_first_dilate') bet_mask = pe.Node(fsl.ApplyMask(), name='skullstrip_first_mask') unifize = pe.Node(afni_utils.Unifize( t2=True, outputtype='NIFTI_GZ', args='-clfrac 0.2 -rbt 18.3 65.0 90.0', out_file="uni.nii.gz"), name='unifize') skullstrip_second_pass = pe.Node(preprocess.Automask( dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') wf.connect([ (input_node, skullstrip_first_pass, [('func', 'in_file')]), (skullstrip_first_pass, bet_dilate, [('mask_file', 'in_file')]), (bet_dilate, bet_mask, [('out_file', 'mask_file')]), (skullstrip_first_pass, bet_mask, [('out_file', 'in_file')]), (bet_mask, unifize, [('out_file', 'in_file')]), (unifize, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, combine_masks, [('out_file', 'operand_file')]), (combine_masks, output_node, [('out_file', 'func_brain_mask')]) ]) # Refine functional mask by registering anatomical mask to functional space elif skullstrip_tool == 'anatomical_refined': # Get functional mean to use later as reference, when transform anatomical mask to functional space func_skull_mean = pe.Node(interface=afni_utils.TStat(), name='func_skull_mean') func_skull_mean.inputs.options = '-mean' func_skull_mean.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_skull_mean, 'in_file') # Register func to anat linear_reg_func_to_anat = pe.Node(interface=fsl.FLIRT(), name='linear_reg_func_to_anat') linear_reg_func_to_anat.inputs.cost = 'mutualinfo' linear_reg_func_to_anat.inputs.dof = 6 wf.connect(func_skull_mean, 'out_file', linear_reg_func_to_anat, 'in_file') wf.connect(input_node, 'anat_skull', linear_reg_func_to_anat, 'reference') # Inverse func to anat affine inv_func_to_anat_affine = pe.Node(interface=fsl.ConvertXFM(), name='inv_func_to_anat_affine') inv_func_to_anat_affine.inputs.invert_xfm = True wf.connect(linear_reg_func_to_anat, 'out_matrix_file', inv_func_to_anat_affine, 'in_file') # Transform anatomical mask to functional space linear_trans_mask_anat_to_func = pe.Node( interface=fsl.FLIRT(), name='linear_trans_mask_anat_to_func') linear_trans_mask_anat_to_func.inputs.apply_xfm = True linear_trans_mask_anat_to_func.inputs.cost = 'mutualinfo' linear_trans_mask_anat_to_func.inputs.dof = 6 linear_trans_mask_anat_to_func.inputs.interp = 'nearestneighbour' # Dialate anatomical mask, if 'anatomical_mask_dilation : True' in config file if anatomical_mask_dilation: anat_mask_dilate = pe.Node(interface=afni.MaskTool(), name='anat_mask_dilate') anat_mask_dilate.inputs.dilate_inputs = '1' anat_mask_dilate.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'anatomical_brain_mask', anat_mask_dilate, 'in_file') wf.connect(anat_mask_dilate, 'out_file', linear_trans_mask_anat_to_func, 'in_file') else: wf.connect(input_node, 'anatomical_brain_mask', linear_trans_mask_anat_to_func, 'in_file') wf.connect(func_skull_mean, 'out_file', linear_trans_mask_anat_to_func, 'reference') wf.connect(inv_func_to_anat_affine, 'out_file', linear_trans_mask_anat_to_func, 'in_matrix_file') wf.connect(linear_trans_mask_anat_to_func, 'out_file', output_node, 'func_brain_mask') func_edge_detect = pe.Node(interface=afni_utils.Calc(), name='func_extract_brain') func_edge_detect.inputs.expr = 'a*b' func_edge_detect.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_edge_detect, 'in_file_a') if skullstrip_tool == 'afni': wf.connect(func_get_brain_mask, 'out_file', func_edge_detect, 'in_file_b') elif skullstrip_tool == 'fsl': wf.connect(erode_one_voxel, 'out_file', func_edge_detect, 'in_file_b') elif skullstrip_tool == 'fsl_afni': wf.connect(combine_masks, 'out_file', func_edge_detect, 'in_file_b') elif skullstrip_tool == 'anatomical_refined': wf.connect(linear_trans_mask_anat_to_func, 'out_file', func_edge_detect, 'in_file_b') wf.connect(func_edge_detect, 'out_file', output_node, 'func_brain') return wf
def create_workflow(self, flow, inputnode, outputnode): # resampling diffusion image and setting output type to short fs_mriconvert = pe.Node(interface=fs.MRIConvert(out_type='nii',out_file='diffusion_resampled.nii'),name="diffusion_resample") fs_mriconvert.inputs.vox_size = self.config.resampling fs_mriconvert.inputs.resample_type = self.config.interpolation flow.connect([(inputnode,fs_mriconvert,[('diffusion','in_file')])]) fs_mriconvert_wm_mask = pe.Node(interface=fs.MRIConvert(out_type='nii',resample_type='nearest',out_file='wm_mask_resampled.nii'),name="mask_resample") fs_mriconvert_wm_mask.inputs.vox_size = self.config.resampling flow.connect([(inputnode,fs_mriconvert_wm_mask,[('wm_mask_registered','in_file')])]) if self.config.processing_tool != 'DTK': fs_mriconvert_ROIs = pe.MapNode(interface=fs.MRIConvert(out_type='nii',resample_type='nearest'),name="ROIs_resample",iterfield=['in_file']) fs_mriconvert_ROIs.inputs.vox_size = self.config.resampling flow.connect([(inputnode,fs_mriconvert_ROIs,[('roi_volumes','in_file')])]) if self.config.dilate_rois: dilate_rois = pe.MapNode(interface=fsl.DilateImage(),iterfield=['in_file'],name='dilate_rois') dilate_rois.inputs.operation = 'modal' flow.connect([ (fs_mriconvert_ROIs,dilate_rois,[("out_file","in_file")]), (dilate_rois,outputnode,[("out_file","roi_volumes")]) ]) else: flow.connect([ (fs_mriconvert_ROIs,outputnode,[("out_file","roi_volumes")]) ]) else: flow.connect([ (inputnode,outputnode,[("roi_volumes","roi_volumes")]) ]) # Reconstruction if self.config.processing_tool == 'DTK': recon_flow = create_dtk_recon_flow(self.config.dtk_recon_config) flow.connect([ (inputnode,recon_flow,[('diffusion','inputnode.diffusion')]), (fs_mriconvert,recon_flow,[('out_file','inputnode.diffusion_resampled')]), ]) elif self.config.processing_tool == 'MRtrix': recon_flow = create_mrtrix_recon_flow(self.config.mrtrix_recon_config) flow.connect([ (inputnode,recon_flow,[('diffusion','inputnode.diffusion')]), (inputnode,recon_flow,[('grad','inputnode.grad')]), (fs_mriconvert,recon_flow,[('out_file','inputnode.diffusion_resampled')]), (fs_mriconvert_wm_mask, recon_flow,[('out_file','inputnode.wm_mask_resampled')]), (recon_flow,outputnode,[("outputnode.FA","gFA")]), ]) elif self.config.processing_tool == 'Camino': recon_flow = create_camino_recon_flow(self.config.camino_recon_config) flow.connect([ (inputnode,recon_flow,[('diffusion','inputnode.diffusion')]), (fs_mriconvert,recon_flow,[('out_file','inputnode.diffusion_resampled')]), (fs_mriconvert_wm_mask, recon_flow,[('out_file','inputnode.wm_mask_resampled')]), (recon_flow,outputnode,[("outputnode.FA","gFA")]) ]) elif self.config.processing_tool == 'FSL': recon_flow = create_fsl_recon_flow(self.config.fsl_recon_config) flow.connect([ (fs_mriconvert,recon_flow,[('out_file','inputnode.diffusion_resampled')]), (fs_mriconvert_wm_mask,recon_flow,[('out_file','inputnode.wm_mask_resampled')]) ]) elif self.config.processing_tool == 'Gibbs': recon_flow = create_gibbs_recon_flow(self.config.gibbs_recon_config) flow.connect([ (fs_mriconvert,recon_flow,[("out_file","inputnode.diffusion_resampled")]) ]) # Tracking if self.config.processing_tool == 'DTK': track_flow = create_dtb_tracking_flow(self.config.dtb_tracking_config) flow.connect([ (inputnode, track_flow,[('wm_mask_registered','inputnode.wm_mask_registered')]), (recon_flow, track_flow,[('outputnode.DWI','inputnode.DWI')]) ]) elif self.config.processing_tool == 'MRtrix': track_flow = create_mrtrix_tracking_flow(self.config.mrtrix_tracking_config) flow.connect([ (fs_mriconvert_wm_mask, track_flow,[('out_file','inputnode.wm_mask_resampled')]), (recon_flow, outputnode,[('outputnode.DWI','fod_file')]), (recon_flow, track_flow,[('outputnode.DWI','inputnode.DWI'),('outputnode.grad','inputnode.grad')]), (dilate_rois,track_flow,[('out_file','inputnode.gm_registered')]) #(recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) # if self.config.diffusion_model == 'Probabilistic': # flow.connect([ # (dilate_rois,track_flow,[('out_file','inputnode.gm_registered')]), # ]) flow.connect([ (track_flow,outputnode,[('outputnode.track_file','track_file')]) ]) elif self.config.processing_tool == 'Camino': track_flow = create_camino_tracking_flow(self.config.camino_tracking_config) flow.connect([ (fs_mriconvert_wm_mask, track_flow,[('out_file','inputnode.wm_mask_resampled')]), (recon_flow, track_flow,[('outputnode.DWI','inputnode.DWI'), ('outputnode.grad','inputnode.grad')]) ]) if self.config.diffusion_model == 'Probabilistic': flow.connect([ (dilate_rois,track_flow,[('out_file','inputnode.gm_registered')]), ]) flow.connect([ (track_flow,outputnode,[('outputnode.track_file','track_file')]) ]) elif self.config.processing_tool == 'FSL': track_flow = create_fsl_tracking_flow(self.config.fsl_tracking_config) flow.connect([ (fs_mriconvert_wm_mask,track_flow,[('out_file','inputnode.wm_mask_resampled')]), (dilate_rois,track_flow,[('out_file','inputnode.gm_registered')]), (recon_flow,track_flow,[('outputnode.fsamples','inputnode.fsamples')]), (recon_flow,track_flow,[('outputnode.phsamples','inputnode.phsamples')]), (recon_flow,track_flow,[('outputnode.thsamples','inputnode.thsamples')]), ]) flow.connect([ (track_flow,outputnode,[("outputnode.targets","track_file")]), ]) elif self.config.processing_tool == 'Gibbs': track_flow = create_gibbs_tracking_flow(self.config.gibbs_tracking_config) flow.connect([ (fs_mriconvert_wm_mask, track_flow,[('out_file','inputnode.wm_mask_resampled')]), (recon_flow,track_flow,[("outputnode.recon_file","inputnode.recon_file")]), (track_flow,outputnode,[('outputnode.track_file','track_file')]) ]) if self.config.processing_tool == 'DTK': flow.connect([ (recon_flow,outputnode, [("outputnode.gFA","gFA"),("outputnode.skewness","skewness"), ("outputnode.kurtosis","kurtosis"),("outputnode.P0","P0")]), (track_flow,outputnode, [('outputnode.track_file','track_file')]) ]) temp_node = pe.Node(interface=util.IdentityInterface(fields=["diffusion_model"]),name="diffusion_model") temp_node.inputs.diffusion_model = self.config.diffusion_model flow.connect([ (temp_node,outputnode,[("diffusion_model","diffusion_model")]) ])
def init_enhance_and_skullstrip_bold_wf(name='enhance_and_skullstrip_bold_wf', omp_nthreads=1, enhance_t2=False): """ This workflow takes in a :abbr:`BOLD (blood-oxygen level-dependant)` :abbr:`fMRI (functional MRI)` average/summary (e.g. a reference image averaging non-steady-state timepoints), and sharpens the histogram with the application of the N4 algorithm for removing the :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal mask. Steps of this workflow are: 1. Calculate a conservative mask using Nilearn's ``create_epi_mask``. 2. Run ANTs' ``N4BiasFieldCorrection`` on the input :abbr:`BOLD (blood-oxygen level-dependant)` average, using the mask generated in 1) instead of the internal Otsu thresholding. 3. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 4. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image with the latest mask calculated in 3), then use AFNI's ``3dUnifize`` to *standardize* the T2* contrast distribution. 5. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 6. Calculate a final mask as the intersection of 3) and 5). 7. Apply final mask on the enhanced reference. .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold.util import init_enhance_and_skullstrip_bold_wf wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1) **Parameters** name : str Name of workflow (default: ``enhance_and_skullstrip_bold_wf``) omp_nthreads : int number of threads available to parallel nodes enhance_t2 : bool perform logarithmic transform of input BOLD image to improve contrast before calculating the preliminary mask **Inputs** in_file BOLD image (single volume) **Outputs** bias_corrected_file the ``in_file`` after `N4BiasFieldCorrection`_ skull_stripped_file the ``bias_corrected_file`` after skull-stripping mask_file mask of the skull-stripped input file out_report reportlet for the skull-stripping .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053 """ workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['mask_file', 'skull_stripped_file', 'bias_corrected_file']), name='outputnode') # Create a loose mask to avoid N4 internal's Otsu mask n4_mask = pe.Node(MaskEPI(upper_cutoff=0.75, enhance_t2=enhance_t2, opening=1, no_sanitize=True), name='n4_mask') # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1) n4_correct = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True), name='n4_correct', n_procs=1) # Create a generous BET mask out of the bias-corrected EPI skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name='skullstrip_first_pass') bet_dilate = pe.Node(fsl.DilateImage(operation='max', kernel_shape='sphere', kernel_size=6.0, internal_datatype='char'), name='skullstrip_first_dilate') bet_mask = pe.Node(fsl.ApplyMask(), name='skullstrip_first_mask') # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( afni.Unifize( t2=True, outputtype='NIFTI_GZ', # Default -clfrac is 0.1, 0.4 was too conservative # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation) args='-clfrac 0.2 -rbt 18.3 65.0 90.0', out_file="uni.nii.gz"), name='unifize') fixhdr_unifize = pe.Node(CopyXForm(), name='fixhdr_unifize', mem_gb=0.1) # Run ANFI's 3dAutomask to extract a refined brain mask skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') fixhdr_skullstrip2 = pe.Node(CopyXForm(), name='fixhdr_skullstrip2', mem_gb=0.1) # Take intersection of both masks combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') # Compute masked brain apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask') workflow.connect([ (inputnode, n4_mask, [('in_file', 'in_files')]), (inputnode, n4_correct, [('in_file', 'input_image')]), (inputnode, fixhdr_unifize, [('in_file', 'hdr_file')]), (inputnode, fixhdr_skullstrip2, [('in_file', 'hdr_file')]), (n4_mask, n4_correct, [('out_mask', 'mask_image')]), (n4_correct, skullstrip_first_pass, [('output_image', 'in_file')]), (skullstrip_first_pass, bet_dilate, [('mask_file', 'in_file')]), (bet_dilate, bet_mask, [('out_file', 'mask_file')]), (skullstrip_first_pass, bet_mask, [('out_file', 'in_file')]), (bet_mask, unifize, [('out_file', 'in_file')]), (unifize, fixhdr_unifize, [('out_file', 'in_file')]), (fixhdr_unifize, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, fixhdr_skullstrip2, [('out_file', 'in_file') ]), (fixhdr_skullstrip2, combine_masks, [('out_file', 'operand_file')]), (fixhdr_unifize, apply_mask, [('out_file', 'in_file')]), (combine_masks, apply_mask, [('out_file', 'mask_file')]), (combine_masks, outputnode, [('out_file', 'mask_file')]), (apply_mask, outputnode, [('out_file', 'skull_stripped_file')]), (n4_correct, outputnode, [('output_image', 'bias_corrected_file')]), ]) return workflow
#Wraps command **fslmaths** NodeHash_179e1da0 = pe.MapNode(interface=fsl.MinImage(), name='NodeName_179e1da0', iterfield=['in_file']) NodeHash_179e1da0.inputs.args = '-bin' NodeHash_179e1da0.inputs.dimension = 'T' #Wraps command **fslmaths** NodeHash_1879dad0 = pe.MapNode(interface=fsl.ChangeDataType(), name='NodeName_1879dad0', iterfield=['in_file']) NodeHash_1879dad0.inputs.output_datatype = 'char' #Wraps command **fslmaths** NodeHash_188ac400 = pe.MapNode(interface=fsl.DilateImage(), name='NodeName_188ac400', iterfield=['in_file']) NodeHash_188ac400.inputs.operation = 'max' #Wraps command **fslstats** NodeHash_1a202720 = pe.MapNode(interface=fsl.ImageStats(), name='NodeName_1a202720', iterfield=['in_file', 'mask_file']) NodeHash_1a202720.inputs.op_string = '-p 50' #Wraps command **fslmaths** NodeHash_19cad2d0 = pe.MapNode(interface=fsl.ApplyMask(), name='NodeName_19cad2d0', iterfield=['in_file', 'mask_file'])
NodeHash_14e3d7c0.inputs.percentage = 0.1 #Wraps command **fslmaths** NodeHash_157bd2b0 = pe.MapNode(interface = fsl.Threshold(), name = 'NodeName_157bd2b0', iterfield = ['in_file', 'thresh']) #Wraps command **fslmaths** NodeHash_15f74220 = pe.MapNode(interface = fsl.MinImage(), name = 'NodeName_15f74220', iterfield = ['in_file']) NodeHash_15f74220.inputs.args = '-bin' NodeHash_15f74220.inputs.dimension = 'T' #Wraps command **fslmaths** NodeHash_16d421a0 = pe.MapNode(interface = fsl.ChangeDataType(), name = 'NodeName_16d421a0', iterfield = ['in_file']) NodeHash_16d421a0.inputs.output_datatype = 'char' #Wraps command **fslmaths** NodeHash_1801caa0 = pe.MapNode(interface = fsl.DilateImage(), name = 'NodeName_1801caa0', iterfield = ['in_file']) NodeHash_1801caa0.inputs.operation = 'max' #Wraps command **fslstats** NodeHash_18508680 = pe.MapNode(interface = fsl.ImageStats(), name = 'NodeName_18508680', iterfield = ['in_file', 'mask_file']) NodeHash_18508680.inputs.op_string = '-p 50' #Wraps command **fslmaths** NodeHash_181e69e0 = pe.MapNode(interface = fsl.ApplyMask(), name = 'NodeName_181e69e0', iterfield = ['in_file', 'mask_file']) #Wraps command **fslmaths** NodeHash_182b4bf0 = pe.MapNode(interface = fsl.MeanImage(), name = 'NodeName_182b4bf0', iterfield = ['in_file']) #Custom interface wrapping function Getusan NodeHash_1a479090 = pe.MapNode(interface = firstlevelhelpers.Getusan, name = 'NodeName_1a479090', iterfield = ['brightness_thresh', 'in_file'])
def create_workflow(self, flow, inputnode, outputnode): """Create the stage worflow. Parameters ---------- flow : nipype.pipeline.engine.Workflow The nipype.pipeline.engine.Workflow instance of the Diffusion pipeline inputnode : nipype.interfaces.utility.IdentityInterface Identity interface describing the inputs of the stage outputnode : nipype.interfaces.utility.IdentityInterface Identity interface describing the outputs of the stage See Also -------- cmp.stages.diffusion.reconstruction.create_dipy_recon_flow cmp.stages.diffusion.reconstruction.create_mrtrix_recon_flow cmp.stages.diffusion.tracking.create_dipy_tracking_flow cmp.stages.diffusion.tracking.create_mrtrix_tracking_flow """ if self.config.dilate_rois: dilate_rois = pe.MapNode(interface=fsl.DilateImage(), iterfield=["in_file"], synchronize=True, name="dilate_rois") dilate_rois.inputs.operation = "modal" if self.config.dilation_kernel == "Box": kernel_size = 2 * self.config.dilation_radius + 1 dilate_rois.inputs.kernel_shape = "boxv" dilate_rois.inputs.kernel_size = kernel_size else: extract_sizes = pe.Node(interface=ExtractImageVoxelSizes(), name="extract_sizes") flow.connect([(inputnode, extract_sizes, [("diffusion", "in_file")])]) extract_sizes.run() print("Voxel sizes : ", extract_sizes.outputs.voxel_sizes) min_size = 100 for voxel_size in extract_sizes.outputs.voxel_sizes: if voxel_size < min_size: min_size = voxel_size print("voxel size (min): %g" % min_size) if self.config.dilation_kernel == "Gauss": kernel_size = 2 * extract_sizes.outputs.voxel_sizes + 1 # FWHM criteria, i.e. sigma = FWHM / 2(sqrt(2ln(2))) sigma = kernel_size / 2.355 dilate_rois.inputs.kernel_shape = "gauss" dilate_rois.inputs.kernel_size = sigma elif self.config.dilation_kernel == "Sphere": radius = 0.5 * min_size + self.config.dilation_radius * min_size dilate_rois.inputs.kernel_shape = "sphere" dilate_rois.inputs.kernel_size = radius # fmt: off flow.connect([ (inputnode, dilate_rois, [("roi_volumes", "in_file")]), (dilate_rois, outputnode, [("out_file", "roi_volumes")]), ]) # fmt: on else: # fmt: off flow.connect([(inputnode, outputnode, [("roi_volumes", "roi_volumes")])]) # fmt: on if self.config.recon_processing_tool == "Dipy": recon_flow = create_dipy_recon_flow(self.config.dipy_recon_config) # fmt: off flow.connect([ (inputnode, recon_flow, [("diffusion", "inputnode.diffusion") ]), (inputnode, recon_flow, [("bvals", "inputnode.bvals")]), (inputnode, recon_flow, [("bvecs", "inputnode.bvecs")]), ( inputnode, recon_flow, [("diffusion", "inputnode.diffusion_resampled")], ), ( inputnode, recon_flow, [("wm_mask_registered", "inputnode.wm_mask_resampled")], ), ( inputnode, recon_flow, [("brain_mask_registered", "inputnode.brain_mask_resampled")], ), (recon_flow, outputnode, [("outputnode.FA", "FA")]), (recon_flow, outputnode, [("outputnode.MD", "ADC")]), (recon_flow, outputnode, [("outputnode.AD", "AD")]), (recon_flow, outputnode, [("outputnode.RD", "RD")]), (recon_flow, outputnode, [("outputnode.shore_maps", "shore_maps")]), ( recon_flow, outputnode, [("outputnode.mapmri_maps", "mapmri_maps")], ), ]) # fmt: on elif self.config.recon_processing_tool == "MRtrix": # TODO modify nipype tensormetric interface to get AD and RD maps recon_flow = create_mrtrix_recon_flow( self.config.mrtrix_recon_config) # fmt: off flow.connect([ (inputnode, recon_flow, [("diffusion", "inputnode.diffusion") ]), (inputnode, recon_flow, [("grad", "inputnode.grad")]), ( inputnode, recon_flow, [("diffusion", "inputnode.diffusion_resampled")], ), ( inputnode, recon_flow, [("brain_mask_registered", "inputnode.wm_mask_resampled")], ), (recon_flow, outputnode, [("outputnode.FA", "FA")]), (recon_flow, outputnode, [("outputnode.ADC", "ADC")]), (recon_flow, outputnode, [("outputnode.tensor", "tensor")]), # (recon_flow,outputnode,[("outputnode.AD","AD")]), # (recon_flow,outputnode,[("outputnode.RD","RD")]), ]) # fmt: on if self.config.tracking_processing_tool == "Dipy": track_flow = create_dipy_tracking_flow( self.config.dipy_tracking_config) if self.config.diffusion_imaging_model != "DSI": # fmt: off flow.connect([ (recon_flow, outputnode, [("outputnode.DWI", "fod_file")]), ( recon_flow, track_flow, [("outputnode.model", "inputnode.model")], ), (inputnode, track_flow, [("bvals", "inputnode.bvals")]), ( recon_flow, track_flow, [("outputnode.bvecs", "inputnode.bvecs")], ), # Diffusion resampled (inputnode, track_flow, [("diffusion", "inputnode.DWI")]), ( inputnode, track_flow, [("partial_volumes", "inputnode.partial_volumes")], ), ( inputnode, track_flow, [("wm_mask_registered", "inputnode.wm_mask_resampled") ], ), # (inputnode, track_flow,[('diffusion','inputnode.DWI')]), (recon_flow, track_flow, [("outputnode.FA", "inputnode.FA") ]), ( dilate_rois, track_flow, [("out_file", "inputnode.gm_registered")], ) # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) # fmt: on else: # fmt: off flow.connect([ (recon_flow, outputnode, [("outputnode.fod", "fod_file")]), ( recon_flow, track_flow, [("outputnode.fod", "inputnode.fod_file")], ), ( recon_flow, track_flow, [("outputnode.model", "inputnode.model")], ), (inputnode, track_flow, [("bvals", "inputnode.bvals")]), ( recon_flow, track_flow, [("outputnode.bvecs", "inputnode.bvecs")], ), # Diffusion resampled (inputnode, track_flow, [("diffusion", "inputnode.DWI")]), ( inputnode, track_flow, [("partial_volumes", "inputnode.partial_volumes")], ), ( inputnode, track_flow, [("wm_mask_registered", "inputnode.wm_mask_resampled") ], ), # (inputnode, track_flow,[('diffusion','inputnode.DWI')]), (recon_flow, track_flow, [("outputnode.FA", "inputnode.FA") ]), ( dilate_rois, track_flow, [("out_file", "inputnode.gm_registered")], ) # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) # fmt: on if (self.config.dipy_tracking_config.use_act and self.config.dipy_tracking_config.seed_from_gmwmi): # fmt: off flow.connect([ ( inputnode, track_flow, [("gmwmi_registered", "inputnode.gmwmi_file")], ), ]) # fmt: on # fmt: off flow.connect([(track_flow, outputnode, [("outputnode.track_file", "track_file")])]) # fmt: on elif (self.config.tracking_processing_tool == "MRtrix" and self.config.recon_processing_tool == "MRtrix"): track_flow = create_mrtrix_tracking_flow( self.config.mrtrix_tracking_config) # fmt: off flow.connect([ (inputnode, track_flow, [("wm_mask_registered", "inputnode.wm_mask_resampled")]), (recon_flow, outputnode, [("outputnode.DWI", "fod_file")]), (recon_flow, track_flow, [("outputnode.DWI", "inputnode.DWI"), ("outputnode.grad", "inputnode.grad") ]), # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) # fmt: on if self.config.dilate_rois: # fmt: off flow.connect([(dilate_rois, track_flow, [("out_file", "inputnode.gm_registered")])]) # fmt: on else: # fmt: off flow.connect([(inputnode, track_flow, [("roi_volumes", "inputnode.gm_registered")])]) # fmt: on # fmt: off flow.connect([ ( inputnode, track_flow, [("act_5tt_registered", "inputnode.act_5tt_registered")], ), ( inputnode, track_flow, [("gmwmi_registered", "inputnode.gmwmi_registered")], ), ]) # fmt: on # fmt: off flow.connect([(track_flow, outputnode, [("outputnode.track_file", "track_file")])]) # fmt: on elif (self.config.tracking_processing_tool == "MRtrix" and self.config.recon_processing_tool == "Dipy"): track_flow = create_mrtrix_tracking_flow( self.config.mrtrix_tracking_config) if self.config.diffusion_imaging_model != "DSI": # fmt: off flow.connect([ ( inputnode, track_flow, [ ("wm_mask_registered", "inputnode.wm_mask_resampled"), ("grad", "inputnode.grad"), ], ), (recon_flow, outputnode, [("outputnode.DWI", "fod_file")]), (recon_flow, track_flow, [("outputnode.DWI", "inputnode.DWI")]), # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) # fmt: on else: # fmt: off flow.connect([ ( inputnode, track_flow, [ ("wm_mask_registered", "inputnode.wm_mask_resampled"), ("grad", "inputnode.grad"), ], ), (recon_flow, outputnode, [("outputnode.fod", "fod_file")]), (recon_flow, track_flow, [("outputnode.fod", "inputnode.DWI")]), # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) # fmt: on if self.config.dilate_rois: # fmt: off flow.connect([( dilate_rois, track_flow, [("out_file", "inputnode.gm_registered")], )]) # fmt: on else: # fmt: off flow.connect([( inputnode, track_flow, [("roi_volumes", "inputnode.gm_registered")], )]) # fmt: on # fmt: off flow.connect([ ( inputnode, track_flow, [("act_5tt_registered", "inputnode.act_5tt_registered")], ), ( inputnode, track_flow, [("gmwmi_registered", "inputnode.gmwmi_registered")], ), ]) # fmt: on # fmt: off flow.connect([(track_flow, outputnode, [("outputnode.track_file", "track_file")])]) # fmt: on temp_node = pe.Node( interface=util.IdentityInterface(fields=["diffusion_model"]), name="diffusion_model", ) temp_node.inputs.diffusion_model = self.config.diffusion_model # fmt: off flow.connect([(temp_node, outputnode, [("diffusion_model", "diffusion_model")])])
def create_workflow(self, flow, inputnode, outputnode): """Create the stage worflow. Parameters ---------- flow : nipype.pipeline.engine.Workflow The nipype.pipeline.engine.Workflow instance of the Diffusion pipeline inputnode : nipype.interfaces.utility.IdentityInterface Identity interface describing the inputs of the stage outputnode : nipype.interfaces.utility.IdentityInterface Identity interface describing the outputs of the stage See Also -------- cmp.stages.diffusion.reconstruction.create_dipy_recon_flow cmp.stages.diffusion.reconstruction.create_mrtrix_recon_flow cmp.stages.diffusion.tracking.create_dipy_tracking_flow cmp.stages.diffusion.tracking.create_mrtrix_tracking_flow """ if self.config.dilate_rois: dilate_rois = pe.MapNode(interface=fsl.DilateImage(), iterfield=[ 'in_file'], name='dilate_rois') dilate_rois.inputs.operation = 'modal' if self.config.dilation_kernel == 'Box': kernel_size = 2 * self.config.dilation_radius + 1 dilate_rois.inputs.kernel_shape = 'boxv' dilate_rois.inputs.kernel_size = kernel_size else: extract_sizes = pe.Node( interface=ExtractImageVoxelSizes(), name='extract_sizes') flow.connect([ (inputnode, extract_sizes, [("diffusion", "in_file")]) ]) extract_sizes.run() print("Voxel sizes : ", extract_sizes.outputs.voxel_sizes) min_size = 100 for voxel_size in extract_sizes.outputs.voxel_sizes: if voxel_size < min_size: min_size = voxel_size print("voxel size (min): %g" % min_size) if self.config.dilation_kernel == 'Gauss': kernel_size = 2 * extract_sizes.outputs.voxel_sizes + 1 # FWHM criteria, i.e. sigma = FWHM / 2(sqrt(2ln(2))) sigma = kernel_size / 2.355 dilate_rois.inputs.kernel_shape = 'gauss' dilate_rois.inputs.kernel_size = sigma elif self.config.dilation_kernel == 'Sphere': radius = 0.5 * min_size + self.config.dilation_radius * min_size dilate_rois.inputs.kernel_shape = 'sphere' dilate_rois.inputs.kernel_size = radius flow.connect([ (inputnode, dilate_rois, [("roi_volumes", "in_file")]), (dilate_rois, outputnode, [("out_file", "roi_volumes")]) ]) else: flow.connect([ (inputnode, outputnode, [("roi_volumes", "roi_volumes")]) ]) if self.config.recon_processing_tool == 'Dipy': recon_flow = create_dipy_recon_flow(self.config.dipy_recon_config) flow.connect([ (inputnode, recon_flow, [ ('diffusion', 'inputnode.diffusion')]), (inputnode, recon_flow, [('bvals', 'inputnode.bvals')]), (inputnode, recon_flow, [('bvecs', 'inputnode.bvecs')]), (inputnode, recon_flow, [ ('diffusion', 'inputnode.diffusion_resampled')]), (inputnode, recon_flow, [ ('wm_mask_registered', 'inputnode.wm_mask_resampled')]), (inputnode, recon_flow, [ ('brain_mask_registered', 'inputnode.brain_mask_resampled')]), (recon_flow, outputnode, [("outputnode.FA", "FA")]), (recon_flow, outputnode, [("outputnode.MD", "ADC")]), (recon_flow, outputnode, [("outputnode.AD", "AD")]), (recon_flow, outputnode, [("outputnode.RD", "RD")]), (recon_flow, outputnode, [ ("outputnode.shore_maps", "shore_maps")]), (recon_flow, outputnode, [ ("outputnode.mapmri_maps", "mapmri_maps")]), ]) elif self.config.recon_processing_tool == 'MRtrix': # TODO modify nipype tensormetric interface to get AD and RD maps recon_flow = create_mrtrix_recon_flow( self.config.mrtrix_recon_config) flow.connect([ (inputnode, recon_flow, [ ('diffusion', 'inputnode.diffusion')]), (inputnode, recon_flow, [('grad', 'inputnode.grad')]), (inputnode, recon_flow, [ ('diffusion', 'inputnode.diffusion_resampled')]), (inputnode, recon_flow, [ ('brain_mask_registered', 'inputnode.wm_mask_resampled')]), (recon_flow, outputnode, [("outputnode.FA", "FA")]), (recon_flow, outputnode, [("outputnode.ADC", "ADC")]), (recon_flow, outputnode, [("outputnode.tensor", "tensor")]), # (recon_flow,outputnode,[("outputnode.AD","AD")]), # (recon_flow,outputnode,[("outputnode.RD","RD")]), ]) if self.config.tracking_processing_tool == 'Dipy': track_flow = create_dipy_tracking_flow( self.config.dipy_tracking_config) # print "Dipy tracking" if self.config.diffusion_imaging_model != 'DSI': flow.connect([ (recon_flow, outputnode, [('outputnode.DWI', 'fod_file')]), (recon_flow, track_flow, [ ('outputnode.model', 'inputnode.model')]), (inputnode, track_flow, [('bvals', 'inputnode.bvals')]), (recon_flow, track_flow, [ ('outputnode.bvecs', 'inputnode.bvecs')]), # Diffusion resampled (inputnode, track_flow, [('diffusion', 'inputnode.DWI')]), (inputnode, track_flow, [ ('partial_volumes', 'inputnode.partial_volumes')]), (inputnode, track_flow, [ ('wm_mask_registered', 'inputnode.wm_mask_resampled')]), # (inputnode, track_flow,[('diffusion','inputnode.DWI')]), (recon_flow, track_flow, [ ("outputnode.FA", "inputnode.FA")]), (dilate_rois, track_flow, [ ('out_file', 'inputnode.gm_registered')]) # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) else: flow.connect([ (recon_flow, outputnode, [('outputnode.fod', 'fod_file')]), (recon_flow, track_flow, [ ('outputnode.fod', 'inputnode.fod_file')]), (recon_flow, track_flow, [ ('outputnode.model', 'inputnode.model')]), (inputnode, track_flow, [('bvals', 'inputnode.bvals')]), (recon_flow, track_flow, [ ('outputnode.bvecs', 'inputnode.bvecs')]), # Diffusion resampled (inputnode, track_flow, [('diffusion', 'inputnode.DWI')]), (inputnode, track_flow, [ ('partial_volumes', 'inputnode.partial_volumes')]), (inputnode, track_flow, [ ('wm_mask_registered', 'inputnode.wm_mask_resampled')]), # (inputnode, track_flow,[('diffusion','inputnode.DWI')]), (recon_flow, track_flow, [ ("outputnode.FA", "inputnode.FA")]), (dilate_rois, track_flow, [ ('out_file', 'inputnode.gm_registered')]) # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) if self.config.dipy_tracking_config.use_act and self.config.dipy_tracking_config.seed_from_gmwmi: flow.connect([ (inputnode, track_flow, [ ('gmwmi_registered', 'inputnode.gmwmi_file')]), ]) flow.connect([ (track_flow, outputnode, [ ('outputnode.track_file', 'track_file')]) ]) elif self.config.tracking_processing_tool == 'MRtrix' and self.config.recon_processing_tool == 'MRtrix': track_flow = create_mrtrix_tracking_flow( self.config.mrtrix_tracking_config) flow.connect([ (inputnode, track_flow, [ ('wm_mask_registered', 'inputnode.wm_mask_resampled')]), (recon_flow, outputnode, [('outputnode.DWI', 'fod_file')]), (recon_flow, track_flow, [ ('outputnode.DWI', 'inputnode.DWI'), ('outputnode.grad', 'inputnode.grad')]), # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) if self.config.dilate_rois: flow.connect([ (dilate_rois, track_flow, [ ('out_file', 'inputnode.gm_registered')]) ]) else: flow.connect([ (inputnode, track_flow, [ ('roi_volumes', 'inputnode.gm_registered')]) ]) flow.connect([ (inputnode, track_flow, [ ('act_5tt_registered', 'inputnode.act_5tt_registered')]), (inputnode, track_flow, [ ('gmwmi_registered', 'inputnode.gmwmi_registered')]) ]) flow.connect([ (track_flow, outputnode, [ ('outputnode.track_file', 'track_file')]) ]) elif self.config.tracking_processing_tool == 'MRtrix' and self.config.recon_processing_tool == 'Dipy': track_flow = create_mrtrix_tracking_flow(self.config.mrtrix_tracking_config) if self.config.diffusion_imaging_model != 'DSI': flow.connect([ (inputnode, track_flow, [('wm_mask_registered', 'inputnode.wm_mask_resampled'), ('grad', 'inputnode.grad')]), (recon_flow, outputnode, [('outputnode.DWI', 'fod_file')]), (recon_flow, track_flow, [ ('outputnode.DWI', 'inputnode.DWI')]), # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) else: flow.connect([ (inputnode, track_flow, [('wm_mask_registered', 'inputnode.wm_mask_resampled'), ('grad', 'inputnode.grad')]), (recon_flow, outputnode, [('outputnode.fod', 'fod_file')]), (recon_flow, track_flow, [ ('outputnode.fod', 'inputnode.DWI')]), # (recon_flow, track_flow,[('outputnode.SD','inputnode.SD')]), ]) if self.config.dilate_rois: flow.connect([ (dilate_rois, track_flow, [ ('out_file', 'inputnode.gm_registered')]) ]) else: flow.connect([ (inputnode, track_flow, [ ('roi_volumes', 'inputnode.gm_registered')]) ]) flow.connect([ (inputnode, track_flow, [ ('act_5tt_registered', 'inputnode.act_5tt_registered')]), (inputnode, track_flow, [ ('gmwmi_registered', 'inputnode.gmwmi_registered')]) ]) # if self.config.diffusion_model == 'Probabilistic': # flow.connect([ # (dilate_rois,track_flow,[('out_file','inputnode.gm_registered')]), # ]) flow.connect([ (track_flow, outputnode, [ ('outputnode.track_file', 'track_file')]) ]) temp_node = pe.Node(interface=util.IdentityInterface( fields=["diffusion_model"]), name='diffusion_model') temp_node.inputs.diffusion_model = self.config.diffusion_model flow.connect([ (temp_node, outputnode, [("diffusion_model", "diffusion_model")]) ])
def run_workflow(): # ------------------ Specify variables ds_root = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) data_dir = ds_root output_dir = 'skull-stripped-pre-mc' working_dir = 'workingdirs/skull-strip-functionals' subject_list = ['eddy'] session_list = ['20170511'] # ------------------ Input Files infosource = Node(IdentityInterface(fields=[ 'subject_id', 'session_id', ]), name="infosource") infosource.iterables = [ ('session_id', session_list), ('subject_id', subject_list), ] # SelectFiles templates = { 'masks': 'transformed-manual-func-mask/sub-{subject_id}/ses-{session_id}/func/' # 'sub-{subject_id}_ses-{session_id}*run-01_bold_res-1x1x1' 'sub-{subject_id}_ses-{session_id}*_bold_res-1x1x1' '_transformedmask.nii.gz', 'functionals': # 'func_unwarp/sub-{subject_id}/ses-{session_id}/func/' 'resampled-isotropic-1mm/sub-{subject_id}/ses-{session_id}/func/' # 'sub-{subject_id}_ses-{session_id}*run-01_bold_res-1x1x1_preproc' 'sub-{subject_id}_ses-{session_id}*_bold_res-1x1x1_preproc' '.nii.gz', } inputfiles = Node(nio.SelectFiles(templates, base_directory=data_dir), name="input_files") # ------------------ Output Files # Datasink outputfiles = Node(nio.DataSink(base_directory=ds_root, container=output_dir, parameterization=True), name="output_files") # Use the following DataSink output substitutions outputfiles.inputs.substitutions = [ ('subject_id_', 'sub-'), ('session_id_', 'ses-'), ('/funcbrain/', '/'), ('_preproc_masked.nii.gz', '_brain.nii.gz'), ] # Put result into a BIDS-like format outputfiles.inputs.regexp_substitutions = [ (r'_ses-([a-zA-Z0-9]*)_sub-([a-zA-Z0-9]*)', r'sub-\2/ses-\1'), (r'_funcbrain[0-9]*/', r'func/'), ] # -------------------------------------------- Create Pipeline workflow = Workflow(name='transform_manual_func_mask', base_dir=os.path.join(ds_root, working_dir)) workflow.connect([(infosource, inputfiles, [ ('subject_id', 'subject_id'), ('session_id', 'session_id'), ])]) dilmask = MapNode(fsl.DilateImage( operation='mean', kernel_shape=('boxv'), kernel_size=7, ), iterfield=['in_file'], name='dilmask') workflow.connect(inputfiles, 'masks', dilmask, 'in_file') erode = MapNode(fsl.ErodeImage( kernel_shape=('boxv'), kernel_size=3, ), iterfield=['in_file'], name='erode') workflow.connect(dilmask, 'out_file', erode, 'in_file') funcbrain = MapNode(fsl.ApplyMask(), iterfield=['in_file', 'mask_file'], name='funcbrain') workflow.connect( erode, 'out_file', funcbrain, 'mask_file', ) workflow.connect( inputfiles, 'functionals', funcbrain, 'in_file', ) workflow.connect(funcbrain, 'out_file', outputfiles, 'funcbrain') workflow.stop_on_first_crash = True workflow.keep_inputs = True workflow.remove_unnecessary_outputs = False workflow.write_graph() workflow.run()
label_unmasked = Node(interface=IdentityInterface(fields=['label_unmasked']), name="label_unmasked") label_masked = Node(interface=IdentityInterface(fields=['label_masked']), name="label_masked") reference_region = Node( interface=CombineROIs(ROI_groupings=list(reference_ROI_grouping.values())), name="reference_region") reference_region_inferior = Node(interface=fsl.ImageMaths(op_string=' -mul '), name="reference_region_inferior") brainmask = Node(interface=fsl.ImageMaths(op_string=' -bin', suffix='_brainmask'), name='brainmask') dilate = Node(interface=fsl.DilateImage(operation='max', kernel_shape='box', kernel_size=3), name='dilate') difference = Node(interface=fsl.ImageMaths(op_string=' -sub ', suffix='_diff'), name='difference') difference_masked = Node(interface=fsl.ImageMaths(op_string=' -mul ', suffix='_mul'), name='difference_masked') add = Node(interface=fsl.ImageMaths(op_string=' -add ', suffix='_add'), name='add') multiply = Node(interface=fsl.ImageMaths(op_string=' -mul ', suffix='_mul'), name='multiply') pvc_labels = Node( interface=CombineROIs(ROI_groupings=list(pvc_ROI_groupings.values())), name="pvc_labels")
def main(data_dict, config_dict): print() # ~~~~~~ SET UP GLOBAL VARIABLES ~~~~~~ data_folder = data_dict['data folder'] data_list = data_dict['data list'] if len(data_list) != 0: parent_logger.info('MOSAICS main analysis beginning, please wait.') # # save directory save_dir_parent = str(data_dict['save_dir']) # dilate variable dilate = int(config_dict['dilate']) # smooth variable smooth = int(config_dict['smooth']) # MEP threshold MEP_thresh = int(config_dict['MEP_threshold']) # Grid spacing grid_spacing = int(data_dict['grid spacing']) file_atlas = str(config_dict['atlas']) # Initialize a list before our for loop so we can create a dataframe to # output for our results spreadsheet! results_column_names = [ 'Subject File Name', 'Muscle', 'Hotspot X', 'Hotspot Y', 'Hotspot Z', 'Max MEP', 'COM X', 'COM Y', 'COM Z', 'Map area (mm^2)', 'Map volume (mm^2 * mV)', 'SD Hotspot X', 'SD Hotspot Y', 'SD Hotspot Z', 'SD COM X', 'SD COM Y', 'SD COM Z', 'Coordinates Used', 'Dilation (mm)', 'Smoothing kernel (mm)', 'MEP threshold (%)' ] results_metrics_list = list() for subject in data_list: # ~~~~~~SET UP SUBJECT-SPECIFIC VARIABLES~~~~~~ # data_list constructed, and these variables determined, by mos_find_datasets.py # tag = subj name, stim_name = name of stimulation data (everything before .xls(x) extension), # structural = nii*, stim_data = xls* tag = subject[0] file_t1 = os.path.join(data_folder, subject[1]) file_nibs_map = os.path.join(data_folder, subject[2]) #save directory, including sub-directory for each subject save_dir = str(data_dict['save_dir'] + '/' + tag) # # Create output directory os.makedirs(save_dir, exist_ok=True) # ~~~~~~THINGS TO DO ONCE PER SUBJECT~~~~~~ parent_logger.info('') parent_logger.info('processing ' + tag + ', stim data: ' + file_nibs_map) # ~~~~~~LOAD DATA~~~~~~ # Read in a 1mm isotropic T1-weighted MRI .nii data_T1 = nib.load(file_t1) # ~~~~~~STRIP T1 image~~~~~~ # reminder, brainmask check = 0 if user does not provide their own brainmask and # MOSAICS is to devise its own (we use default BET settings) if data_dict['brainmask check'].get() == 0: # if and elif check if brainmask exists in data folder and save dir (in that order) # if it doesn't exist, run BET skullstripping if os.path.isfile( os.path.join(data_folder, tag + data_dict['brainmask suffix'])): ps_brainmask = os.path.abspath( os.path.join(data_folder, tag + data_dict['brainmask suffix'])) elif os.path.isfile( os.path.join(save_dir, tag + data_dict['brainmask suffix'])): ps_brainmask = os.path.abspath( os.path.join(save_dir, tag + data_dict['brainmask suffix'])) else: parent_logger.info('performing BET skull stripping') ps_brainmask = mos_skullstrip.main(tag, file_t1, data_folder, save_dir) elif data_dict['brainmask check'].get() == 1: # if and elif check if brainmask exists in data folder and save dir (in that order) # if it doesn't exist, run BET skullstripping if os.path.isfile( os.path.join(data_folder, tag + data_dict['brainmask suffix'])): ps_brainmask = os.path.abspath( os.path.join(data_folder, tag + data_dict['brainmask suffix'])) elif os.path.isfile( os.path.join(save_dir, tag + data_dict['brainmask suffix'])): ps_brainmask = os.path.abspath( os.path.join(save_dir, tag + data_dict['brainmask suffix'])) else: parent_logger.warning( 'supplied brainmask not found, creating our own.') parent_logger.info('performing BET skull stripping') ps_brainmask = mos_skullstrip.main(tag, file_t1, data_folder, save_dir) ##### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ##### ~~~~~~~~~~~~~~~~~~~ Muscle loop starts below here stim_dict = mos_load_data_multi_muscle.main(file_nibs_map) locs_dict = stim_dict['locs'] muscles_dict = stim_dict[ 'muscles'] # muscles_dict[0] = MEP data, [1] = responsive yes or no for muscle in muscles_dict: parent_logger.info('processing ' + muscle + ' data') # establish save file names PER MUSCLE file_grid = os.path.join(save_dir, tag + '_' + muscle + '_grid.nii.gz') file_samples = os.path.join( save_dir, tag + '_' + muscle + '_samples.nii.gz') file_responses = os.path.join( save_dir, tag + '_' + muscle + '_responses.nii.gz') # Noscale (below) is the initial heatmap, gets warped to standard space used file_heatmap_ps_initial = os.path.join( save_dir, tag + '_' + muscle + '_heatmap_initial.nii') # Nomask includes weighted MEP values for heatmap, and is masked by fsl.ApplyMask() on line ~237 file_heatmap_ps_weighted = os.path.join( save_dir, tag + '_' + muscle + '_heatmap_weighted.nii') # Below variable is used on line 236 file_heatmap_ps_final = os.path.join( save_dir, tag + '_' + muscle + '_heatmap.nii.gz') file_heatmap_sd = os.path.join( save_dir, tag + '_' + muscle + '_warped_heatmap.nii.gz') # ~~~~~~SET UP STIM DATA ARRAYS~~~~~~ # Create an array of zeroes equal to size of T1 image, to initialize our output images # What are these maps (below)? # - map_responses = MEP amplitude overlayed in an array the same size as the T1 image, dilated across 5 voxels # (so 5mm isotropic) in the script # - map_samples = the same as responses, but no dilation, so 1mm isotropic? # - map_grid = 'binary' mask, 0 or 99, which points had a stim? Originally # also points orthogonally adjacent to each stim point are 1 instead of 99. # the dict, map_outputs, contains the matrix arrays for each image #map_outputs = initialize_stim_arrays(data_T1, data_nibs_map, MEP_thresh) map_outputs = initialize_stim_arrays(data_T1, locs_dict, muscles_dict, muscle, MEP_thresh) map_grid = map_outputs['grid'] map_samples = map_outputs['samples'] map_responses = map_outputs['responses'] # ~~~~~~SAVE RESPONSE MAP SO WE CAN DILATE~~~~~~ # save_map(file_responses, map_responses, data_T1) save_map(file_samples, map_samples, data_T1) """ --- DEV NOTE --- Need to ensure that borders between MEPs are maintained, no values are overwritten if dilation is too large - if user inputs resolution in configure GUI, we can check if dilation is too large for the voxel size? """ # ~~~~~~RESLICE STRUCTURAL AND STIM IMAGES~~~~~~ # nibabel.processing.conform(data_T1) produces a 1mm isotropic, 256x256x256 image # above also reorients the image to RAS which is something I guess. # - Not implemented yet. Helen has notes in Slack I have not read yet. # ~~~~~~DILATE STIMULATION DATA (MAP_RESPONSES)~~~~~~ parent_logger.info('dilating stimulation coordinates by ' + str(config_dict['dilate']) + ' voxels') if not os.path.isfile(file_responses): map_responses_dilate = fsl.DilateImage() map_responses_dilate.inputs.in_file = file_samples map_responses_dilate.inputs.operation = 'max' map_responses_dilate.inputs.kernel_shape = 'sphere' map_responses_dilate.inputs.kernel_size = dilate map_responses_dilate.inputs.out_file = file_responses map_responses_temp = map_responses_dilate.run() else: parent_logger.info( 'dilation already done, skipping this step') # Re-load the responses map, to receive the dilated version of the map map_responses = nib.load(file_responses).get_fdata() # ~~~~~~FLIP MAPS ANTERIOR/POSTERIOR IF BRAINSIGHT COORDINATES USED~~~~~~ # Rotate matrices in the y dimension (AP) to convert from RPS (Brainsight) to RAS (Nifti) # RPS = +x is right, +y is posterior, +z is superior # RAS = +x is right, +y is anterior, +z is superior if data_dict['stim_coords'].get() == "Brainsight": parent_logger.info( 'flipping coordinates of stimulations along anterior-posterior axis' ) map_responses = np.flip(map_responses, 1) map_samples = np.flip(map_samples, 1) map_grid = np.flip(map_grid, 1) # ~~~~~~PRODUCE HEATMAP~~~~~~ # Smooth the hotspot map using a 3D Gaussian # Interestingly, FWHM = 2.355 * s.d. for Gaussian distribution, so divide smooth by 2.355 to get s.d. parent_logger.info('producing heatmap of responsive sites') stdev_gaussian = smooth / 2.355 map_heatmap_ps_initial = ndi.gaussian_filter(map_responses, stdev_gaussian, 0, mode='reflect') # ~~~~~~WEIGHT MEPs~~~~~~ parent_logger.info('normalizing response map (by hotspot MEP)') MEP_ps_max, map_responses_weighted, map_heatmap_ps_weighted =\ normalize_ps_heatmap(map_heatmap_ps_initial, map_samples, map_responses) # ~~~~~~SAVE PATIENT SPACE FILES~~~~~~ # Stimulations: MEP amplitudes within a matrix sized to match structural image. # Stimulations from experiment have been uniformaly dilated by the 'dilate' integer. # Heatmap: Stimulations map with a gaussian filter applied to smooth the data parent_logger.info( 'saving stimulation sites (grid), responsive sites (responses), and heatmap (heatmap)' ) save_map(file_grid, map_grid, data_T1) save_map(file_responses, map_responses_weighted, data_T1) save_map(file_heatmap_ps_initial, map_heatmap_ps_initial, data_T1) save_map(file_heatmap_ps_weighted, map_heatmap_ps_weighted, data_T1) # remove samples map as we don't actually want the users to see it, only useful for development if os.path.exists(file_samples): os.remove(file_samples) # ~~~~~~MASK HEATMAP MAPS IN PATIENT SPACE~~~~~~ # Heatmap: apply brain mask to limit smoothing into skull / scalp # native space mask application parent_logger.info( 'applying brainmask to patient-space heatmap') mask_heatmap(file_heatmap_ps_weighted, ps_brainmask, file_heatmap_ps_final) # ~~~~~~CALCULATE METRICS (patient space)~~~~~~ # load back in masked heatmap to calculate metrics map_heatmap_masked = nib.load( file_heatmap_ps_final).get_fdata() # HOTSPOT: # raw MEP from the stim data, and smoothed (post-Gaussian filter), needed to normalize patient heatmap results_ps_hotspot = np.unravel_index( np.argmax(map_heatmap_masked), map_heatmap_masked.shape) # CENTER OF MASS: # convenient method from scipy / ndimage (imported as ndi) results_ps_center_mass = ndi.measurements.center_of_mass( map_heatmap_masked) # MAP AREA: #number of spots where a responsive MEP was observed nonzero_responses = np.count_nonzero(map_samples) ps_map_area = nonzero_responses * (grid_spacing**2) # MAP VOLUME: ps_map_volume = 0 # for all non-zero values (non-zero MEPs) in our array of mapped regions for i in map_samples[np.nonzero(map_samples)]: ps_map_volume = ps_map_volume + (i * (grid_spacing**2)) # ~~~~~~REPEAT RELEVANT STEPS IF DATA NORMALIZED~~~~~~ # Note this has to come after saving the initial files, as warps are applied to the heatmap if config_dict['normalize'].get() == 1: parent_logger.info( 'normalizing heatmap to standard space (SD)') # -- register and establish name of the warped map, for functions below parent_logger.info('atlas chosen: ' + file_atlas) mos_warp_to_mni.main(tag, muscle, data_folder, save_dir, file_t1, file_heatmap_ps_weighted, file_atlas) # -- standard space mask application to heatmap parent_logger.info( 'applying brainmask to standard-space heatmap') mask_heatmap(file_heatmap_sd, str(config_dict['atlas mask']), file_heatmap_sd) # -- load in normalized heatmap to calculate some metrics data_heatmap_warped = nib.load(file_heatmap_sd) map_heatmap_warped = data_heatmap_warped.get_fdata() # -- calculate standard space (sd) hotspot results_sd_hotspot = np.unravel_index( np.argmax(map_heatmap_warped), map_heatmap_warped.shape) MEP_sd_smoothed = map_heatmap_warped[results_sd_hotspot] # -- calculate standard space center of gravity results_sd_center_mass = ndi.measurements.center_of_mass( map_heatmap_warped) # Replace tuple with ## Probably don't need this unrounded tuple bit, no changes made # rounded_sd_center_mass = (results_sd_center_mass[0], # results_sd_center_mass[1], # results_sd_center_mass[2]) # results_sd_center_mass = (round(results_sd_center_mass[0]), # round(results_sd_center_mass[1]), # round(results_sd_center_mass[2])) # -- Convert standard space hotspot / COM from voxel coordinates to SD anatomical coords (mm) atlas_affine = nib.load(file_atlas) atlas_affine = atlas_affine.affine ## Hotspot results_sd_hotspot = apply_affine(atlas_affine, results_sd_hotspot) ## COM results_sd_center_mass = apply_affine( atlas_affine, results_sd_center_mass) rounded_sd_center_mass = list() rounded_sd_center_mass.append( round(results_sd_center_mass[0], 2)) rounded_sd_center_mass.append( round(results_sd_center_mass[1], 2)) rounded_sd_center_mass.append( round(results_sd_center_mass[2], 2)) # normalize MEPs / intensity values for standard space heatmap map_heatmap_sd_normal = (map_heatmap_warped / MEP_sd_smoothed) * 100 # Overwrite previously warped, masked heatmap with a new, weighted MEP version # parent_logger.info('weighting MEPs of standard-space heatmap') file_heatmap_sd_normal = os.path.join( save_dir, tag + '_warped_heatmap.nii.gz') nii_heatmap_sd_normal = nib.Nifti1Image( map_heatmap_sd_normal, data_heatmap_warped.affine) nib.save(nii_heatmap_sd_normal, file_heatmap_sd_normal) # standard space values are added to dict below, on line 292 else: # put n/a values in correct dict locations results_sd_hotspot = ('-', '-', '-') results_sd_center_mass = ('-', '-', '-') rounded_sd_center_mass = ('-', '-', '-') # ~~~~~~OUTPUT SUBJECT METRICS TO RESULTS SPREADSHEET~~~~~~ # Make a list of this subject's values, then append it to the overall results list # Variable order set on line 69 above (results_column_names): # Participant, Image File, Stim file, MEP threshold, Hotspot X, Y, Z, Hotspot MEP, COG X, Y, Z, # Standard hotspot X, Y, Z, Standard COG X, Y, Z measures_list = [ tag, muscle, results_ps_hotspot[0], results_ps_hotspot[1], results_ps_hotspot[2], MEP_ps_max, round(results_ps_center_mass[0], 2), round(results_ps_center_mass[1], 2), round(results_ps_center_mass[2], 2), ps_map_area, ps_map_volume, results_sd_hotspot[0], results_sd_hotspot[1], results_sd_hotspot[2], rounded_sd_center_mass[0], rounded_sd_center_mass[1], rounded_sd_center_mass[2], data_dict['stim_coords'].get(), str(dilate), str(smooth), str(MEP_thresh) ] results_metrics_list.append(measures_list) #clean up files, put into a separate function, see if that helps track everything file_cleanup(file_heatmap_ps_initial, file_heatmap_ps_weighted, save_dir, tag) parent_logger.info('analysis completed for ' + tag + ' ' + muscle) print() # ~~~~~~print values to spreadsheet after the loop has completed~~~~~~ metrics_dataframe = pd.DataFrame(results_metrics_list, columns=results_column_names) measures_file = os.path.join(save_dir_parent, 'mapping_results.xlsx') metrics_dataframe.to_excel(measures_file) parent_logger.info('MOSAICS main analysis completed successfully!') else: parent_logger.error( 'No subjects found for processing, MOSAICS processing not run')
def fsl_getmask(name): import nipype.interfaces.fsl as fsl import nipype.pipeline.engine as pe import nipype.interfaces.utility as niu wf = pe.Workflow(name=name) inputspec = pe.Node( niu.IdentityInterface(fields=['functional', 'structural']), name='inputspec') bet = pe.Node(fsl.BET(mask=True, remove_eyes=True), name='bet') flirt = pe.Node(fsl.FLIRT(dof=6), name='flirt') flirt_inv = flirt.clone('func2struct') applyxfm_mask = pe.Node(fsl.ApplyXfm(interp='nearestneighbour', apply_xfm=True), name='applyxfm_mask') applyxfm_seg = pe.MapNode(fsl.ApplyXfm(interp='nearestneighbour', apply_xfm=True), name='applyxfm_seg', iterfield=['in_file']) dilate = pe.Node(fsl.DilateImage(operation='mean'), name='dilate') fast = pe.Node(fsl.FAST(), name='fast') outputspec = pe.Node(niu.IdentityInterface(fields=[ 'mask', 'reg_file', 'segments', 'warped_struct', 'bet_struct', 'inverse_reg' ]), name='outputspec') #create brain mask wf.connect(inputspec, "structural", bet, "in_file") # calculate transfor, struct --> func wf.connect(inputspec, "functional", flirt, "reference") wf.connect(inputspec, "structural", flirt, "in_file") wf.connect(flirt, 'out_matrix_file', outputspec, 'reg_file') wf.connect(flirt, 'out_file', outputspec, 'warped_struct') # Calculate inverse wf.connect(inputspec, "functional", flirt_inv, "in_file") wf.connect(inputspec, "structural", flirt_inv, "reference") wf.connect(flirt_inv, "out_matrix_file", outputspec, "inverse_reg") #dilate brain mask wf.connect(bet, "mask_file", dilate, "in_file") #transform mask to functional space wf.connect(dilate, "out_file", applyxfm_mask, "in_file") wf.connect(inputspec, "functional", applyxfm_mask, "reference") wf.connect(flirt, "out_matrix_file", applyxfm_mask, "in_matrix_file") wf.connect(applyxfm_mask, 'out_file', outputspec, 'mask') #segment with FAST wf.connect(bet, "out_file", fast, "in_files") wf.connect(bet, "out_file", outputspec, "bet_struct") #transform segments wf.connect(fast, "tissue_class_map", applyxfm_seg, "in_file") wf.connect(flirt, 'out_matrix_file', applyxfm_seg, "in_matrix_file") wf.connect(inputspec, "functional", applyxfm_seg, "reference") wf.connect(applyxfm_seg, "out_file", outputspec, "segments") return wf
def init_enhance_and_skullstrip_dwi_wf( name="enhance_and_skullstrip_dwi_wf", omp_nthreads=1 ): """ Enhance a *b0* reference and perform brain extraction. This workflow takes in a *b0* reference image and sharpens the histogram with the application of the N4 algorithm for removing the :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal mask. Steps of this workflow are: 1. Run ANTs' ``N4BiasFieldCorrection`` on the input dwi reference image and mask. 2. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 3. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image with the latest mask calculated in 3), then use AFNI's ``3dUnifize`` to *standardize* the T2* contrast distribution. 4. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 5. Calculate a final mask as the intersection of 2) and 4). 6. Apply final mask on the enhanced reference. Workflow Graph: .. workflow :: :graph2use: orig :simple_form: yes from dmriprep.workflows.dwi.util import init_enhance_and_skullstrip_dwi_wf wf = init_enhance_and_skullstrip_dwi_wf(omp_nthreads=1) .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053 Parameters ---------- name : str Name of workflow (default: ``enhance_and_skullstrip_dwi_wf``) omp_nthreads : int number of threads available to parallel nodes Inputs ------ in_file The *b0* reference (single volume) pre_mask initial mask Outputs ------- bias_corrected_file the ``in_file`` after `N4BiasFieldCorrection`_ skull_stripped_file the ``bias_corrected_file`` after skull-stripping mask_file mask of the skull-stripped input file out_report reportlet for the skull-stripping """ from niworkflows.interfaces.header import CopyXForm from niworkflows.interfaces.fixes import ( FixN4BiasFieldCorrection as N4BiasFieldCorrection, ) from niworkflows.interfaces.nibabel import ApplyMask workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=["in_file", "pre_mask"]), name="inputnode" ) outputnode = pe.Node( niu.IdentityInterface( fields=["mask_file", "skull_stripped_file", "bias_corrected_file"] ), name="outputnode", ) # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1) n4_correct = pe.Node( N4BiasFieldCorrection( dimension=3, copy_header=True, bspline_fitting_distance=200 ), shrink_factor=2, name="n4_correct", n_procs=1, ) n4_correct.inputs.rescale_intensities = True # Create a generous BET mask out of the bias-corrected EPI skullstrip_first_pass = pe.Node( fsl.BET(frac=0.2, mask=True), name="skullstrip_first_pass" ) bet_dilate = pe.Node( fsl.DilateImage( operation="max", kernel_shape="sphere", kernel_size=6.0, internal_datatype="char", ), name="skullstrip_first_dilate", ) bet_mask = pe.Node(fsl.ApplyMask(), name="skullstrip_first_mask") # Use AFNI's unifize for T2 contrast & fix header unifize = pe.Node( afni.Unifize( t2=True, outputtype="NIFTI_GZ", args="-clfrac 0.2 -rbt 18.3 65.0 90.0", out_file="uni.nii.gz", ), name="unifize", ) fixhdr_unifize = pe.Node(CopyXForm(), name="fixhdr_unifize", mem_gb=0.1) # Run AFNI's 3dAutomask to extract a refined brain mask skullstrip_second_pass = pe.Node( afni.Automask(dilate=1, outputtype="NIFTI_GZ"), name="skullstrip_second_pass" ) fixhdr_skullstrip2 = pe.Node(CopyXForm(), name="fixhdr_skullstrip2", mem_gb=0.1) # Take intersection of both masks combine_masks = pe.Node(fsl.BinaryMaths(operation="mul"), name="combine_masks") normalize = pe.Node(niu.Function(function=_normalize), name="normalize") # Compute masked brain apply_mask = pe.Node(ApplyMask(), name="apply_mask") # fmt:off workflow.connect([ (inputnode, n4_correct, [("in_file", "input_image"), ("pre_mask", "mask_image")]), (inputnode, fixhdr_unifize, [("in_file", "hdr_file")]), (inputnode, fixhdr_skullstrip2, [("in_file", "hdr_file")]), (n4_correct, skullstrip_first_pass, [("output_image", "in_file")]), (skullstrip_first_pass, bet_dilate, [("mask_file", "in_file")]), (bet_dilate, bet_mask, [("out_file", "mask_file")]), (skullstrip_first_pass, bet_mask, [("out_file", "in_file")]), (bet_mask, unifize, [("out_file", "in_file")]), (unifize, fixhdr_unifize, [("out_file", "in_file")]), (fixhdr_unifize, skullstrip_second_pass, [("out_file", "in_file")]), (skullstrip_first_pass, combine_masks, [("mask_file", "in_file")]), (skullstrip_second_pass, fixhdr_skullstrip2, [("out_file", "in_file")]), (fixhdr_skullstrip2, combine_masks, [("out_file", "operand_file")]), (combine_masks, apply_mask, [("out_file", "in_mask")]), (combine_masks, outputnode, [("out_file", "mask_file")]), (n4_correct, normalize, [("output_image", "in_file")]), (normalize, apply_mask, [("out", "in_file")]), (normalize, outputnode, [("out", "bias_corrected_file")]), (apply_mask, outputnode, [("out_file", "skull_stripped_file")]), ] ) # fmt:on return workflow
def init_enhance_and_skullstrip_bold_wf( brainmask_thresh=0.5, name="enhance_and_skullstrip_bold_wf", omp_nthreads=1, pre_mask=False, ): """ Enhance and run brain extraction on a BOLD EPI image. This workflow takes in a :abbr:`BOLD (blood-oxygen level-dependant)` :abbr:`fMRI (functional MRI)` average/summary (e.g., a reference image averaging non-steady-state timepoints), and sharpens the histogram with the application of the N4 algorithm for removing the :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal mask. Steps of this workflow are: 1. Calculate a tentative mask by registering (9-parameters) to *fMRIPrep*'s :abbr:`EPI (echo-planar imaging)` -*boldref* template, which is in MNI space. The tentative mask is obtained by resampling the MNI template's brainmask into *boldref*-space. 2. Binary dilation of the tentative mask with a sphere of 3mm diameter. 3. Run ANTs' ``N4BiasFieldCorrection`` on the input :abbr:`BOLD (blood-oxygen level-dependant)` average, using the mask generated in 1) instead of the internal Otsu thresholding. 4. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 5. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image with the latest mask calculated in 3), then use AFNI's ``3dUnifize`` to *standardize* the T2* contrast distribution. 6. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 7. Calculate a final mask as the intersection of 4) and 6). 8. Apply final mask on the enhanced reference. Step 1 can be skipped if the ``pre_mask`` argument is set to ``True`` and a tentative mask is passed in to the workflow throught the ``pre_mask`` Nipype input. Workflow graph .. workflow :: :graph2use: orig :simple_form: yes from niworkflows.func.util import init_enhance_and_skullstrip_bold_wf wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1) .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053 Parameters ---------- brainmask_thresh: :obj:`float` Lower threshold for the probabilistic brainmask to obtain the final binary mask (default: 0.5). name : str Name of workflow (default: ``enhance_and_skullstrip_bold_wf``) omp_nthreads : int number of threads available to parallel nodes pre_mask : bool Indicates whether the ``pre_mask`` input will be set (and thus, step 1 should be skipped). Inputs ------ in_file : str BOLD image (single volume) pre_mask : bool A tentative brain mask to initialize the workflow (requires ``pre_mask`` parameter set ``True``). Outputs ------- bias_corrected_file : str the ``in_file`` after `N4BiasFieldCorrection`_ skull_stripped_file : str the ``bias_corrected_file`` after skull-stripping mask_file : str mask of the skull-stripped input file out_report : str reportlet for the skull-stripping """ workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=["in_file", "pre_mask"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface( fields=["mask_file", "skull_stripped_file", "bias_corrected_file" ]), name="outputnode", ) # Dilate pre_mask pre_dilate = pe.Node( fsl.DilateImage( operation="max", kernel_shape="sphere", kernel_size=3.0, internal_datatype="char", ), name="pre_mask_dilate", ) # Ensure mask's header matches reference's check_hdr = pe.Node(MatchHeader(), name="check_hdr", run_without_submitting=True) # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1) n4_correct = pe.Node( N4BiasFieldCorrection(dimension=3, copy_header=True, bspline_fitting_distance=200), shrink_factor=2, name="n4_correct", n_procs=1, ) n4_correct.inputs.rescale_intensities = True # Create a generous BET mask out of the bias-corrected EPI skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name="skullstrip_first_pass") bet_dilate = pe.Node( fsl.DilateImage( operation="max", kernel_shape="sphere", kernel_size=6.0, internal_datatype="char", ), name="skullstrip_first_dilate", ) bet_mask = pe.Node(fsl.ApplyMask(), name="skullstrip_first_mask") # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( afni.Unifize( t2=True, outputtype="NIFTI_GZ", # Default -clfrac is 0.1, 0.4 was too conservative # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation) args="-clfrac 0.2 -rbt 18.3 65.0 90.0", out_file="uni.nii.gz", ), name="unifize", ) fixhdr_unifize = pe.Node(CopyXForm(), name="fixhdr_unifize", mem_gb=0.1) # Run ANFI's 3dAutomask to extract a refined brain mask skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype="NIFTI_GZ"), name="skullstrip_second_pass") fixhdr_skullstrip2 = pe.Node(CopyXForm(), name="fixhdr_skullstrip2", mem_gb=0.1) # Take intersection of both masks combine_masks = pe.Node(fsl.BinaryMaths(operation="mul"), name="combine_masks") # Compute masked brain apply_mask = pe.Node(fsl.ApplyMask(), name="apply_mask") if not pre_mask: from ..interfaces.nibabel import Binarize bold_template = get_template("MNI152NLin2009cAsym", resolution=2, desc="fMRIPrep", suffix="boldref") brain_mask = get_template("MNI152NLin2009cAsym", resolution=2, desc="brain", suffix="mask") # Initialize transforms with antsAI init_aff = pe.Node( AI( fixed_image=str(bold_template), fixed_image_mask=str(brain_mask), metric=("Mattes", 32, "Regular", 0.2), transform=("Affine", 0.1), search_factor=(20, 0.12), principal_axes=False, convergence=(10, 1e-6, 10), verbose=True, ), name="init_aff", n_procs=omp_nthreads, ) # Registration().version may be None if parseversion(Registration().version or "0.0.0") > Version("2.2.0"): init_aff.inputs.search_grid = (40, (0, 40, 40)) # Set up spatial normalization norm = pe.Node( Registration(from_file=pkgr_fn("niworkflows.data", "epi_atlasbased_brainmask.json")), name="norm", n_procs=omp_nthreads, ) norm.inputs.fixed_image = str(bold_template) map_brainmask = pe.Node( ApplyTransforms( interpolation="BSpline", float=True, # Use the higher resolution and probseg for numerical stability in rounding input_image=str( get_template( "MNI152NLin2009cAsym", resolution=1, label="brain", suffix="probseg", )), ), name="map_brainmask", ) binarize_mask = pe.Node(Binarize(thresh_low=brainmask_thresh), name="binarize_mask") # fmt: off workflow.connect([ (inputnode, init_aff, [("in_file", "moving_image")]), (inputnode, map_brainmask, [("in_file", "reference_image")]), (inputnode, norm, [("in_file", "moving_image")]), (init_aff, norm, [("output_transform", "initial_moving_transform") ]), (norm, map_brainmask, [ ("reverse_invert_flags", "invert_transform_flags"), ("reverse_transforms", "transforms"), ]), (map_brainmask, binarize_mask, [("output_image", "in_file")]), (binarize_mask, pre_dilate, [("out_mask", "in_file")]), ]) # fmt: on else: # fmt: off workflow.connect([ (inputnode, pre_dilate, [("pre_mask", "in_file")]), ]) # fmt: on # fmt: off workflow.connect([ (inputnode, check_hdr, [("in_file", "reference")]), (pre_dilate, check_hdr, [("out_file", "in_file")]), (check_hdr, n4_correct, [("out_file", "mask_image")]), (inputnode, n4_correct, [("in_file", "input_image")]), (inputnode, fixhdr_unifize, [("in_file", "hdr_file")]), (inputnode, fixhdr_skullstrip2, [("in_file", "hdr_file")]), (n4_correct, skullstrip_first_pass, [("output_image", "in_file")]), (skullstrip_first_pass, bet_dilate, [("mask_file", "in_file")]), (bet_dilate, bet_mask, [("out_file", "mask_file")]), (skullstrip_first_pass, bet_mask, [("out_file", "in_file")]), (bet_mask, unifize, [("out_file", "in_file")]), (unifize, fixhdr_unifize, [("out_file", "in_file")]), (fixhdr_unifize, skullstrip_second_pass, [("out_file", "in_file")]), (skullstrip_first_pass, combine_masks, [("mask_file", "in_file")]), (skullstrip_second_pass, fixhdr_skullstrip2, [("out_file", "in_file") ]), (fixhdr_skullstrip2, combine_masks, [("out_file", "operand_file")]), (fixhdr_unifize, apply_mask, [("out_file", "in_file")]), (combine_masks, apply_mask, [("out_file", "mask_file")]), (combine_masks, outputnode, [("out_file", "mask_file")]), (apply_mask, outputnode, [("out_file", "skull_stripped_file")]), (n4_correct, outputnode, [("output_image", "bias_corrected_file")]), ]) # fmt: on return workflow
def init_enhance_and_skullstrip_asl_wf( brainmask_thresh=0.5, name="enhance_and_skullstrip_asl_wf", omp_nthreads=1, pre_mask=False, ): """ Enhance and run brain extraction on a ASL image. This workflow takes in a :abbr:`ASL (Aretrrail Spin Labeling)` average/summary (e.g., a reference image averaging non-steady-state timepoints), and sharpens the histogram with the application of the N4 algorithm for removing the :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal mask. Steps of this workflow are: 1. Calculate a tentative mask by registering (9-parameters) to *fMRIPrep*'s :abbr:`EPI (echo-planar imaging)` -*aslref* template, which is in MNI space. The tentative mask is obtained by resampling the MNI template's brainmask into *aslref*-space. 2. Binary dilation of the tentative mask with a sphere of 3mm diameter. 3. Run ANTs' ``N4BiasFieldCorrection`` on the input :abbr:`ASL (arterial spin labeling)` average, using the mask generated in 1) instead of the internal Otsu thresholding. 4. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 5. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image with the latest mask calculated in 3), then use AFNI's ``3dUnifize`` to *standardize* the T2* contrast distribution. 6. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 7. Calculate a final mask as the intersection of 4) and 6). 8. Apply final mask on the enhanced reference. Step 1 can be skipped if the ``pre_mask`` argument is set to ``True`` and a tentative mask is passed in to the workflow throught the ``pre_mask`` Nipype input. Workflow graph .. workflow :: :graph2use: orig :simple_form: yes from niworkflows.func.util import init_enhance_and_skullstrip_asl_wf wf = init_enhance_and_skullstrip_asl_wf(omp_nthreads=1) .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053 Parameters ---------- brainmask_thresh: :obj:`float` Lower threshold for the probabilistic brainmask to obtain the final binary mask (default: 0.5). name : str Name of workflow (default: ``enhance_and_skullstrip_asl_wf``) omp_nthreads : int number of threads available to parallel nodes pre_mask : bool Indicates whether the ``pre_mask`` input will be set (and thus, step 1 should be skipped). Inputs ------ in_file : str ASL image (single volume) pre_mask : bool A tentative brain mask to initialize the workflow (requires ``pre_mask`` parameter set ``True``). Outputs ------- bias_corrected_file : str the ``in_file`` after `N4BiasFieldCorrection`_ skull_stripped_file : str the ``bias_corrected_file`` after skull-stripping mask_file : str mask of the skull-stripped input file out_report : str reportlet for the skull-stripping """ workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=["in_file", "pre_mask"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface( fields=["mask_file", "skull_stripped_file", "bias_corrected_file" ]), name="outputnode", ) pre_mask = pre_mask # Ensure mask's header matches reference's #check_hdr = pe.Node(MatchHeader(), name="check_hdr", run_without_submitting=True) # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1) n4_correct = pe.Node( N4BiasFieldCorrection(dimension=3, copy_header=True, bspline_fitting_distance=200), shrink_factor=2, name="n4_correct", n_procs=1, ) n4_correct.inputs.rescale_intensities = True # Create a generous BET mask out of the bias-corrected EPI skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name="skullstrip_first_pass") bet_dilate = pe.Node( fsl.DilateImage( operation="max", kernel_shape="sphere", kernel_size=6.0, internal_datatype="char", ), name="skullstrip_first_dilate", ) bet_mask = pe.Node(fsl.ApplyMask(), name="skullstrip_first_mask") # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( afni.Unifize( t2=True, outputtype="NIFTI_GZ", # Default -clfrac is 0.1, 0.4 was too conservative # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation) args="-clfrac 0.2 -rbt 18.3 65.0 90.0", out_file="uni.nii.gz", ), name="unifize", ) fixhdr_unifize = pe.Node(CopyXForm(), name="fixhdr_unifize", mem_gb=0.1) # Run ANFI's 3dAutomask to extract a refined brain mask skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype="NIFTI_GZ"), name="skullstrip_second_pass") fixhdr_skullstrip2 = pe.Node(CopyXForm(), name="fixhdr_skullstrip2", mem_gb=0.1) # Take intersection of both masks combine_masks = pe.Node(fsl.BinaryMaths(operation="mul"), name="combine_masks") # Compute masked brain apply_mask = pe.Node(fsl.ApplyMask(), name="apply_mask") #binarize_mask = pe.Node(Binarize(thresh_low=brainmask_thresh), name="binarize_mask") # fmt: off workflow.connect([ (inputnode, n4_correct, [("in_file", "mask_image")]), (inputnode, n4_correct, [("in_file", "input_image")]), (inputnode, fixhdr_unifize, [("in_file", "hdr_file")]), (inputnode, fixhdr_skullstrip2, [("in_file", "hdr_file")]), (n4_correct, skullstrip_first_pass, [("output_image", "in_file")]), (skullstrip_first_pass, bet_dilate, [("mask_file", "in_file")]), (bet_dilate, bet_mask, [("out_file", "mask_file")]), (skullstrip_first_pass, bet_mask, [("out_file", "in_file")]), (bet_mask, unifize, [("out_file", "in_file")]), (unifize, fixhdr_unifize, [("out_file", "in_file")]), (fixhdr_unifize, skullstrip_second_pass, [("out_file", "in_file")]), (skullstrip_first_pass, combine_masks, [("mask_file", "in_file")]), (skullstrip_second_pass, fixhdr_skullstrip2, [("out_file", "in_file") ]), (fixhdr_skullstrip2, combine_masks, [("out_file", "operand_file")]), (fixhdr_unifize, apply_mask, [("out_file", "in_file")]), (combine_masks, apply_mask, [("out_file", "mask_file")]), (combine_masks, outputnode, [("out_file", "mask_file")]), (apply_mask, outputnode, [("out_file", "skull_stripped_file")]), (n4_correct, outputnode, [("output_image", "bias_corrected_file")]), ]) # fmt: on return workflow
def t1_freesurfer_pipeline(name='t1_preproc', use_T2=False): inputnode = pe.Node(utility.IdentityInterface( fields=['t1_files', 't2_file', 'subject_id']), run_without_submitting=True, name='inputspec') n_freesurfer = pe.Node( interface=freesurfer.ReconAll(directive='all', use_T2=use_T2), name='freesurfer', ) n_fs_seg2mask = pe.Node(utility.Function( input_names=['parc_file', 'out_file'], output_names=['out_file'], function=fs_seg2mask), name='fs_seg2mask') n_fs_seg2mask.inputs.out_file = 'mask.nii' n_autobox_mask_fs = pe.Node(afni.Autobox(padding=15, out_file='%s_crop.nii'), name='autobox_mask_fs') n_compute_pvmaps = pe.Node(freesurfer.utils.ComputeVolumeFractions( gm_file='pve.nii.gz', niigz=True, ), name='compute_pvmaps') n_crop_t1 = pe.Node(nipy.Crop(out_file='%s_crop.nii.gz', outputtype='NIFTI_GZ'), name='crop_t1') n_crop_brain = pe.Node(nipy.Crop(out_file='%s_crop.nii.gz', outputtype='NIFTI_GZ'), name='crop_brain') n_t1_nii = pe.Node(freesurfer.MRIConvert(out_type='niigz'), name='t1_nii') n_dilate_mask = pe.Node(fsl.DilateImage(operation='mean', kernel_shape='3D'), name='dilate_mask') n_reg_crop = pe.Node(freesurfer.Tkregister(reg_file='reg_crop.dat', freeview='freeview.mat', fsl_reg_out='fsl_reg_out.mat', lta_out='lta.mat', xfm_out='xfm.mat', reg_header=True), name='reg_crop') w = pe.Workflow(name=name) if (use_T2): w.connect([(inputnode, n_freesurfer, [ ('t2_file', 'T2_file'), ])]) w.connect([ (inputnode, n_freesurfer, [('t1_files', 'T1_files'), ('subject_id', 'subject_id')]), (n_freesurfer, n_fs_seg2mask, [(('aparc_aseg', utility.select, 1), 'parc_file')]), (n_fs_seg2mask, n_autobox_mask_fs, [('out_file', 'in_file')]), (n_autobox_mask_fs, n_dilate_mask, [('out_file', 'in_file')]), (n_autobox_mask_fs, n_crop_t1, [('%s_min' % c, ) * 2 for c in 'xyz'] + [(('%s_max' % c, wrap(operator.__add__), [1]), '%s_max' % c) for c in 'xyz']), # add 1 for boundary inclusive (n_freesurfer, n_crop_t1, [('T1', 'in_file')]), (n_autobox_mask_fs, n_crop_brain, [('%s_min' % c, ) * 2 for c in 'xyz'] + [(('%s_max' % c, wrap(operator.__add__), [1]), '%s_max' % c) for c in 'xyz']), # add 1 for boundary inclusive (n_freesurfer, n_crop_brain, [('norm', 'in_file')]), (n_freesurfer, n_t1_nii, [('T1', 'in_file')]), (n_freesurfer, n_reg_crop, [('norm', 'target'), ('subject_id', ) * 2, ('subjects_dir', ) * 2]), (n_autobox_mask_fs, n_reg_crop, [('out_file', 'mov')]), (n_reg_crop, n_compute_pvmaps, [('reg_file', ) * 2]), (n_autobox_mask_fs, n_compute_pvmaps, [('out_file', 'in_file')]), (n_freesurfer, n_compute_pvmaps, [('subjects_dir', ) * 2]) ]) return w
def create_old_segment_pipe(params_template, params={}, name="old_segment_pipe"): """ Description: Extract brain using tissues masks output by SPM's old_segment function: - Segment the T1 using given priors; - Threshold GM, WM and CSF maps; - Compute union of those 3 tissues; - Apply morphological opening on the union mask - Fill holes Inputs: inputnode: T1: T1 file name arguments: priors: list of file names params: dictionary of node sub-parameters (from a json file) name: pipeline name (default = "old_segment_pipe") Outputs: fill_holes.out_file: filled mask after erode fill_holes_dil.out_file filled mask after dilate threshold_gm, threshold_wm, threshold_csf.out_file: resp grey matter, white matter, and csf after thresholding """ # creating pipeline be_pipe = pe.Workflow(name=name) # Creating inputnode inputnode = pe.Node( niu.IdentityInterface(fields=['T1', 'indiv_params']), name='inputnode' ) # Segment in to 6 tissues segment = NodeParams(spm.Segment(), params=parse_key(params, "segment"), name="old_segment") segment.inputs.tissue_prob_maps = [params_template["template_gm"], params_template["template_wm"], params_template["template_csf"]] be_pipe.connect(inputnode, 'T1', segment, 'data') # Threshold GM, WM and CSF thd_nodes = {} for tissue in ['gm', 'wm', 'csf']: tmp_node = NodeParams(fsl.Threshold(), params=parse_key(params, "threshold_" + tissue), name="threshold_" + tissue) be_pipe.connect(segment, 'native_' + tissue + '_image', tmp_node, 'in_file') be_pipe.connect( inputnode, ('indiv_params', parse_key, "threshold_" + tissue), tmp_node, "indiv_params") thd_nodes[tissue] = tmp_node # Compute union of the 3 tissues # Done with 2 fslmaths as it seems to hard to do it wmgm_union = pe.Node(fsl.BinaryMaths(), name="wmgm_union") wmgm_union.inputs.operation = "add" be_pipe.connect(thd_nodes['gm'], 'out_file', wmgm_union, 'in_file') be_pipe.connect(thd_nodes['wm'], 'out_file', wmgm_union, 'operand_file') tissues_union = pe.Node(fsl.BinaryMaths(), name="tissues_union") tissues_union.inputs.operation = "add" be_pipe.connect(wmgm_union, 'out_file', tissues_union, 'in_file') be_pipe.connect(thd_nodes['csf'], 'out_file', tissues_union, 'operand_file') # Opening dilate_mask = NodeParams(fsl.DilateImage(), params=parse_key(params, "dilate_mask"), name="dilate_mask") dilate_mask.inputs.operation = "mean" # Arbitrary operation be_pipe.connect(tissues_union, 'out_file', dilate_mask, 'in_file') # Eroding mask erode_mask = NodeParams(fsl.ErodeImage(), params=parse_key(params, "erode_mask"), name="erode_mask") be_pipe.connect(tissues_union, 'out_file', erode_mask, 'in_file') # fill holes of erode_mask fill_holes = pe.Node(BinaryFillHoles(), name="fill_holes") be_pipe.connect(erode_mask, 'out_file', fill_holes, 'in_file') # fill holes of dilate_mask fill_holes_dil = pe.Node(BinaryFillHoles(), name="fill_holes_dil") be_pipe.connect(dilate_mask, 'out_file', fill_holes_dil, 'in_file') return be_pipe
def skullstrip_functional(tool='afni', wf_name='skullstrip_functional'): tool = tool.lower() if tool != 'afni' and tool != 'fsl' and tool != 'fsl_afni': raise Exception("\n\n[!] Error: The 'tool' parameter of the " "'skullstrip_functional' workflow must be either " "'afni' or 'fsl'.\n\nTool input: " "{0}\n\n".format(tool)) wf = pe.Workflow(name=wf_name) input_node = pe.Node(util.IdentityInterface(fields=['func']), name='inputspec') output_node = pe.Node( util.IdentityInterface(fields=['func_brain', 'func_brain_mask']), name='outputspec') if tool == 'afni': func_get_brain_mask = pe.Node(interface=preprocess.Automask(), name='func_get_brain_mask_AFNI') func_get_brain_mask.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_get_brain_mask, 'in_file') wf.connect(func_get_brain_mask, 'out_file', output_node, 'func_brain_mask') elif tool == 'fsl': func_get_brain_mask = pe.Node(interface=fsl.BET(), name='func_get_brain_mask_BET') func_get_brain_mask.inputs.mask = True func_get_brain_mask.inputs.functional = True erode_one_voxel = pe.Node(interface=fsl.ErodeImage(), name='erode_one_voxel') erode_one_voxel.inputs.kernel_shape = 'box' erode_one_voxel.inputs.kernel_size = 1.0 wf.connect(input_node, 'func', func_get_brain_mask, 'in_file') wf.connect(func_get_brain_mask, 'mask_file', erode_one_voxel, 'in_file') wf.connect(erode_one_voxel, 'out_file', output_node, 'func_brain_mask') elif tool == 'fsl_afni': skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True, functional=True), name='skullstrip_first_pass') bet_dilate = pe.Node(fsl.DilateImage(operation='max', kernel_shape='sphere', kernel_size=6.0, internal_datatype='char'), name='skullstrip_first_dilate') bet_mask = pe.Node(fsl.ApplyMask(), name='skullstrip_first_mask') unifize = pe.Node(afni_utils.Unifize( t2=True, outputtype='NIFTI_GZ', args='-clfrac 0.2 -rbt 18.3 65.0 90.0', out_file="uni.nii.gz"), name='unifize') skullstrip_second_pass = pe.Node(preprocess.Automask( dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') wf.connect([ (input_node, skullstrip_first_pass, [('func', 'in_file')]), (skullstrip_first_pass, bet_dilate, [('mask_file', 'in_file')]), (bet_dilate, bet_mask, [('out_file', 'mask_file')]), (skullstrip_first_pass, bet_mask, [('out_file', 'in_file')]), (bet_mask, unifize, [('out_file', 'in_file')]), (unifize, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, combine_masks, [('out_file', 'operand_file')]), (combine_masks, output_node, [('out_file', 'func_brain_mask')]) ]) func_edge_detect = pe.Node(interface=afni_utils.Calc(), name='func_extract_brain') func_edge_detect.inputs.expr = 'a*b' func_edge_detect.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_edge_detect, 'in_file_a') if tool == 'afni': wf.connect(func_get_brain_mask, 'out_file', func_edge_detect, 'in_file_b') elif tool == 'fsl': wf.connect(erode_one_voxel, 'out_file', func_edge_detect, 'in_file_b') elif tool == 'fsl_afni': wf.connect(combine_masks, 'out_file', func_edge_detect, 'in_file_b') wf.connect(func_edge_detect, 'out_file', output_node, 'func_brain') return wf
def init_enhance_and_skullstrip_bold_wf(name='enhance_and_skullstrip_bold_wf', pre_mask=False, omp_nthreads=1): """ This workflow takes in a :abbr:`BOLD (blood-oxygen level-dependant)` :abbr:`fMRI (functional MRI)` average/summary (e.g., a reference image averaging non-steady-state timepoints), and sharpens the histogram with the application of the N4 algorithm for removing the :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal mask. Steps of this workflow are: 1. Calculate a tentative mask by registering (9-parameters) to *fMRIPrep*'s :abbr:`EPI (echo-planar imaging)` -*boldref* template, which is in MNI space. The tentative mask is obtained by resampling the MNI template's brainmask into *boldref*-space. 2. Binary dilation of the tentative mask with a sphere of 3mm diameter. 3. Run ANTs' ``N4BiasFieldCorrection`` on the input :abbr:`BOLD (blood-oxygen level-dependant)` average, using the mask generated in 1) instead of the internal Otsu thresholding. 4. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 5. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image with the latest mask calculated in 3), then use AFNI's ``3dUnifize`` to *standardize* the T2* contrast distribution. 6. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 7. Calculate a final mask as the intersection of 4) and 6). 8. Apply final mask on the enhanced reference. Step 1 can be skipped if the ``pre_mask`` argument is set to ``True`` and a tentative mask is passed in to the workflow throught the ``pre_mask`` Nipype input. .. workflow :: :graph2use: orig :simple_form: yes from niworkflows.func.util import init_enhance_and_skullstrip_bold_wf wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1) **Parameters** name : str Name of workflow (default: ``enhance_and_skullstrip_bold_wf``) pre_mask : bool Indicates whether the ``pre_mask`` input will be set (and thus, step 1 should be skipped). omp_nthreads : int number of threads available to parallel nodes **Inputs** in_file BOLD image (single volume) pre_mask : bool A tentative brain mask to initialize the workflow (requires ``pre_mask`` parameter set ``True``). **Outputs** bias_corrected_file the ``in_file`` after `N4BiasFieldCorrection`_ skull_stripped_file the ``bias_corrected_file`` after skull-stripping mask_file mask of the skull-stripped input file out_report reportlet for the skull-stripping .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053 """ workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'pre_mask']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['mask_file', 'skull_stripped_file', 'bias_corrected_file']), name='outputnode') # Dilate pre_mask pre_dilate = pe.Node(fsl.DilateImage(operation='max', kernel_shape='sphere', kernel_size=3.0, internal_datatype='char'), name='pre_mask_dilate') # Ensure mask's header matches reference's check_hdr = pe.Node(MatchHeader(), name='check_hdr', run_without_submitting=True) # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1) n4_correct = pe.Node(ants.N4BiasFieldCorrection( dimension=3, copy_header=True, bspline_fitting_distance=200), name='n4_correct', n_procs=1) # Create a generous BET mask out of the bias-corrected EPI skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name='skullstrip_first_pass') bet_dilate = pe.Node(fsl.DilateImage(operation='max', kernel_shape='sphere', kernel_size=6.0, internal_datatype='char'), name='skullstrip_first_dilate') bet_mask = pe.Node(fsl.ApplyMask(), name='skullstrip_first_mask') # Use AFNI's unifize for T2 constrast & fix header unifize = pe.Node( afni.Unifize( t2=True, outputtype='NIFTI_GZ', # Default -clfrac is 0.1, 0.4 was too conservative # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation) args='-clfrac 0.2 -rbt 18.3 65.0 90.0', out_file="uni.nii.gz"), name='unifize') fixhdr_unifize = pe.Node(CopyXForm(), name='fixhdr_unifize', mem_gb=0.1) # Run ANFI's 3dAutomask to extract a refined brain mask skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') fixhdr_skullstrip2 = pe.Node(CopyXForm(), name='fixhdr_skullstrip2', mem_gb=0.1) # Take intersection of both masks combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') # Compute masked brain apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask') if not pre_mask: bold_template = get_template('MNI152NLin2009cAsym', resolution=2, desc='fMRIPrep', suffix='boldref') brain_mask = get_template('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='mask') # Initialize transforms with antsAI init_aff = pe.Node(AI(fixed_image=str(bold_template), fixed_image_mask=str(brain_mask), metric=('Mattes', 32, 'Regular', 0.2), transform=('Affine', 0.1), search_factor=(20, 0.12), principal_axes=False, convergence=(10, 1e-6, 10), verbose=True), name='init_aff', n_procs=omp_nthreads) # Registration().version may be None if parseversion(Registration().version or '0.0.0') > Version('2.2.0'): init_aff.inputs.search_grid = (40, (0, 40, 40)) # Set up spatial normalization norm = pe.Node(Registration(from_file=pkgr_fn( 'fmriprep.data', 'epi_atlasbased_brainmask.json')), name='norm', n_procs=omp_nthreads) norm.inputs.fixed_image = str(bold_template) map_brainmask = pe.Node(ApplyTransforms(interpolation='MultiLabel', float=True, input_image=str(brain_mask)), name='map_brainmask') workflow.connect([ (inputnode, init_aff, [('in_file', 'moving_image')]), (inputnode, map_brainmask, [('in_file', 'reference_image')]), (inputnode, norm, [('in_file', 'moving_image')]), (init_aff, norm, [('output_transform', 'initial_moving_transform') ]), (norm, map_brainmask, [('reverse_invert_flags', 'invert_transform_flags'), ('reverse_transforms', 'transforms')]), (map_brainmask, pre_dilate, [('output_image', 'in_file')]), ]) else: workflow.connect([ (inputnode, pre_dilate, [('pre_mask', 'in_file')]), ]) workflow.connect([ (inputnode, check_hdr, [('in_file', 'reference')]), (pre_dilate, check_hdr, [('out_file', 'in_file')]), (check_hdr, n4_correct, [('out_file', 'mask_image')]), (inputnode, n4_correct, [('in_file', 'input_image')]), (inputnode, fixhdr_unifize, [('in_file', 'hdr_file')]), (inputnode, fixhdr_skullstrip2, [('in_file', 'hdr_file')]), (n4_correct, skullstrip_first_pass, [('output_image', 'in_file')]), (skullstrip_first_pass, bet_dilate, [('mask_file', 'in_file')]), (bet_dilate, bet_mask, [('out_file', 'mask_file')]), (skullstrip_first_pass, bet_mask, [('out_file', 'in_file')]), (bet_mask, unifize, [('out_file', 'in_file')]), (unifize, fixhdr_unifize, [('out_file', 'in_file')]), (fixhdr_unifize, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, fixhdr_skullstrip2, [('out_file', 'in_file') ]), (fixhdr_skullstrip2, combine_masks, [('out_file', 'operand_file')]), (fixhdr_unifize, apply_mask, [('out_file', 'in_file')]), (combine_masks, apply_mask, [('out_file', 'mask_file')]), (combine_masks, outputnode, [('out_file', 'mask_file')]), (apply_mask, outputnode, [('out_file', 'skull_stripped_file')]), (n4_correct, outputnode, [('output_image', 'bias_corrected_file')]), ]) return workflow
def prepare_template_wf(name="prepare_template"): wf = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['tpl_t1w', 'tpl_t1w_brainmask', 'CSF_pve']), name='inputnode') tpl_t1w_brain = pe.Node(fsl.ApplyMask(), name='tpl_t1w_brain') wf.connect(inputnode, "tpl_t1w", tpl_t1w_brain, "in_file") wf.connect(inputnode, "tpl_t1w_brainmask", tpl_t1w_brain, "mask_file") norm_wf = get_norm_wf() wf.connect(inputnode, 'tpl_t1w', norm_wf, "inputnode.t1w") wf.connect(tpl_t1w_brain, 'out_file', norm_wf, "inputnode.t1w_brain") MNI_2_t1w_warp = pe.Node(fsl.InvWarp(), name='MNI_2_t1w_warp') wf.connect(inputnode, 'tpl_t1w', MNI_2_t1w_warp, 'reference') wf.connect(norm_wf, 'outputnode.t1w_2_MNI_warp', MNI_2_t1w_warp, 'warp') bianca_mask = pe.Node(MakeBiancaMask(), name='bianca_mask') bianca_mask.inputs.keep_intermediate_files = 0 wf.connect(inputnode, 'tpl_t1w', bianca_mask, 'structural_image') wf.connect(inputnode, 'CSF_pve', bianca_mask, 'CSF_pve') wf.connect(MNI_2_t1w_warp, 'inverse_warp', bianca_mask, 'warp_file_MNI2structural') wf.connect(tpl_t1w_brain, 'out_file', bianca_mask, 'structural_image_brainextracted') wf.connect(inputnode, 'tpl_t1w_brainmask', bianca_mask, 'brainmask') # distancemap # dilate for distancemap to avoid rim effects when resampling distancemap brainmask_dil = pe.Node(fsl.DilateImage(operation="max"), name="brainmask_dil") wf.connect(inputnode, 'tpl_t1w_brainmask', brainmask_dil, "in_file") distancemap = pe.Node(fsl.DistanceMap(), name="distancemap") wf.connect(bianca_mask, 'vent_file', distancemap, "in_file") wf.connect(brainmask_dil, 'out_file', distancemap, "mask_file") perivent_mask_init = pe.Node(fsl.maths.MathsCommand(), name="perivent_mask_init") perivent_mask_init.inputs.args = "-uthr 10 -bin" wf.connect(distancemap, "distance_map", perivent_mask_init, "in_file") perivent_mask = pe.Node(fsl.ApplyMask(), name="perivent_mask") wf.connect(perivent_mask_init, "out_file", perivent_mask, "in_file") wf.connect(inputnode, "tpl_t1w_brainmask", perivent_mask, "mask_file") deepWM_mask_init = pe.Node(fsl.maths.MathsCommand(), name="deepWM_mask_init") deepWM_mask_init.inputs.args = "-thr 10 -bin" wf.connect(distancemap, "distance_map", deepWM_mask_init, "in_file") deepWM_mask = pe.Node(fsl.ApplyMask(), name="deepWM_mask") wf.connect(deepWM_mask_init, "out_file", deepWM_mask, "in_file") wf.connect(inputnode, "tpl_t1w_brainmask", deepWM_mask, "mask_file") outputnode = pe.Node(niu.IdentityInterface(fields=[ "t1w_2_MNI_mat", "t1w_MNIspace", "t1w_2_MNI_warp", "bianca_wm_mask_file", "vent_file", "distance_map", "perivent_mask", "deepWM_mask" ]), name='outputnode') wf.connect(norm_wf, 'outputnode.t1w_2_MNI_mat', outputnode, "t1w_2_MNI_mat") wf.connect(norm_wf, 'outputnode.t1w_MNIspace', outputnode, "t1w_MNIspace") wf.connect(norm_wf, 'outputnode.t1w_2_MNI_warp', outputnode, "t1w_2_MNI_warp") wf.connect(bianca_mask, 'mask_file', outputnode, "bianca_wm_mask_file") wf.connect(bianca_mask, 'vent_file', outputnode, "vent_file") wf.connect(distancemap, "distance_map", outputnode, "distance_map") wf.connect(perivent_mask, "out_file", outputnode, "perivent_mask") wf.connect(deepWM_mask, "out_file", outputnode, "deepWM_mask") return wf