Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
    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
Ejemplo n.º 4
0
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##
###############
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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'])
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
    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")])
                    ])
Ejemplo n.º 10
0
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'])
Ejemplo n.º 13
0
    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")])])
Ejemplo n.º 14
0
    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")])
        ])
Ejemplo n.º 15
0
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()
Ejemplo n.º 16
0
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")
Ejemplo n.º 17
0
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
Ejemplo n.º 19
0
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
Ejemplo n.º 20
0
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
Ejemplo n.º 21
0
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
Ejemplo n.º 22
0
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
Ejemplo n.º 23
0
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
Ejemplo n.º 24
0
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
Ejemplo n.º 25
0
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
Ejemplo n.º 26
0
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