Example #1
0
def warp_rois_gray_fs(name='warp_rois_gray_fs'):

    inputnode = pe.Node(
        utility.IdentityInterface(
            fields=['fmri_reference','seg','mni_reg','def_field',
                    'rois_files','t1_to_epi']),
        name='inputspec')

    outputnode = pe.Node(
        utility.IdentityInterface(
            fields=['t1_rois','t1_gray_rois','fmri_rois','min_nvox']),
        name='outputspec')
    
    n_mni_to_t1 = pe.MapNode(
        freesurfer.ApplyVolTransform(interp='nearest',
                                     no_def_m3z_path=True,
                                     inverse=True,invert_morph=True),
        iterfield = ['target_file','transformed_file'],
        name='mni_to_t1')

    n_restrict_to_gray_fs = pe.Node(
        utility.Function(input_names=['rois','seg','tissues'],
                         output_names=['masked_rois'],
                         function=restrict_to_gray_fs),
        name='restrict_to_gray_fs')
    n_restrict_to_gray_fs.inputs.min_nvox = 100
    n_restrict_to_gray_fs.inputs.tissues = [2,42,8,47,12,51,11,50,10,49,18,54,26,58]
    n_restrict_to_gray_fs.inputs.threshold = 1e-3

    n_t1_to_fmri = pe.MapNode(
        freesurfer.ApplyVolTransform(interp='nearest',inverse=True),
        iterfield=['target_file','transformed_file'],
        name='t1_to_fmri')

    w=pe.Workflow(name=name)
    w.connect([
            (inputnode,n_mni_to_t1,
             [('rois_files','target_file'),
              (('rois_files',fname_presuffix_basename,'','_native'),
               'transformed_file'),
              ('def_field','m3z_file'),
              ('mni_reg','reg_file'),
              ('seg','source_file')]),
            (inputnode,n_restrict_to_gray_fs,[('seg','seg')]),
            (n_mni_to_t1,n_restrict_to_gray_fs,[('transformed_file','rois')]),
            (n_restrict_to_gray_fs,n_t1_to_fmri,[
                    ('masked_rois','target_file'),
                    (('masked_rois',fname_presuffix_basename,'','_epi'),
                     'transformed_file'),]),
            (inputnode,n_t1_to_fmri,[('fmri_reference','source_file'),
                                     ('t1_to_epi','reg_file')]),
            (n_mni_to_t1,outputnode,[('transformed_file','t1_rois')]),
            (n_t1_to_fmri,outputnode,[('transformed_file','fmri_rois')]),
            (n_restrict_to_gray_fs,outputnode,[('masked_rois','t1_gray_rois')])
            ])
    return w
Example #2
0
    def _post_run_hook(self, runtime):
        outputs = self.aggregate_outputs(runtime=runtime)
        mri_dir = None
        if isdefined(self.inputs.subject_id):
            mri_dir = os.path.join(self.inputs.subjects_dir,
                                   self.inputs.subject_id, "mri")

        if isdefined(self.inputs.reference_file):
            target_file = self.inputs.reference_file
        else:
            target_file = os.path.join(mri_dir, "brainmask.mgz")

        # Apply transform for simplicity
        mri_vol2vol = fs.ApplyVolTransform(
            source_file=self.inputs.source_file,
            target_file=target_file,
            lta_file=outputs.out_lta_file,
            interp="nearest",
        )
        res = mri_vol2vol.run()

        self._fixed_image = target_file
        self._moving_image = res.outputs.transformed_file
        if mri_dir is not None:
            self._contour = os.path.join(mri_dir, "ribbon.mgz")
        NIWORKFLOWS_LOG.info(
            "Report - setting fixed (%s) and moving (%s) images",
            self._fixed_image,
            self._moving_image,
        )

        return super(MRICoregRPT, self)._post_run_hook(runtime)
Example #3
0
def epi_fs_coregister(name='epi_fs_coregister'):
    
    inputnode = pe.Node(
        utility.IdentityInterface(
            fields=['fmri','subject_id','subjects_dir',
                    'roi_file','mask_file']),
        name='inputspec')

    outputnode = pe.Node(
        utility.IdentityInterface(
            fields=['fmri_mask','fmri_rois','reg_file','fsl_reg_file']),
        name='outputspec')


    n_bbregister = pe.Node(
        freesurfer.BBRegister(init='fsl', contrast_type='t2',
                              out_fsl_file=True),
        name='bbregister')

    n_fsmask2epi = pe.Node(
        freesurfer.ApplyVolTransform(inverse=True, interp='nearest',
                                     transformed_file='mask_epi.nii.gz'),
        name='fsmask2epi')

    n_fsrois2epi = pe.Node(
        freesurfer.ApplyVolTransform(inverse=True, interp='nearest',
                                     transformed_file='epi_aparc.aseg.nii.gz'),
        name='fsrois2epi')
    w=pe.Workflow(name=name)
    w.connect([
            (inputnode, n_bbregister,[('fmri','source_file'),
                                      ('subjects_dir','subjects_dir'),
                                      ('subject_id','subject_id')]),
            (n_bbregister, n_fsrois2epi,[('out_reg_file','reg_file')]),
            (inputnode, n_fsrois2epi, [('fmri','source_file'),
                                       ('roi_file','target_file')]),
            (n_bbregister, n_fsmask2epi,[('out_reg_file','reg_file')]),
            (inputnode, n_fsmask2epi, [('fmri','source_file'),
                                       ('mask_file','target_file')]),
            (n_bbregister, outputnode,[('out_reg_file','reg_file')]),
            (n_bbregister, outputnode,[('out_fsl_file','fsl_reg_file')]),
            (n_fsmask2epi, outputnode, [('transformed_file','fmri_mask')]),
            (n_fsrois2epi, outputnode, [('transformed_file','fmri_rois')]),
            ])
    return w
    def make_freesurfer(self):

        # Ref: http://nipype.readthedocs.io/en/1.0.4/interfaces/generated/interfaces.freesurfer/preprocess.html#reconall
        fs_recon1 = Node(interface=fs.ReconAll(directive='autorecon1',
                                               mris_inflate='-n 15',
                                               hires=True,
                                               mprage=True,
                                               openmp=self.omp_nthreads),
                         name='fs_recon1',
                         n_procs=self.omp_nthreads)
        fs_mriconv = Node(interface=fs.MRIConvert(out_type='mgz'),
                          name='fs_mriconv')
        fs_vol2vol = Node(interface=fs.ApplyVolTransform(mni_152_reg=True),
                          name='fs_vol2vol')
        fs_mrimask = Node(interface=fs.ApplyMask(), name='fs_mrimask')
        fs_recon2 = Node(interface=fs.ReconAll(directive='autorecon2',
                                               hires=True,
                                               mprage=True,
                                               hippocampal_subfields_T1=False,
                                               openmp=self.omp_nthreads),
                         name='fs_recon2',
                         n_procs=self.omp_nthreads)

        fs_recon3 = Node(interface=fs.ReconAll(directive='autorecon3',
                                               hires=True,
                                               mprage=True,
                                               hippocampal_subfields_T1=False,
                                               openmp=self.omp_nthreads),
                         name='fs_recon3',
                         n_procs=self.omp_nthreads)

        copy_brainmask = Node(Function(['in_file', 'fs_dir'], ['fs_dir'],
                                       self.copy_mask),
                              name='copy_brainmask')
        segment_hp = Node(interface=SegmentHA_T1(), name='segment_hp')

        freesurfer = Workflow(name='freesurfer', base_dir=self.temp_dir)
        freesurfer.connect(fs_recon1, 'T1', fs_vol2vol, 'target_file')
        freesurfer.connect(fs_mriconv, 'out_file', fs_vol2vol, 'source_file')
        freesurfer.connect(fs_recon1, 'T1', fs_mrimask, 'in_file')
        freesurfer.connect(fs_vol2vol, 'transformed_file', fs_mrimask,
                           'mask_file')
        freesurfer.connect(fs_mrimask, 'out_file', copy_brainmask, 'in_file')
        freesurfer.connect(fs_recon1, 'subjects_dir', copy_brainmask, 'fs_dir')
        freesurfer.connect(copy_brainmask, 'fs_dir', fs_recon2, 'subjects_dir')
        freesurfer.connect(fs_recon2, 'subjects_dir', fs_recon3,
                           'subjects_dir')
        freesurfer.connect(fs_recon3, 'subjects_dir', segment_hp,
                           'subjects_dir')

        return freesurfer
Example #5
0
File: pet.py Project: bpinsard/misc
def pet_register_rois(name='pet_register_rois', pet_prefix='fdg'):
    inputnode = pe.Node(utility.IdentityInterface(
        fields=['pet_image', 't1_image', 'rois_image']),
                        name='inputspec')
    outputnode = pe.Node(utility.IdentityInterface(
        fields=['pet2t1', 'pet2t1_xfm', 'warped_rois', 'stats']),
                         name='outputspec')

    n_flirt_pet2t1 = pe.Node(fsl.FLIRT(dof=6,
                                       cost='mutualinfo',
                                       out_file=Undefined,
                                       out_matrix_file='%spet2t1.mat' %
                                       pet_prefix),
                             name='flirt_%spet2t1' % pet_prefix)

    n_fsl2xfm = pe.Node(freesurfer.preprocess.Tkregister(no_edit=True,
                                                         xfm_out='%s.xfm',
                                                         reg_file='%s.dat'),
                        name='fsl2xfm')

    n_warp_rois = pe.Node(freesurfer.ApplyVolTransform(
        inverse=True, interp='nearest', transformed_file='warped_rois.nii.gz'),
                          name='warp_rois')

    w = pe.Workflow(name=name)

    n_extract_signal = pe.Node(
        afni.ROIStats(args='-nzvoxels -nzsigma -nzmedian -nobriklab'),
        name='extract_signal')

    w.connect([(inputnode, n_flirt_pet2t1, [('pet_image', 'in_file'),
                                            ('t1_image', 'reference')]),
               (n_flirt_pet2t1, n_fsl2xfm, [('out_matrix_file', 'fsl_reg')]),
               (inputnode, n_fsl2xfm, [
                   ('pet_image', 'mov'),
                   ('t1_image', 'target'),
               ]), (n_fsl2xfm, n_warp_rois, [('xfm_out', 'xfm_reg_file')]),
               (inputnode, n_warp_rois, [('pet_image', 'source_file'),
                                         ('rois_image', 'target_file')]),
               (n_warp_rois, n_extract_signal, [('transformed_file', 'mask')]),
               (inputnode, n_extract_signal, [('pet_image', 'in_file')]),
               (n_warp_rois, outputnode, [('transformed_file', 'warped_rois')
                                          ]),
               (n_flirt_pet2t1, outputnode, [('out_matrix_file', 'pet2t1')]),
               (n_fsl2xfm, outputnode, [('xfm_out', 'pet2t1_xfm')]),
               (n_extract_signal, outputnode, [('stats', 'stats')])])
    return w
Example #6
0
def extract_csf_mask():
    """Create a workflow to extract a mask of csf voxels
    
    Inputs
    ------
    inputspec.mean_file :
    inputspec.reg_file :
    inputspec.fsaseg_file :
    
    Outputs
    -------
    outputspec.csf_mask :
    
    Returns
    -------
    workflow : workflow that extracts mask of csf voxels
    """
    import nipype.pipeline.engine as pe
    import nipype.interfaces.freesurfer as fs
    import nipype.interfaces.utility as util

    extract_csf = pe.Workflow(name='extract_csf_mask')
    inputspec = pe.Node(util.IdentityInterface(
        fields=['mean_file', 'reg_file', 'fsaseg_file']),
                        name='inputspec')

    bin = pe.Node(fs.Binarize(), name='binarize')
    bin.inputs.wm_ven_csf = True
    bin.inputs.match = [4, 5, 14, 15, 24, 31, 43, 44, 63]
    bin.inputs.erode = 2

    extract_csf.connect(inputspec, 'fsaseg_file', bin, "in_file")
    voltransform = pe.Node(fs.ApplyVolTransform(inverse=True),
                           name='inverse_transform')
    extract_csf.connect(bin, 'binary_file', voltransform, 'target_file')
    extract_csf.connect(inputspec, 'reg_file', voltransform, 'reg_file')
    extract_csf.connect(inputspec, 'mean_file', voltransform, 'source_file')
    outputspec = pe.Node(util.IdentityInterface(fields=['csf_mask']),
                         name='outputspec')
    extract_csf.connect(voltransform, 'transformed_file', outputspec,
                        'csf_mask')
    return extract_csf
Example #7
0
def freesurfer_brain_connector(wf, cfg, strat_pool, pipe_num, opt):
    # register FS brain mask to native space
    fs_brain_mask_to_native = pe.Node(interface=freesurfer.ApplyVolTransform(),
                                      name='fs_brain_mask_to_native')
    fs_brain_mask_to_native.inputs.reg_header = True

    node, out = strat_pool.get_data('space-T1w_desc-brain_mask')
    wf.connect(node, out, fs_brain_mask_to_native, 'source_file')

    node, out = strat_pool.get_data('raw_average')
    wf.connect(node, out, fs_brain_mask_to_native, 'target_file')

    node, out = strat_pool.get_data('freesurfer_subject_dir')
    wf.connect(node, out, fs_brain_mask_to_native, 'subjects_dir')

    # convert brain mask file from .mgz to .nii.gz
    fs_brain_mask_to_nifti = pe.Node(util.Function(input_names=['in_file'],
                                                   output_names=['out_file'],
                                                   function=mri_convert),
                                     name='fs_brainmask_to_nifti')
    wf.connect(fs_brain_mask_to_native, 'transformed_file',
               fs_brain_mask_to_nifti, 'in_file')

    # binarize the brain mask
    binarize_fs_brain_mask = pe.Node(interface=fsl.maths.MathsCommand(),
                                     name='binarize_fs_brainmask')
    binarize_fs_brain_mask.inputs.args = '-bin'
    wf.connect(fs_brain_mask_to_nifti, 'out_file', binarize_fs_brain_mask,
               'in_file')

    # fill holes
    fill_fs_brain_mask = pe.Node(interface=afni.MaskTool(),
                                 name='fill_fs_brainmask')
    fill_fs_brain_mask.inputs.fill_holes = True
    fill_fs_brain_mask.inputs.outputtype = 'NIFTI_GZ'
    wf.connect(binarize_fs_brain_mask, 'out_file', fill_fs_brain_mask,
               'in_file')

    outputs = {'space-T1w_desc-brain_mask': (fill_fs_brain_mask, 'out_file')}

    return (wf, outputs)
Example #8
0
    def _post_run_hook(self, runtime):
        outputs = self.aggregate_outputs(runtime=runtime)
        mri_dir = os.path.join(self.inputs.subjects_dir,
                               self.inputs.subject_id, 'mri')
        target_file = os.path.join(mri_dir, 'brainmask.mgz')

        # Apply transform for simplicity
        mri_vol2vol = fs.ApplyVolTransform(source_file=self.inputs.source_file,
                                           target_file=target_file,
                                           lta_file=outputs.out_lta_file,
                                           interp='nearest')
        res = mri_vol2vol.run()

        self._fixed_image = target_file
        self._moving_image = res.outputs.transformed_file
        self._contour = os.path.join(mri_dir, 'ribbon.mgz')
        NIWORKFLOWS_LOG.info(
            'Report - setting fixed (%s) and moving (%s) images',
            self._fixed_image, self._moving_image)

        return super(BBRegisterRPT, self)._post_run_hook(runtime)
Example #9
0
def create_confound_extraction_workflow(name="confounds", wm_components=6):
    """Extract nuisance variables from anatomical sources."""
    inputnode = Node(
        IdentityInterface(
            ["timeseries", "brain_mask", "reg_file", "subject_id"]), "inputs")

    # Find the subject's Freesurfer segmentation
    # Grab the Freesurfer aparc+aseg file as an anatomical brain mask
    getaseg = Node(
        io.SelectFiles({"aseg": "{subject_id}/mri/aseg.mgz"},
                       base_directory=os.environ["SUBJECTS_DIR"]), "getaseg")

    # Select and erode the white matter to get deep voxels
    selectwm = Node(fs.Binarize(erode=3, wm=True), "selectwm")

    # Transform the mask into functional space
    transform = MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"),
                        ["reg_file", "source_file"], "transform")

    # Extract eigenvariates of the timeseries from WM and whole brain
    extract = MapNode(ExtractConfounds(n_components=wm_components),
                      ["timeseries", "brain_mask", "wm_mask"], "extract")

    outputnode = Node(IdentityInterface(["confound_file"]), "outputs")

    confounds = Workflow(name)
    confounds.connect([
        (inputnode, getaseg, [("subject_id", "subject_id")]),
        (getaseg, selectwm, [("aseg", "in_file")]),
        (selectwm, transform, [("binary_file", "target_file")]),
        (inputnode, transform, [("reg_file", "reg_file"),
                                ("timeseries", "source_file")]),
        (transform, extract, [("transformed_file", "wm_mask")]),
        (inputnode, extract, [("timeseries", "timeseries"),
                              ("brain_mask", "brain_mask")]),
        (extract, outputnode, [("out_file", "confound_file")]),
    ])

    return confounds
Example #10
0
def init_segs_to_native_wf(*, name="segs_to_native", segmentation="aseg"):
    """
    Get a segmentation from FreeSurfer conformed space into native T1w space.

    Workflow Graph
        .. workflow::
            :graph2use: orig
            :simple_form: yes

            from smriprep.workflows.surfaces import init_segs_to_native_wf
            wf = init_segs_to_native_wf()

    Parameters
    ----------
    segmentation
        The name of a segmentation ('aseg' or 'aparc_aseg' or 'wmparc')

    Inputs
    ------
    in_file
        Anatomical, merged T1w image after INU correction
    subjects_dir
        FreeSurfer SUBJECTS_DIR
    subject_id
        FreeSurfer subject ID
    fsnative2t1w_xfm
        LTA-style affine matrix translating from FreeSurfer-conformed subject space to T1w

    Outputs
    -------
    out_file
        The selected segmentation, after resampling in native space

    """
    workflow = Workflow(name="%s_%s" % (name, segmentation))
    inputnode = pe.Node(
        niu.IdentityInterface(
            ["in_file", "subjects_dir", "subject_id", "fsnative2t1w_xfm"]
        ),
        name="inputnode",
    )
    outputnode = pe.Node(niu.IdentityInterface(["out_file"]), name="outputnode")
    # Extract the aseg and aparc+aseg outputs
    fssource = pe.Node(nio.FreeSurferSource(), name="fs_datasource")
    # Resample from T1.mgz to T1w.nii.gz, applying any offset in fsnative2t1w_xfm,
    # and convert to NIfTI while we're at it
    resample = pe.Node(
        fs.ApplyVolTransform(transformed_file="seg.nii.gz", interp="nearest"),
        name="resample",
    )

    if segmentation.startswith("aparc"):
        if segmentation == "aparc_aseg":

            def _sel(x):
                return [parc for parc in x if "aparc+" in parc][0]  # noqa

        elif segmentation == "aparc_a2009s":

            def _sel(x):
                return [parc for parc in x if "a2009s+" in parc][0]  # noqa

        elif segmentation == "aparc_dkt":

            def _sel(x):
                return [parc for parc in x if "DKTatlas+" in parc][0]  # noqa

        segmentation = (segmentation, _sel)

    # fmt:off
    workflow.connect([
        (inputnode, fssource, [
            ('subjects_dir', 'subjects_dir'),
            ('subject_id', 'subject_id')]),
        (inputnode, resample, [('in_file', 'target_file'),
                               ('fsnative2t1w_xfm', 'lta_file')]),
        (fssource, resample, [(segmentation, 'source_file')]),
        (resample, outputnode, [('transformed_file', 'out_file')]),
    ])
    # fmt:on
    return workflow
Example #11
0
def create_skullstrip_workflow(name="skullstrip"):
    """Remove non-brain voxels from the timeseries."""

    # Define the workflow inputs
    inputnode = Node(
        IdentityInterface(["subject_id", "timeseries", "reg_file"]), "inputs")

    # Mean the timeseries across the fourth dimension
    origmean = MapNode(fsl.MeanImage(), "in_file", "origmean")

    # Grab the Freesurfer aparc+aseg file as an anatomical brain mask
    getaseg = Node(
        io.SelectFiles({"aseg": "{subject_id}/mri/aparc+aseg.mgz"},
                       base_directory=os.environ["SUBJECTS_DIR"]), "getaseg")

    # Threshold the aseg volume to get a boolean mask
    makemask = Node(fs.Binarize(dilate=4, min=0.5), "makemask")

    # Transform the brain mask into functional space
    transform = MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"),
                        ["reg_file", "source_file"], "transform")

    # Convert the mask to nifti and rename
    convertmask = MapNode(fs.MRIConvert(out_file="functional_mask.nii.gz"),
                          "in_file", "convertmask")

    # Use the mask to skullstrip the timeseries
    stripts = MapNode(fs.ApplyMask(), ["in_file", "mask_file"], "stripts")

    # Use the mask to skullstrip the mean image
    stripmean = MapNode(fs.ApplyMask(), ["in_file", "mask_file"], "stripmean")

    # Generate images summarizing the skullstrip and resulting data
    reportmask = MapNode(MaskReport(), ["mask_file", "orig_file", "mean_file"],
                         "reportmask")

    # Define the workflow outputs
    outputnode = Node(
        IdentityInterface(["timeseries", "mean_file", "mask_file", "report"]),
        "outputs")

    # Define and connect the workflow
    skullstrip = Workflow(name)

    skullstrip.connect([
        (inputnode, origmean, [("timeseries", "in_file")]),
        (inputnode, getaseg, [("subject_id", "subject_id")]),
        (origmean, transform, [("out_file", "source_file")]),
        (getaseg, makemask, [("aseg", "in_file")]),
        (makemask, transform, [("binary_file", "target_file")]),
        (inputnode, transform, [("reg_file", "reg_file")]),
        (transform, stripts, [("transformed_file", "mask_file")]),
        (transform, stripmean, [("transformed_file", "mask_file")]),
        (inputnode, stripts, [("timeseries", "in_file")]),
        (origmean, stripmean, [("out_file", "in_file")]),
        (stripmean, reportmask, [("out_file", "mean_file")]),
        (origmean, reportmask, [("out_file", "orig_file")]),
        (transform, reportmask, [("transformed_file", "mask_file")]),
        (transform, convertmask, [("transformed_file", "in_file")]),
        (stripts, outputnode, [("out_file", "timeseries")]),
        (stripmean, outputnode, [("out_file", "mean_file")]),
        (convertmask, outputnode, [("out_file", "mask_file")]),
        (reportmask, outputnode, [("out_files", "report")]),
    ])

    return skullstrip
Example #12
0
def define_template_workflow(info, subjects, qc=True):

    # --- Workflow parameterization

    subject_source = Node(IdentityInterface(["subject"]),
                          name="subject_source",
                          iterables=("subject", subjects))

    # Data input
    template_input = Node(TemplateInput(data_dir=info.data_dir),
                          "template_input")

    # --- Definition of functional template space

    crop_image = Node(fs.ApplyMask(args="-bb 4"), "crop_image")

    zoom_image = Node(fs.MRIConvert(resample_type="cubic",
                                    out_type="niigz",
                                    vox_size=info.voxel_size,
                                    ),
                      "zoom_image")

    reorient_image = Node(fsl.Reorient2Std(out_file="anat.nii.gz"),
                          "reorient_image")

    generate_reg = Node(fs.Tkregister2(fsl_out="anat2func.mat",
                                       reg_file="anat2func.dat",
                                       reg_header=True),
                        "generate_reg")

    invert_reg = Node(fs.Tkregister2(reg_file="func2anat.dat",
                                     reg_header=True),
                      "invert_reg")

    # --- Identification of surface vertices

    hemi_source = Node(IdentityInterface(["hemi"]), "hemi_source",
                       iterables=("hemi", ["lh", "rh"]))

    tag_surf = Node(fs.Surface2VolTransform(surf_name="graymid",
                                            transformed_file="ribbon.nii.gz",
                                            vertexvol_file="vertices.nii.gz",
                                            mkmask=True),
                    "tag_surf")

    mask_cortex = Node(MaskWithLabel(fill_value=-1), "mask_cortex")

    combine_hemis = JoinNode(fsl.Merge(dimension="t",
                                       merged_file="surf.nii.gz"),
                             name="combine_hemis",
                             joinsource="hemi_source",
                             joinfield="in_files")

    make_ribbon = Node(MakeRibbon(), "make_ribbon")

    # --- Segementation of anatomical tissue in functional space

    transform_wmparc = Node(fs.ApplyVolTransform(inverse=True,
                                                 interp="nearest",
                                                 args="--keep-precision"),
                            "transform_wmparc")

    anat_segment = Node(AnatomicalSegmentation(), "anat_segment")

    # --- Template QC

    template_qc = Node(TemplateReport(), "template_qc")

    # --- Workflow ouptut

    save_info = Node(SaveInfo(info_dict=info.trait_get()), "save_info")

    template_output = Node(DataSink(base_directory=info.proc_dir,
                                    parameterization=False),
                           "template_output")

    # === Assemble pipeline

    workflow = Workflow(name="template", base_dir=info.cache_dir)

    processing_edges = [

        (subject_source, template_input,
            [("subject", "subject")]),
        (template_input, crop_image,
            [("norm_file", "in_file"),
             ("wmparc_file", "mask_file")]),
        (crop_image, zoom_image,
            [("out_file", "in_file")]),
        (zoom_image, reorient_image,
            [("out_file", "in_file")]),

        (subject_source, generate_reg,
            [("subject", "subject_id")]),
        (template_input, generate_reg,
            [("norm_file", "moving_image")]),
        (reorient_image, generate_reg,
            [("out_file", "target_image")]),

        (subject_source, invert_reg,
            [("subject", "subject_id")]),
        (template_input, invert_reg,
            [("norm_file", "target_image")]),
        (reorient_image, invert_reg,
            [("out_file", "moving_image")]),

        (hemi_source, tag_surf,
            [("hemi", "hemi")]),
        (invert_reg, tag_surf,
            [("reg_file", "reg_file")]),
        (reorient_image, tag_surf,
            [("out_file", "template_file")]),
        (template_input, mask_cortex,
            [("label_files", "label_files")]),
        (hemi_source, mask_cortex,
            [("hemi", "hemi")]),
        (tag_surf, mask_cortex,
            [("vertexvol_file", "in_file")]),
        (mask_cortex, combine_hemis,
            [("out_file", "in_files")]),
        (combine_hemis, make_ribbon,
            [("merged_file", "in_file")]),

        (reorient_image, transform_wmparc,
            [("out_file", "source_file")]),
        (template_input, transform_wmparc,
            [("wmparc_file", "target_file")]),
        (invert_reg, transform_wmparc,
            [("reg_file", "reg_file")]),
        (reorient_image, anat_segment,
            [("out_file", "anat_file")]),
        (transform_wmparc, anat_segment,
            [("transformed_file", "wmparc_file")]),
        (combine_hemis, anat_segment,
            [("merged_file", "surf_file")]),

        (template_input, template_output,
            [("output_path", "container")]),
        (reorient_image, template_output,
            [("out_file", "@anat")]),
        (generate_reg, template_output,
            [("fsl_file", "@anat2func")]),
        (anat_segment, template_output,
            [("seg_file", "@seg"),
             ("lut_file", "@lut"),
             ("edge_file", "@edge"),
             ("mask_file", "@mask")]),
        (combine_hemis, template_output,
            [("merged_file", "@surf")]),
        (make_ribbon, template_output,
            [("out_file", "@ribon")]),

    ]
    workflow.connect(processing_edges)

    # Optionally connect QC nodes

    qc_edges = [

        (reorient_image, template_qc,
            [("out_file", "anat_file")]),
        (combine_hemis, template_qc,
            [("merged_file", "surf_file")]),
        (anat_segment, template_qc,
            [("lut_file", "lut_file"),
             ("seg_file", "seg_file"),
             ("edge_file", "edge_file"),
             ("mask_file", "mask_file")]),

        (subject_source, save_info,
            [("subject", "parameterization")]),
        (save_info, template_output,
            [("info_file", "qc.@info_json")]),

        (template_qc, template_output,
            [("seg_plot", "qc.@seg_plot"),
             ("mask_plot", "qc.@mask_plot"),
             ("edge_plot", "qc.@edge_plot"),
             ("surf_plot", "qc.@surf_plot"),
             ("anat_plot", "qc.@anat_plot")]),

    ]
    if qc:
        workflow.connect(qc_edges)

    return workflow
Example #13
0
def get_fmri2standard_wf(
        tvols,
        subject_id,
        ACQ_PARAMS="/home/didac/LabScripts/fMRI_preprocess/acparams_hcp.txt"):
    """Estimates transformation from Gradiend Field Distortion-warped BOLD to T1
    
    In general:
        BOLD is field-inhomogeneity corrected and corregistered into standard space (T1).  
        
    To do so, the following steps are carried out:
        1)  Corregister SBref to SEgfmAP (fsl.FLIRT)
        2)  Realign BOLD to corrected SBref (fsl.MCFLIRT)
        3)  Field inhomogeneity correction estimation of SBref from SEfm_AP and SEfm_PA (fsl.TOPUP)
        4)  Apply field inhomogeneity correction to SBref (fsl.ApplyTOPUP)
        5)  Apply field inhomogeneity correction to BOLD (fsl.ApplyTOPUP)
        6)  Transform free-surfer brain mask (brain.mgz) to T1 space (freesurfer.ApplyVolTransform ;mri_vol2vol), 
            then binarized (fsl.UnaryMaths) and the mask is extracted from T1 (fsl.BinaryMaths)
        7)  Corregister BOLD (field-inhomogeneity corrected) to Standard T1 (fsl.Epi2Reg)

    Parameters
    ----------
    tvols: [t_initial, t_final] volumes included in the preprocess
    ACQ_params: Path to txt file containing MRI acquisition parameters; needs to be specified for topup correction
    
    
    Returns
    -------
    Workflow with the transformation
 
    """
    from nipype import Workflow, Node, interfaces
    from nipype.interfaces import fsl, utility, freesurfer

    print("defining workflow...")
    wf = Workflow(name=subject_id, base_dir='')

    #Setting INPUT node...
    print("defines input node...")
    node_input = Node(utility.IdentityInterface(fields=[
        'func_sbref_img', 'func_segfm_ap_img', 'func_segfm_pa_img',
        'func_bold_ap_img', 'T1_img', 'T1_brain_freesurfer_mask'
    ]),
                      name='input_node')

    print(
        "Averages the three repeated Spin-Echo images with same Phase Encoding (AP or PA) for Susceptibility Correction (unwarping)..."
    )
    node_average_SEgfm = Node(fsl.maths.MeanImage(), name='Mean_SEgfm_AP')

    print("Corregister SB-ref to average SEgfm-AP")
    node_coregister_SBref2SEgfm = Node(
        fsl.FLIRT(dof=6  #translation and rotation only
                  ),
        name='Corregister_SBref2SEgfm')

    print("Eliminates first volumes.")
    node_eliminate_first_scans = Node(
        fsl.ExtractROI(
            t_min=tvols[0],  # first included volume
            t_size=tvols[1] -
            tvols[0],  # number of volumes from the first to the last one
        ),
        name="eliminate_first_scans")

    print("Realigns fMRI BOLD volumes to SBref in SEgfm-AP space")
    node_realign_bold = Node(
        fsl.MCFLIRT(
            save_plots=True,  # save transformation matrices
        ),
        name="realign_fmri2SBref")

    print("Concatenates AP and PA SEgfm volumes...")
    # AP AP AP PA PA PA
    node_merge_ap_pa_inputs = Node(
        utility.base.Merge(2  # number of inputs; it concatenates lists
                           ),
        name='Merge_ap_pa_inputs')
    node_merge_SEgfm = Node(
        fsl.Merge(dimension='t'  # ¿? 
                  ),
        name='Merge_SEgfm_AP_PA')

    print(
        "Estimates TopUp inhomogeneity correction from SEfm_AP and SEfm_PA...")
    node_topup_SEgfm = Node(fsl.TOPUP(encoding_file=ACQ_PARAMS, ),
                            name='Topup_SEgfm_estimation')

    print("Applies warp from TOPUP to correct SBref...")
    node_apply_topup_to_SBref = Node(
        fsl.ApplyTOPUP(
            encoding_file=ACQ_PARAMS,
            method='jac',  # jacobian modulation
            interp='spline',  # interpolation method
        ),
        name="apply_topup_to_SBref")

    print("Applies warp from TOPUP to correct realigned BOLD...")
    node_apply_topup = Node(
        fsl.ApplyTOPUP(
            encoding_file=ACQ_PARAMS,
            method='jac',  # jacobian modulation
            interp='spline',  # interpolation method
        ),
        name="apply_topup")

    ## BRAIN MASK

    #Registration to T1. Epireg without fieldmaps combined (see https://www.fmrib.ox.ac.uk/primers/intro_primer/ExBox20/IntroBox20.html)
    #    print ("Eliminates scalp from brain using T1 high res image");
    #    node_mask_T1=Node(fsl.BET(
    #            frac=0.7 # umbral
    #            ),
    #    name="mask_T1");

    print('Transform brain mask T1 from freesurfer space to T1 space')
    node_vol2vol_brain = Node(
        freesurfer.ApplyVolTransform(
            reg_header=True,  # (--regheader)
            transformed_file='brainmask_warped.nii.gz'
            #source_file --mov (INPUT; freesurfer brain.mgz)
            #transformed_file --o (OUTPUT; ...brain.nii.gz)
            #target_file --targ (REFERENCE; ...T1w.nii.gz)
        ),
        name="vol2vol")

    print('Transform brain mask T1 to binary mask')
    node_bin_mask_brain = Node(
        fsl.UnaryMaths(  # fslmaths T1_brain -bin T1_binarized mask
            operation='bin',  # (-bin)
            #in_file (T1_brain)
            #out_file (T1_binarized_mask)
        ),
        name="binarize_mask")

    print('Extract brain mask from T1 using binary mask')
    node_extract_mask = Node(
        fsl.
        BinaryMaths(  # fslmaths T1 -mul T1_binarized_mask T1_extracted_mask
            operation='mul'  # (-mul)
            #in_file (T1)
            #out_file (T1_extracted_mask)
            #operand_file (T1_binarized_mask)
        ),
        name="extract_mask")

    ##
    print("Estimate and appply transformation from SBref to T1")
    node_epireg = Node(
        fsl.EpiReg(
            #t1_head=SUBJECT_FSTRUCT_DIC['anat_T1'],
            out_base='SEgfm2T1'),
        name="epi2reg")
    '''  
    EPI2REG ALREADY APPLIED         
    print ("Apply epi2reg to SBRef..");
    node_apply_epi2reg_SBref= Node(fsl.ApplyXFM(
            ),
    name="node_apply_epi2reg_SBref");
    '''

    print("Estimates inverse transform from epi2reg...")
    # quality control
    node_invert_epi2reg = Node(fsl.ConvertXFM(invert_xfm=True),
                               name="invert_epi2reg")

    print("...")
    node_mask_fMRI = Node(fsl.BET(mask=True, ), name='mask_fMRI')
    #node_fmriMask.overwrite=True
    print("Setting OUTPUT node...")
    node_output = Node(interfaces.utility.IdentityInterface(fields=[
        'SBref2SEgfm_mat',
        'realign_movpar_txt',
        'realign_fmri_img',
        'topup_movpar_txt',
        'topup_field_coef_img',
        'epi2str_mat',
        'epi2str_img',
        'fmri_mask_img',
        'rfmri_unwarped_imgs',
        'sb_ref_unwarped_img',
    ]),
                       name='output_node')

    print("All nodes created; Starts creating connections")

    #Connects nodes
    wf.connect([
        #inputs
        (node_input, node_average_SEgfm, [("func_segfm_ap_img", "in_file")]),
        (node_input, node_coregister_SBref2SEgfm, [("func_sbref_img",
                                                    "in_file")]),
        (node_input, node_eliminate_first_scans, [("func_bold_ap_img",
                                                   "in_file")]),
        (node_input, node_merge_ap_pa_inputs, [("func_segfm_ap_img", "in1"),
                                               ("func_segfm_pa_img", "in2")]),
        (node_merge_ap_pa_inputs, node_merge_SEgfm, [("out", "in_files")]),
        (node_input, node_epireg, [("T1_img", "t1_head")]),
        (node_input, node_vol2vol_brain, [("T1_brain_freesurfer_mask",
                                           "source_file")]),
        (node_input, node_vol2vol_brain, [("T1_img", "target_file")]),
        (node_input, node_extract_mask, [("T1_img", "in_file")]),

        #connections
        (node_eliminate_first_scans, node_realign_bold, [("roi_file",
                                                          "in_file")]),
        (node_average_SEgfm, node_coregister_SBref2SEgfm, [("out_file",
                                                            "reference")]),
        (node_coregister_SBref2SEgfm, node_realign_bold, [("out_file",
                                                           "ref_file")]),

        #T1 brain mask transformations (change space / vol2vol, binarize and extract)
        (node_vol2vol_brain, node_bin_mask_brain, [("transformed_file",
                                                    "in_file")]),
        (node_bin_mask_brain, node_extract_mask, [("out_file", "operand_file")
                                                  ]),

        #(node_realign_bold, node_tsnr, [("out_file", "in_file")]),
        (node_merge_SEgfm, node_topup_SEgfm, [("merged_file", "in_file")]),
        (node_realign_bold, node_apply_topup, [("out_file", "in_files")]),
        (node_topup_SEgfm, node_apply_topup,
         [("out_fieldcoef", "in_topup_fieldcoef"),
          ("out_movpar", "in_topup_movpar")]),
        (node_topup_SEgfm, node_apply_topup_to_SBref,
         [("out_fieldcoef", "in_topup_fieldcoef"),
          ("out_movpar", "in_topup_movpar")]),
        (node_coregister_SBref2SEgfm, node_apply_topup_to_SBref,
         [("out_file", "in_files")]),

        #corregister to T1
        (node_extract_mask, node_epireg, [("out_file", "t1_brain")]),
        (node_apply_topup_to_SBref, node_epireg, [("out_corrected", "epi")]),
        (node_epireg, node_invert_epi2reg, [("epi2str_mat", "in_file")]),
        (node_coregister_SBref2SEgfm, node_mask_fMRI, [("out_file", "in_file")
                                                       ]),

        #yeld relevant data to output node
        (node_coregister_SBref2SEgfm, node_output, [("out_matrix_file",
                                                     "SBref2SEgfm_mat")]),
        (node_realign_bold, node_output, [("par_file", "realign_movpar_txt"),
                                          ("out_file", "realign_fmri_img")]),
        (node_mask_fMRI, node_output, [("mask_file", "fmri_mask_img")]),
        (node_epireg, node_output, [("epi2str_mat", "epi2str_mat")]),
        (node_epireg, node_output, [("out_file", "epi2str_img")]),
        (node_topup_SEgfm, node_output,
         [("out_fieldcoef", "topup_field_coef_img"),
          ("out_corrected", "sb_ref_unwarped_img")]),
        (node_apply_topup, node_output, [("out_corrected",
                                          "rfmri_unwarped_imgs")])
    ])
    print("All connections created")
    return (wf)
Example #14
0
# Register a source file to fs space and create a brain mask in source space
# The node below creates the Freesurfer source
fssource = pe.Node(nio.FreeSurferSource(), name='fssource')
fssource.inputs.subject_id = f'sub-{sids[0]}'
fssource.inputs.subjects_dir = fs_dir

# Extract aparc+aseg brain mask, binarize, and dilate by 1 voxel
fs_threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'),
                       name='fs_threshold')
fs_threshold.inputs.dilate = 1
psb6351_wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), fs_threshold,
                   'in_file')

# Transform the binarized aparc+aseg file to the EPI space
# use a nearest neighbor interpolation
fs_voltransform = pe.Node(fs.ApplyVolTransform(inverse=True),
                          name='fs_transform')
fs_voltransform.inputs.subjects_dir = fs_dir
fs_voltransform.inputs.interp = 'nearest'
psb6351_wf.connect(extractref, 'roi_file', fs_voltransform, 'source_file')
psb6351_wf.connect(fs_register, 'out_reg_file', fs_voltransform, 'reg_file')
psb6351_wf.connect(fs_threshold, 'binary_file', fs_voltransform, 'target_file')

# Mask the functional runs with the extracted mask
maskfunc = pe.MapNode(fsl.ImageMaths(suffix='_bet', op_string='-mas'),
                      iterfield=['in_file'],
                      name='maskfunc')
psb6351_wf.connect(tshifter, 'out_file', maskfunc, 'in_file')
psb6351_wf.connect(fs_voltransform, 'transformed_file', maskfunc, 'in_file2')

# Smooth each run using SUSAn with the brightness threshold set to 75%
Example #15
0
surfregister = pe.Node(interface=fs.BBRegister(), name='surfregister')
surfregister.inputs.init = 'fsl'
surfregister.inputs.contrast_type = 't2'
"""
Use :class:`nipype.interfaces.io.FreeSurferSource` to retrieve various image
files that are automatically generated by the recon-all process.
"""

FreeSurferSource = pe.Node(interface=nio.FreeSurferSource(), name='fssource')
"""
Use :class:`nipype.interfaces.freesurfer.ApplyVolTransform` to convert the
brainmask generated by freesurfer into the realigned functional space.
"""

ApplyVolTransform = pe.Node(interface=fs.ApplyVolTransform(), name='applyreg')
ApplyVolTransform.inputs.inverse = True
"""
Use :class:`nipype.interfaces.freesurfer.Binarize` to extract a binary brain
mask.
"""

Threshold = pe.Node(interface=fs.Binarize(), name='threshold')
Threshold.inputs.min = 10
Threshold.inputs.out_type = 'nii'
"""
Two different types of functional data smoothing are performed in this
workflow. The volume smoothing option performs a standard SPM smoothin. using
:class:`nipype.interfaces.spm.Smooth`. In addition, we use a smoothing routine
from freesurfer (:class:`nipype.interfaces.freesurfer.Binarize`) to project the
functional data from the volume to the subjects' surface, smooth it on the
Example #16
0
def create_getmask_flow(name='getmask', dilate_mask=True):
    """Registers a source file to freesurfer space and create a brain mask in
source space

Requires fsl tools for initializing registration

Parameters
----------

name : string
name of workflow
dilate_mask : boolean
indicates whether to dilate mask or not

Example
-------

>>> getmask = create_getmask_flow()
>>> getmask.inputs.inputspec.source_file = 'mean.nii'
>>> getmask.inputs.inputspec.subject_id = 's1'
>>> getmask.inputs.inputspec.subjects_dir = '.'
>>> getmask.inputs.inputspec.contrast_type = 't2'


Inputs::

inputspec.source_file : reference image for mask generation
inputspec.subject_id : freesurfer subject id
inputspec.subjects_dir : freesurfer subjects directory
inputspec.contrast_type : MR contrast of reference image

Outputs::

outputspec.mask_file : binary mask file in reference image space
outputspec.reg_file : registration file that maps reference image to
freesurfer space
outputspec.reg_cost : cost of registration (useful for detecting misalignment)
"""
    import nipype.pipeline.engine as pe
    import nipype.interfaces.utility as niu
    import nipype.interfaces.freesurfer as fs
    import nipype.interfaces.io as nio
    """
Initialize the workflow
"""

    getmask = pe.Workflow(name=name)

    """
Define the inputs to the workflow.
"""

    inputnode = pe.Node(niu.IdentityInterface(fields=['source_file',
                                                      'subject_id',
                                                      'subjects_dir',
                                                      'contrast_type']),
        name='inputspec')

    """
Define all the nodes of the workflow:

fssource: used to retrieve aseg.mgz
threshold : binarize aseg
register : coregister source file to freesurfer space
voltransform: convert binarized aseg to source file space

"""

    fssource = pe.Node(nio.FreeSurferSource(),
        name = 'fssource')
    threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'),
        name='threshold')
    register = pe.MapNode(fs.BBRegister(init='fsl'),
        iterfield=['source_file'],
        name='register')
    voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True),
        iterfield=['source_file', 'reg_file'],
        name='transform')

    """
Connect the nodes
"""

    getmask.connect([
        (inputnode, fssource, [('subject_id','subject_id'),
            ('subjects_dir','subjects_dir')]),
        (inputnode, register, [('source_file', 'source_file'),
            ('subject_id', 'subject_id'),
            ('subjects_dir', 'subjects_dir'),
            ('contrast_type', 'contrast_type')]),
        (inputnode, voltransform, [('subjects_dir', 'subjects_dir'),
            ('source_file', 'source_file')]),
        (fssource, threshold, [(('aparc_aseg', get_aparc_aseg), 'in_file')]),
        (register, voltransform, [('out_reg_file','reg_file')]),
        (threshold, voltransform, [('binary_file','target_file')])
    ])


    """
Add remaining nodes and connections

dilate : dilate the transformed file in source space
threshold2 : binarize transformed file
"""

    threshold2 = pe.MapNode(fs.Binarize(min=0.5, out_type='nii'),
        iterfield=['in_file'],
        name='threshold2')
    if dilate_mask:
        threshold2.inputs.dilate = 1
    getmask.connect([
        (voltransform, threshold2, [('transformed_file', 'in_file')])
    ])

    """
Setup an outputnode that defines relevant inputs of the workflow.
"""

    outputnode = pe.Node(niu.IdentityInterface(fields=["mask_file",
                                                       "reg_file",
                                                       "reg_cost"
    ]),
        name="outputspec")
    getmask.connect([
        (register, outputnode, [("out_reg_file", "reg_file")]),
        (register, outputnode, [("min_cost_file", "reg_cost")]),
        (threshold2, outputnode, [("binary_file", "mask_file")]),
    ])
    return getmask
Example #17
0
    def plot_epi_to_t1_coregistration(epi_file, reg_file, ribbon,
                                      fssubjects_dir):
        import pylab as plt
        from nipy.labs import viz
        import nibabel as nb
        import numpy as np
        import os
        import nipype.interfaces.freesurfer as fs
        anat = nb.load(ribbon).get_data()
        anat[anat > 1] = 1
        anat_affine = nb.load(ribbon).get_affine()
        func = nb.load(epi_file).get_data()
        func_affine = nb.load(epi_file).get_affine()
        fig = plt.figure(figsize=(8, 6), edgecolor='k', facecolor='k')
        slicer = viz.plot_anat(np.asarray(func),
                               np.asarray(func_affine),
                               black_bg=True,
                               cmap=plt.cm.spectral,
                               cut_coords=(-6, 3, 12),
                               figure=fig,
                               axes=[0, .50, 1, .33])
        slicer.contour_map(np.asarray(anat),
                           np.asarray(anat_affine),
                           levels=[.51],
                           colors=[
                               'r',
                           ])
        slicer.title(
            "Mean EPI with cortical surface contour overlay (before registration)",
            size=12,
            color='w',
            alpha=0)

        res = fs.ApplyVolTransform(source_file=epi_file,
                                   reg_file=reg_file,
                                   fs_target=True,
                                   subjects_dir=fssubjects_dir).run()

        func = nb.load(res.outputs.transformed_file).get_data()
        func_affine = nb.load(res.outputs.transformed_file).get_affine()
        slicer = viz.plot_anat(np.asarray(func),
                               np.asarray(func_affine),
                               black_bg=True,
                               cmap=plt.cm.spectral,
                               cut_coords=(-6, 3, 12),
                               figure=fig,
                               axes=[0, 0, 1, .33])
        slicer.contour_map(np.asarray(anat),
                           np.asarray(anat_affine),
                           levels=[.51],
                           colors=[
                               'r',
                           ])
        slicer.title(
            "Mean EPI with cortical surface contour overlay (after registration)",
            size=12,
            color='w',
            alpha=0)
        plt.savefig("reg_plot.png",
                    facecolor=fig.get_facecolor(),
                    edgecolor='none')
        return os.path.abspath("reg_plot.png")
Example #18
0
def run_dmriprep(dwi_file, bvec_file, bval_file, subjects_dir, working_dir,
                 out_dir):
    """
    Runs dmriprep for acquisitions with just one PE direction.

    """
    from glob import glob
    import nibabel as nib
    import nipype.interfaces.freesurfer as fs
    import nipype.interfaces.fsl as fsl
    import nipype.interfaces.io as nio
    import nipype.interfaces.utility as niu
    import nipype.pipeline.engine as pe
    import numpy as np
    from nipype.algorithms.rapidart import ArtifactDetect
    from nipype.interfaces.dipy import DTI
    from nipype.interfaces.fsl.utils import AvScale
    from nipype.utils.filemanip import fname_presuffix
    from nipype.workflows.dmri.fsl.epi import create_dmri_preprocessing

    wf = create_dmri_preprocessing(name='dmriprep',
                                   use_fieldmap=False,
                                   fieldmap_registration=False)
    wf.inputs.inputnode.ref_num = 0
    wf.inputs.inputnode.in_file = dwi_file
    wf.inputs.inputnode.in_bvec = bvec_file

    dwi_fname = op.split(dwi_file)[1].split(".nii.gz")[0]
    bids_sub_name = dwi_fname.split("_")[0]
    assert bids_sub_name.startswith("sub-")

    # inputnode = wf.get_node("inputnode")
    outputspec = wf.get_node("outputnode")

    # QC: FLIRT translation and rotation parameters
    flirt = wf.get_node("motion_correct.coregistration")
    # flirt.inputs.save_mats = True

    get_tensor = pe.Node(DTI(), name="dipy_tensor")
    wf.connect(outputspec, "dmri_corrected", get_tensor, "in_file")
    # wf.connect(inputspec2,"bvals", get_tensor, "in_bval")
    get_tensor.inputs.in_bval = bval_file
    wf.connect(outputspec, "bvec_rotated", get_tensor, "in_bvec")

    scale_tensor = pe.Node(name='scale_tensor', interface=fsl.BinaryMaths())
    scale_tensor.inputs.operation = 'mul'
    scale_tensor.inputs.operand_value = 1000
    wf.connect(get_tensor, 'out_file', scale_tensor, 'in_file')

    fslroi = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="fslroi")
    wf.connect(outputspec, "dmri_corrected", fslroi, "in_file")

    bbreg = pe.Node(fs.BBRegister(contrast_type="t2",
                                  init="fsl",
                                  out_fsl_file=True,
                                  subjects_dir=subjects_dir,
                                  epi_mask=True),
                    name="bbreg")
    # wf.connect(inputspec2,"fsid", bbreg,"subject_id")
    bbreg.inputs.subject_id = 'freesurfer'  # bids_sub_name
    wf.connect(fslroi, "roi_file", bbreg, "source_file")

    voltransform = pe.Node(fs.ApplyVolTransform(inverse=True),
                           iterfield=['source_file', 'reg_file'],
                           name='transform')
    voltransform.inputs.subjects_dir = subjects_dir

    vt2 = voltransform.clone("transform_aparcaseg")
    vt2.inputs.interp = "nearest"

    def binarize_aparc(aparc_aseg):
        img = nib.load(aparc_aseg)
        data, aff = img.get_data(), img.affine
        outfile = fname_presuffix(aparc_aseg,
                                  suffix="bin.nii.gz",
                                  newpath=op.abspath("."),
                                  use_ext=False)
        nib.Nifti1Image((data > 0).astype(float), aff).to_filename(outfile)
        return outfile

    # wf.connect(inputspec2, "mask_nii", voltransform, "target_file")
    create_mask = pe.Node(niu.Function(input_names=["aparc_aseg"],
                                       output_names=["outfile"],
                                       function=binarize_aparc),
                          name="bin_aparc")

    def get_aparc_aseg(subjects_dir, sub):
        return op.join(subjects_dir, sub, "mri", "aparc+aseg.mgz")

    create_mask.inputs.aparc_aseg = get_aparc_aseg(subjects_dir, 'freesurfer')
    wf.connect(create_mask, "outfile", voltransform, "target_file")

    wf.connect(fslroi, "roi_file", voltransform, "source_file")
    wf.connect(bbreg, "out_reg_file", voltransform, "reg_file")

    vt2.inputs.target_file = get_aparc_aseg(subjects_dir, 'freesurfer')
    # wf.connect(inputspec2, "aparc_aseg", vt2, "target_file")
    wf.connect(fslroi, "roi_file", vt2, "source_file")
    wf.connect(bbreg, "out_reg_file", vt2, "reg_file")

    # AK (2017): THIS NODE MIGHT NOT BE NECESSARY
    # AK (2018) doesn't know why she said that above..
    threshold2 = pe.Node(fs.Binarize(min=0.5, out_type='nii.gz', dilate=1),
                         iterfield=['in_file'],
                         name='threshold2')
    wf.connect(voltransform, "transformed_file", threshold2, "in_file")

    # wf.connect(getmotion, "motion_params", datasink, "dti.@motparams")

    def get_flirt_motion_parameters(flirt_out_mats):
        def get_params(A):
            """This is a copy of spm's spm_imatrix where
            we already know the rotations and translations matrix,
            shears and zooms (as outputs from fsl FLIRT/avscale)
            Let A = the 4x4 rotation and translation matrix
            R = [          c5*c6,           c5*s6, s5]
                [-s4*s5*c6-c4*s6, -s4*s5*s6+c4*c6, s4*c5]
                [-c4*s5*c6+s4*s6, -c4*s5*s6-s4*c6, c4*c5]
            """
            def rang(b):
                a = min(max(b, -1), 1)
                return a

            Ry = np.arcsin(A[0, 2])
            # Rx = np.arcsin(A[1, 2] / np.cos(Ry))
            # Rz = np.arccos(A[0, 1] / np.sin(Ry))

            if (abs(Ry) - np.pi / 2)**2 < 1e-9:
                Rx = 0
                Rz = np.arctan2(-rang(A[1, 0]), rang(-A[2, 0] / A[0, 2]))
            else:
                c = np.cos(Ry)
                Rx = np.arctan2(rang(A[1, 2] / c), rang(A[2, 2] / c))
                Rz = np.arctan2(rang(A[0, 1] / c), rang(A[0, 0] / c))

            rotations = [Rx, Ry, Rz]
            translations = [A[0, 3], A[1, 3], A[2, 3]]

            return rotations, translations

        motion_params = open(op.abspath('motion_parameters.par'), 'w')
        for mat in flirt_out_mats:
            res = AvScale(mat_file=mat).run()
            A = np.asarray(res.outputs.rotation_translation_matrix)
            rotations, translations = get_params(A)
            for i in rotations + translations:
                motion_params.write('%f ' % i)
            motion_params.write('\n')
        motion_params.close()
        motion_params = op.abspath('motion_parameters.par')
        return motion_params

    getmotion = pe.Node(niu.Function(input_names=["flirt_out_mats"],
                                     output_names=["motion_params"],
                                     function=get_flirt_motion_parameters),
                        name="get_motion_parameters",
                        iterfield="flirt_out_mats")

    wf.connect(flirt, "out_matrix_file", getmotion, "flirt_out_mats")

    art = pe.Node(interface=ArtifactDetect(), name="art")
    art.inputs.use_differences = [True, True]
    art.inputs.save_plot = False
    art.inputs.use_norm = True
    art.inputs.norm_threshold = 3
    art.inputs.zintensity_threshold = 9
    art.inputs.mask_type = 'spm_global'
    art.inputs.parameter_source = 'FSL'

    wf.connect(getmotion, "motion_params", art, "realignment_parameters")
    wf.connect(outputspec, "dmri_corrected", art, "realigned_files")

    datasink = pe.Node(nio.DataSink(), name="sinker")
    datasink.inputs.base_directory = out_dir
    datasink.inputs.substitutions = [
        ("vol0000_flirt_merged.nii.gz", dwi_fname + '.nii.gz'),
        ("stats.vol0000_flirt_merged.txt", dwi_fname + ".art.json"),
        ("motion_parameters.par", dwi_fname + ".motion.txt"),
        ("_rotated.bvec", ".bvec"),
        ("aparc+aseg_warped_out", dwi_fname.replace("_dwi", "_aparc+aseg")),
        ("art.vol0000_flirt_merged_outliers.txt", dwi_fname + ".outliers.txt"),
        ("vol0000_flirt_merged", dwi_fname),
        ("_roi_bbreg_freesurfer", "_register"),
        ("aparc+asegbin_warped_thresh", dwi_fname.replace("_dwi", "_mask")),
        ("derivatives/dmriprep",
         "derivatives/{}/dmriprep".format(bids_sub_name))
    ]

    wf.connect(art, "statistic_files", datasink, "dmriprep.art.@artstat")
    wf.connect(art, "outlier_files", datasink, "dmriprep.art.@artoutlier")
    wf.connect(outputspec, "dmri_corrected", datasink,
               "dmriprep.dwi.@corrected")
    wf.connect(outputspec, "bvec_rotated", datasink, "dmriprep.dwi.@rotated")
    wf.connect(getmotion, "motion_params", datasink, "dmriprep.art.@motion")

    wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@tensor")
    wf.connect(get_tensor, "fa_file", datasink, "dmriprep.dti.@fa")
    wf.connect(get_tensor, "md_file", datasink, "dmriprep.dti.@md")
    wf.connect(get_tensor, "ad_file", datasink, "dmriprep.dti.@ad")
    wf.connect(get_tensor, "rd_file", datasink, "dmriprep.dti.@rd")
    wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@scaled_tensor")

    wf.connect(bbreg, "min_cost_file", datasink, "dmriprep.reg.@mincost")
    wf.connect(bbreg, "out_fsl_file", datasink, "dmriprep.reg.@fslfile")
    wf.connect(bbreg, "out_reg_file", datasink, "dmriprep.reg.@reg")
    wf.connect(threshold2, "binary_file", datasink, "dmriprep.anat.@mask")
    # wf.connect(vt2, "transformed_file", datasink, "dwi.@aparc_aseg")

    convert = pe.Node(fs.MRIConvert(out_type="niigz"), name="convert2nii")
    wf.connect(vt2, "transformed_file", convert, "in_file")
    wf.connect(convert, "out_file", datasink, "dmriprep.anat.@aparc_aseg")

    wf.base_dir = working_dir
    wf.run()

    copyfile(
        bval_file,
        op.join(out_dir, bids_sub_name, "dmriprep", "dwi",
                op.split(bval_file)[1]))

    dmri_corrected = glob(op.join(out_dir, '*/dmriprep/dwi', '*.nii.gz'))[0]
    bvec_rotated = glob(op.join(out_dir, '*/dmriprep/dwi', '*.bvec'))[0]
    bval_file = glob(op.join(out_dir, '*/dmriprep/dwi', '*.bval'))[0]
    art_file = glob(op.join(out_dir, '*/dmriprep/art', '*.art.json'))[0]
    motion_file = glob(op.join(out_dir, '*/dmriprep/art', '*.motion.txt'))[0]
    outlier_file = glob(op.join(out_dir, '*/dmriprep/art',
                                '*.outliers.txt'))[0]
    return dmri_corrected, bvec_rotated, art_file, motion_file, outlier_file
Example #19
0
def get_dmriprep_pe_workflow():
    """Return the dmriprep (phase encoded) nipype workflow

    Parameters
    ----------


    Returns
    -------
    wf : nipype.pipeline.engine.Workflow
        Nipype dmriprep workflow

    Notes
    -----
    This assumes that there are scans with phase-encode directions AP/PA for
    topup.
    """
    import nipype.interfaces.freesurfer as fs
    import nipype.interfaces.fsl as fsl
    import nipype.interfaces.io as nio
    import nipype.interfaces.utility as niu
    import nipype.pipeline.engine as pe
    from nipype.interfaces.dipy import DTI
    from nipype.workflows.dmri.fsl.artifacts import all_fsl_pipeline

    inputspec = pe.Node(niu.IdentityInterface(fields=[
        'subject_id', 'dwi_file', 'dwi_file_ap', 'dwi_file_pa', 'bvec_file',
        'bval_file', 'subjects_dir', 'out_dir', 'eddy_niter',
        'slice_outlier_threshold'
    ]),
                        name="inputspec")

    # AK: watch out, other datasets might be encoded LR
    epi_ap = {'echospacing': 66.5e-3, 'enc_dir': 'y-'}
    epi_pa = {'echospacing': 66.5e-3, 'enc_dir': 'y'}
    prep = all_fsl_pipeline(epi_params=epi_ap, altepi_params=epi_pa)

    # initialize an overall workflow
    wf = pe.Workflow(name="dmriprep")

    wf.connect(inputspec, 'dwi_file', prep, 'inputnode.in_file')
    wf.connect(inputspec, 'bvec_file', prep, 'inputnode.in_bvec')
    wf.connect(inputspec, 'bval_file', prep, 'inputnode.in_bval')
    wf.connect(inputspec, 'eddy_niter', prep, 'fsl_eddy.niter')

    eddy = prep.get_node('fsl_eddy')
    eddy.inputs.repol = True
    eddy.inputs.cnr_maps = True
    eddy.inputs.residuals = True
    import multiprocessing
    eddy.inputs.num_threads = multiprocessing.cpu_count()

    topup = prep.get_node('peb_correction.topup')
    topup.inputs.checksize = True

    applytopup = prep.get_node('peb_correction.unwarp')
    applytopup.inputs.checksize = True

    eddy.inputs.checksize = True

    eddy_quad = pe.Node(fsl.EddyQuad(verbose=True, checksize=True),
                        name="eddy_quad")
    get_path = lambda x: x.split('.nii.gz')[0].split('_fix')[0]
    wf.connect(prep, ('fsl_eddy.out_corrected', get_path), eddy_quad,
               "base_name")
    wf.connect(inputspec, 'bval_file', eddy_quad, 'bval_file')
    wf.connect(prep, 'Rotate_Bvec.out_file', eddy_quad, 'bvec_file')
    wf.connect(prep, 'peb_correction.topup.out_field', eddy_quad, 'field')
    wf.connect(prep, 'gen_index.out_file', eddy_quad, 'idx_file')
    wf.connect(prep, 'peb_correction.topup.out_enc_file', eddy_quad,
               'param_file')

    # need a mask file for eddy_quad. lets get it from the B0.
    def get_b0_mask_fn(b0_file):
        import nibabel as nib
        from nipype.utils.filemanip import fname_presuffix
        from dipy.segment.mask import median_otsu
        import os

        mask_file = fname_presuffix(b0_file,
                                    suffix="_mask",
                                    newpath=os.path.abspath('.'))
        img = nib.load(b0_file)
        data, aff = img.get_data(), img.affine
        _, mask = median_otsu(data, 2, 1)
        nib.Nifti1Image(mask.astype(float), aff).to_filename(mask_file)
        return mask_file

    def id_outliers_fn(outlier_report, threshold, dwi_file):
        """Get list of scans that exceed threshold for number of outliers

        Parameters
        ----------
        outlier_report: string
            Path to the fsl_eddy outlier report

        threshold: int or float
            If threshold is an int, it is treated as number of allowed outlier
            slices. If threshold is a float between 0 and 1 (exclusive), it is
            treated the fraction of allowed outlier slices before we drop the
            whole volume.

        dwi_file: string
            Path to nii dwi file to determine total number of slices

        Returns
        -------
        drop_scans: numpy.ndarray
            List of scan indices to drop
        """
        import nibabel as nib
        import numpy as np
        import os.path as op
        import parse

        with open(op.abspath(outlier_report), 'r') as fp:
            lines = fp.readlines()

        p = parse.compile(
            "Slice {slice:d} in scan {scan:d} is an outlier with "
            "mean {mean_sd:f} standard deviations off, and mean "
            "squared {mean_sq_sd:f} standard deviations off.")

        outliers = [p.parse(l).named for l in lines]
        scans = {d['scan'] for d in outliers}

        def num_outliers(scan, outliers):
            return len([d for d in outliers if d['scan'] == scan])

        if 0 < threshold < 1:
            img = nib.load(dwi_file)
            try:
                threshold *= img.header.get_n_slices()
            except nib.spatialimages.HeaderDataError:
                print(
                    'WARNING. We are not sure which dimension has the '
                    'slices in this image. So we are using the 3rd dim.',
                    img.shape)
                threshold *= img.shape[2]

        drop_scans = np.array(
            [s for s in scans if num_outliers(s, outliers) > threshold])

        outpath = op.abspath("dropped_scans.txt")
        np.savetxt(outpath, drop_scans, fmt="%d")

        return drop_scans, outpath

    id_outliers_node = pe.Node(niu.Function(
        input_names=["outlier_report", "threshold", "dwi_file"],
        output_names=["drop_scans", "outpath"],
        function=id_outliers_fn),
                               name="id_outliers_node")

    wf.connect(inputspec, 'dwi_file', id_outliers_node, 'dwi_file')
    wf.connect(inputspec, 'slice_outlier_threshold', id_outliers_node,
               'threshold')

    wf.connect(prep, "fsl_eddy.out_outlier_report", id_outliers_node,
               "outlier_report")

    list_merge = pe.Node(niu.Merge(numinputs=2), name="list_merge")
    wf.connect(inputspec, 'dwi_file_ap', list_merge, 'in1')
    wf.connect(inputspec, 'dwi_file_pa', list_merge, 'in2')

    merge = pe.Node(fsl.Merge(dimension='t'), name="mergeAPPA")
    wf.connect(merge, 'merged_file', prep, 'inputnode.alt_file')
    wf.connect(list_merge, 'out', merge, 'in_files')

    fslroi = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="fslroi")
    wf.connect(prep, "outputnode.out_file", fslroi, "in_file")

    b0mask_node = pe.Node(niu.Function(input_names=['b0_file'],
                                       output_names=['mask_file'],
                                       function=get_b0_mask_fn),
                          name="getB0Mask")
    wf.connect(fslroi, 'roi_file', b0mask_node, 'b0_file')
    wf.connect(b0mask_node, 'mask_file', eddy_quad, 'mask_file')

    bbreg = pe.Node(
        fs.BBRegister(
            contrast_type="t2",
            init="coreg",
            out_fsl_file=True,
            # subjects_dir=subjects_dir,
            epi_mask=True),
        name="bbreg")
    bbreg.inputs.subject_id = 'freesurfer'  # bids_sub_name
    wf.connect(fslroi, "roi_file", bbreg, "source_file")
    wf.connect(inputspec, 'subjects_dir', bbreg, 'subjects_dir')

    def drop_outliers_fn(in_file, in_bval, in_bvec, drop_scans):
        """Drop outlier volumes from dwi file

        Parameters
        ----------
        in_file: string
            Path to nii dwi file to drop outlier volumes from

        in_bval: string
            Path to bval file to drop outlier volumes from

        in_bvec: string
            Path to bvec file to drop outlier volumes from

        drop_scans: numpy.ndarray
            List of scan indices to drop

        Returns
        -------
        out_file: string
            Path to "thinned" output dwi file

        out_bval: string
            Path to "thinned" output bval file

        out_bvec: string
            Path to "thinned" output bvec file
        """
        import nibabel as nib
        import numpy as np
        import os.path as op
        from nipype.utils.filemanip import fname_presuffix

        img = nib.load(op.abspath(in_file))
        img_data = img.get_data()
        img_data_thinned = np.delete(img_data, drop_scans, axis=3)
        if isinstance(img, nib.nifti1.Nifti1Image):
            img_thinned = nib.Nifti1Image(img_data_thinned.astype(np.float64),
                                          img.affine,
                                          header=img.header)
        elif isinstance(img, nib.nifti2.Nifti2Image):
            img_thinned = nib.Nifti2Image(img_data_thinned.astype(np.float64),
                                          img.affine,
                                          header=img.header)
        else:
            raise TypeError("in_file does not contain Nifti image datatype.")

        out_file = fname_presuffix(in_file,
                                   suffix="_thinned",
                                   newpath=op.abspath('.'))
        nib.save(img_thinned, op.abspath(out_file))

        bval = np.loadtxt(in_bval)
        bval_thinned = np.delete(bval, drop_scans, axis=0)
        out_bval = fname_presuffix(in_bval,
                                   suffix="_thinned",
                                   newpath=op.abspath('.'))
        np.savetxt(out_bval, bval_thinned)

        bvec = np.loadtxt(in_bvec)
        bvec_thinned = np.delete(bvec, drop_scans, axis=1)
        out_bvec = fname_presuffix(in_bvec,
                                   suffix="_thinned",
                                   newpath=op.abspath('.'))
        np.savetxt(out_bvec, bvec_thinned)

        return out_file, out_bval, out_bvec

    drop_outliers_node = pe.Node(niu.Function(
        input_names=["in_file", "in_bval", "in_bvec", "drop_scans"],
        output_names=["out_file", "out_bval", "out_bvec"],
        function=drop_outliers_fn),
                                 name="drop_outliers_node")

    # Align the output of drop_outliers_node & also the eddy corrected version to the anatomical space
    # without resampling. and then for aparc+aseg & the mask, resample to the larger voxel size of the B0 image from
    # fslroi. Also we need to apply the transformation to both bvecs (dropped & eddied) and I think we can just load
    # the affine from bbreg (sio.loadmat) and np.dot(coord, aff) for each coord in bvec

    def get_orig(subjects_dir, sub='freesurfer'):
        import os.path as op
        return op.join(subjects_dir, sub, "mri", "orig.mgz")

    def get_aparc_aseg(subjects_dir, sub='freesurfer'):
        import os.path as op
        return op.join(subjects_dir, sub, "mri", "aparc+aseg.mgz")

    # transform the dropped volume version to anat space w/ out resampling
    voltransform = pe.Node(fs.ApplyVolTransform(no_resample=True),
                           iterfield=['source_file', 'reg_file'],
                           name='transform')

    wf.connect(inputspec, 'subjects_dir', voltransform, 'subjects_dir')
    wf.connect(inputspec, ('subjects_dir', get_aparc_aseg), voltransform,
               'target_file')
    wf.connect(prep, "outputnode.out_file", voltransform, "source_file")
    wf.connect(bbreg, "out_reg_file", voltransform, "reg_file")

    def apply_transform_to_bvecs_fn(bvec_file, reg_mat_file):
        import numpy as np
        import nipype.utils.filemanip as fm
        import os
        aff = np.loadtxt(reg_mat_file)
        bvecs = np.loadtxt(bvec_file)
        bvec_trans = []
        for bvec in bvecs.T:
            coord = np.hstack((bvec, [1]))
            coord_trans = np.dot(coord, aff)[:-1]
            bvec_trans.append(coord_trans)
        out_bvec = fm.fname_presuffix(bvec_file,
                                      suffix="anat_space",
                                      newpath=os.path.abspath('.'))
        np.savetxt(out_bvec, np.asarray(bvec_trans).T)
        return out_bvec

    apply_transform_to_bvecs_node = pe.Node(niu.Function(
        input_names=['bvec_file', 'reg_mat_file'],
        output_names=['out_bvec'],
        function=apply_transform_to_bvecs_fn),
                                            name="applyTransformToBvecs")
    wf.connect(bbreg, 'out_fsl_file', apply_transform_to_bvecs_node,
               'reg_mat_file')
    wf.connect(prep, 'outputnode.out_bvec', apply_transform_to_bvecs_node,
               'bvec_file')

    # ok cool, now lets do the thresholding.

    wf.connect(id_outliers_node, "drop_scans", drop_outliers_node,
               "drop_scans")
    wf.connect(voltransform, "transformed_file", drop_outliers_node, "in_file")
    wf.connect(inputspec, 'bval_file', drop_outliers_node, 'in_bval')
    wf.connect(apply_transform_to_bvecs_node, "out_bvec", drop_outliers_node,
               "in_bvec")

    # lets compute the tensor on both the dropped volume scan
    # and also the original, eddy corrected one.
    get_tensor = pe.Node(DTI(), name="dipy_tensor")
    wf.connect(drop_outliers_node, "out_file", get_tensor, "in_file")
    wf.connect(drop_outliers_node, "out_bval", get_tensor, "in_bval")
    wf.connect(drop_outliers_node, "out_bvec", get_tensor, "in_bvec")

    get_tensor_eddy = get_tensor.clone('dipy_tensor_eddy')
    wf.connect(voltransform, 'transformed_file', get_tensor_eddy, "in_file")
    wf.connect(apply_transform_to_bvecs_node, 'out_bvec', get_tensor_eddy,
               "in_bvec")
    wf.connect(inputspec, 'bval_file', get_tensor_eddy, 'in_bval')

    # AK: What is this, some vestigal node from a previous workflow?
    # I'm not sure why the tensor gets scaled. but i guess lets scale it for
    # both the dropped & eddy corrected versions.
    scale_tensor = pe.Node(name='scale_tensor', interface=fsl.BinaryMaths())
    scale_tensor.inputs.operation = 'mul'
    scale_tensor.inputs.operand_value = 1000
    wf.connect(get_tensor, 'out_file', scale_tensor, 'in_file')

    scale_tensor_eddy = scale_tensor.clone('scale_tensor_eddy')
    wf.connect(get_tensor_eddy, 'out_file', scale_tensor_eddy, 'in_file')

    # OK now that anatomical stuff (segmentation & mask)
    # We'll need:
    # 1. the B0 image in anat space (fslroi the 'transformed file' of voltransform
    # 2. the aparc aseg resampled-like the B0 image (mri_convert)
    # 3. the resample aparc_aseg binarized to be the mask image.

    def binarize_aparc(aparc_aseg):
        import nibabel as nib
        from nipype.utils.filemanip import fname_presuffix
        import os.path as op
        img = nib.load(aparc_aseg)
        data, aff = img.get_data(), img.affine
        outfile = fname_presuffix(aparc_aseg,
                                  suffix="bin.nii.gz",
                                  newpath=op.abspath("."),
                                  use_ext=False)
        nib.Nifti1Image((data > 0).astype(float), aff).to_filename(outfile)
        return outfile

    create_mask = pe.Node(niu.Function(input_names=["aparc_aseg"],
                                       output_names=["outfile"],
                                       function=binarize_aparc),
                          name="bin_aparc")

    get_b0_anat = fslroi.clone('get_b0_anat')
    wf.connect(voltransform, 'transformed_file', get_b0_anat, 'in_file')

    # reslice the anat-space aparc+aseg to the DWI resolution
    reslice_to_dwi = pe.Node(fs.MRIConvert(resample_type="nearest"),
                             name="reslice_to_dwi")
    wf.connect(get_b0_anat, 'roi_file', reslice_to_dwi, 'reslice_like')
    wf.connect(inputspec, ('subjects_dir', get_aparc_aseg), reslice_to_dwi,
               'in_file')

    # also reslice the orig i suppose
    reslice_orig_to_dwi = reslice_to_dwi.clone('resliceT1wToDwi')
    wf.connect(inputspec, ('subjects_dir', get_orig), reslice_orig_to_dwi,
               'in_file')
    # reslice_orig_to_dwi.inputs.in_file = get_orig(subjects_dir, 'freesurfer')
    reslice_orig_to_dwi.inputs.out_type = 'niigz'
    wf.connect(get_b0_anat, 'roi_file', reslice_orig_to_dwi, 'reslice_like')

    # we assume the freesurfer is the output of BIDS
    # so the freesurfer output is in /path/to/derivatives/sub-whatever/freesurfer
    # which means the subject_dir is /path/to/derivatives/sub-whatever
    # reslice_to_dwi.inputs.in_file = get_aparc_aseg(subjects_dir, 'freesurfer')

    # now we have a nice aparc+aseg still in anat space but resliced like the dwi file
    # lets create a mask file from it.

    wf.connect(reslice_to_dwi, 'out_file', create_mask, 'aparc_aseg')

    # save all the things
    datasink = pe.Node(nio.DataSink(), name="sinker")
    wf.connect(inputspec, 'out_dir', datasink, 'base_directory')
    wf.connect(inputspec, 'subject_id', datasink, 'container')

    wf.connect(drop_outliers_node, "out_file", datasink,
               "dmriprep.dwi.@thinned")
    wf.connect(drop_outliers_node, "out_bval", datasink,
               "dmriprep.dwi.@bval_thinned")
    wf.connect(drop_outliers_node, "out_bvec", datasink,
               "dmriprep.dwi.@bvec_thinned")

    # eddy corrected files
    wf.connect(prep, "outputnode.out_file", datasink,
               "dmriprep.dwi_eddy.@corrected")
    wf.connect(prep, "outputnode.out_bvec", datasink,
               "dmriprep.dwi_eddy.@rotated")
    wf.connect(inputspec, 'bval_file', datasink, 'dmriprep.dwi_eddy.@bval')

    # all the eddy stuff except the corrected files
    wf.connect(prep, "fsl_eddy.out_movement_rms", datasink,
               "dmriprep.qc.@eddyparamsrms")
    wf.connect(prep, "fsl_eddy.out_outlier_report", datasink,
               "dmriprep.qc.@eddyparamsreport")
    wf.connect(prep, "fsl_eddy.out_restricted_movement_rms", datasink,
               "dmriprep.qc.@eddyparamsrestrictrms")
    wf.connect(prep, "fsl_eddy.out_shell_alignment_parameters", datasink,
               "dmriprep.qc.@eddyparamsshellalign")
    wf.connect(prep, "fsl_eddy.out_parameter", datasink,
               "dmriprep.qc.@eddyparams")
    wf.connect(prep, "fsl_eddy.out_cnr_maps", datasink,
               "dmriprep.qc.@eddycndr")
    wf.connect(prep, "fsl_eddy.out_residuals", datasink,
               "dmriprep.qc.@eddyresid")

    # the file that told us which volumes to drop
    wf.connect(id_outliers_node, "outpath", datasink,
               "dmriprep.qc.@droppedscans")

    # the tensors of the dropped volumes dwi
    wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@tensor")
    wf.connect(get_tensor, "fa_file", datasink, "dmriprep.dti.@fa")
    wf.connect(get_tensor, "md_file", datasink, "dmriprep.dti.@md")
    wf.connect(get_tensor, "ad_file", datasink, "dmriprep.dti.@ad")
    wf.connect(get_tensor, "rd_file", datasink, "dmriprep.dti.@rd")
    wf.connect(get_tensor, "color_fa_file", datasink, "dmriprep.dti.@colorfa")
    wf.connect(scale_tensor, "out_file", datasink,
               "dmriprep.dti.@scaled_tensor")

    # the tensors of the eddied volumes dwi
    wf.connect(get_tensor_eddy, "out_file", datasink,
               "dmriprep.dti_eddy.@tensor")
    wf.connect(get_tensor_eddy, "fa_file", datasink, "dmriprep.dti_eddy.@fa")
    wf.connect(get_tensor_eddy, "md_file", datasink, "dmriprep.dti_eddy.@md")
    wf.connect(get_tensor_eddy, "ad_file", datasink, "dmriprep.dti_eddy.@ad")
    wf.connect(get_tensor_eddy, "rd_file", datasink, "dmriprep.dti_eddy.@rd")
    wf.connect(get_tensor_eddy, "color_fa_file", datasink,
               "dmriprep.dti_eddy.@colorfa")
    wf.connect(scale_tensor_eddy, "out_file", datasink,
               "dmriprep.dti_eddy.@scaled_tensor")

    # all the eddy_quad stuff
    wf.connect(eddy_quad, 'out_qc_json', datasink,
               "dmriprep.qc.@eddyquad_json")
    wf.connect(eddy_quad, 'out_qc_pdf', datasink, "dmriprep.qc.@eddyquad_pdf")
    wf.connect(eddy_quad, 'out_avg_b_png', datasink,
               "dmriprep.qc.@eddyquad_bpng")
    wf.connect(eddy_quad, 'out_avg_b0_pe_png', datasink,
               "dmriprep.qc.@eddyquad_b0png")
    wf.connect(eddy_quad, 'out_cnr_png', datasink, "dmriprep.qc.@eddyquad_cnr")
    wf.connect(eddy_quad, 'out_vdm_png', datasink, "dmriprep.qc.@eddyquad_vdm")
    wf.connect(eddy_quad, 'out_residuals', datasink,
               'dmriprep.qc.@eddyquad_resid')

    # anatomical registration stuff
    wf.connect(bbreg, "min_cost_file", datasink, "dmriprep.reg.@mincost")
    wf.connect(bbreg, "out_fsl_file", datasink, "dmriprep.reg.@fslfile")
    wf.connect(bbreg, "out_reg_file", datasink, "dmriprep.reg.@reg")

    # anatomical files resliced
    wf.connect(reslice_to_dwi, 'out_file', datasink,
               'dmriprep.anat.@segmentation')
    wf.connect(create_mask, 'outfile', datasink, 'dmriprep.anat.@mask')
    wf.connect(reslice_orig_to_dwi, 'out_file', datasink, 'dmriprep.anat.@T1w')

    def report_fn(dwi_corrected_file, eddy_rms, eddy_report, color_fa_file,
                  anat_mask_file, outlier_indices, eddy_qc_file):
        from dmriprep.qc import create_report_json

        report = create_report_json(dwi_corrected_file, eddy_rms, eddy_report,
                                    color_fa_file, anat_mask_file,
                                    outlier_indices, eddy_qc_file)
        return report

    report_node = pe.Node(niu.Function(input_names=[
        'dwi_corrected_file', 'eddy_rms', 'eddy_report', 'color_fa_file',
        'anat_mask_file', 'outlier_indices', 'eddy_qc_file'
    ],
                                       output_names=['report'],
                                       function=report_fn),
                          name="reportJSON")

    # for the report, lets show the eddy corrected (full volume) image
    wf.connect(voltransform, "transformed_file", report_node,
               'dwi_corrected_file')
    wf.connect(eddy_quad, 'out_qc_json', report_node, 'eddy_qc_file')

    # add the rms movement output from eddy
    wf.connect(prep, "fsl_eddy.out_movement_rms", report_node, 'eddy_rms')
    wf.connect(prep, "fsl_eddy.out_outlier_report", report_node, 'eddy_report')
    wf.connect(id_outliers_node, 'drop_scans', report_node, 'outlier_indices')

    # the mask file to check our registration, and the colorFA file go in the report
    wf.connect(create_mask, "outfile", report_node, 'anat_mask_file')
    wf.connect(get_tensor, "color_fa_file", report_node, 'color_fa_file')

    # save that report!
    wf.connect(report_node, 'report', datasink, 'dmriprep.report.@report')

    # this part is done last, to get the filenames *just right*
    # its super annoying.
    def name_files_nicely(dwi_file, subject_id):
        import os.path as op
        dwi_fname = op.split(dwi_file)[1].split(".nii.gz")[0]
        substitutions = [
            ("vol0000_flirt_merged.nii.gz", dwi_fname + '.nii.gz'),
            ("stats.vol0000_flirt_merged.txt", dwi_fname + ".art.json"),
            ("motion_parameters.par", dwi_fname + ".motion.txt"),
            ("_rotated.bvec", ".bvec"),
            ("art.vol0000_flirt_merged_outliers.txt",
             dwi_fname + ".outliers.txt"), ("vol0000_flirt_merged", dwi_fname),
            ("_roi_bbreg_freesurfer", "_register"),
            ("dwi/eddy_corrected", "dwi/%s" % dwi_fname),
            ("dti/eddy_corrected", "dti/%s" % dwi_fname.replace("_dwi", "")),
            ("reg/eddy_corrected", "reg/%s" % dwi_fname.replace("_dwi", "")),
            ("aparc+aseg_outbin", dwi_fname.replace("_dwi", "_mask")),
            ("aparc+aseg_out", dwi_fname.replace("_dwi", "_aparc+aseg")),
            ("art.eddy_corrected_outliers",
             dwi_fname.replace("dwi", "outliers")), ("color_fa", "colorfa"),
            ("orig_out", dwi_fname.replace("_dwi", "_T1w")),
            ("stats.eddy_corrected", dwi_fname.replace("dwi", "artStats")),
            ("eddy_corrected.eddy_parameters", dwi_fname + ".eddy_parameters"),
            ("qc/eddy_corrected", "qc/" + dwi_fname),
            ("derivatives/dmriprep",
             "derivatives/{}/dmriprep".format(subject_id)),
            ("_rotatedanat_space_thinned", ""), ("_thinned", ""),
            ("eddy_corrected", dwi_fname), ("_warped", ""),
            ("_maths", "_scaled"),
            ("dropped_scans", dwi_fname.replace("_dwi", "_dwi_dropped_scans")),
            ("report.json", dwi_fname.replace("_dwi", "_dwi_report.json"))
        ]
        return substitutions

    node_name_files_nicely = pe.Node(niu.Function(
        input_names=['dwi_file', 'subject_id'],
        output_names=['substitutions'],
        function=name_files_nicely),
                                     name="name_files_nicely")
    wf.connect(inputspec, 'dwi_file', node_name_files_nicely, 'dwi_file')
    wf.connect(inputspec, 'subject_id', node_name_files_nicely, 'subject_id')
    wf.connect(node_name_files_nicely, 'substitutions', datasink,
               'substitutions')

    return wf
Example #20
0
def create_confound_removal_workflow(workflow_name="confound_removal"):

    inputnode = pe.Node(util.IdentityInterface(
        fields=["subject_id", "timeseries", "reg_file", "motion_parameters"]),
                        name="inputs")

    # Get the Freesurfer aseg volume from the Subjects Directory
    getaseg = pe.Node(io.FreeSurferSource(subjects_dir=fs.Info.subjectsdir()),
                      name="getaseg")

    # Binarize the Aseg to use as a whole brain mask
    asegmask = pe.Node(fs.Binarize(min=0.5, dilate=2), name="asegmask")

    # Extract and erode a mask of the deep cerebral white matter
    extractwm = pe.Node(fs.Binarize(match=[2, 41], erode=3), name="extractwm")

    # Extract and erode a mask of the ventricles and CSF
    extractcsf = pe.Node(fs.Binarize(match=[4, 5, 14, 15, 24, 31, 43, 44, 63],
                                     erode=1),
                         name="extractcsf")

    # Mean the timeseries across the fourth dimension
    meanfunc = pe.MapNode(fsl.MeanImage(),
                          iterfield=["in_file"],
                          name="meanfunc")

    # Invert the anatomical coregistration and resample the masks
    regwm = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"),
                       iterfield=["source_file", "reg_file"],
                       name="regwm")

    regcsf = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"),
                        iterfield=["source_file", "reg_file"],
                        name="regcsf")

    regbrain = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"),
                          iterfield=["source_file", "reg_file"],
                          name="regbrain")

    # Convert to Nifti for FSL tools
    convertwm = pe.MapNode(fs.MRIConvert(out_type="niigz"),
                           iterfield=["in_file"],
                           name="convertwm")

    convertcsf = pe.MapNode(fs.MRIConvert(out_type="niigz"),
                            iterfield=["in_file"],
                            name="convertcsf")

    convertbrain = pe.MapNode(fs.MRIConvert(out_type="niigz"),
                              iterfield=["in_file"],
                              name="convertbrain")

    # Add the mask images together for a report image
    addconfmasks = pe.MapNode(fsl.ImageMaths(suffix="conf",
                                             op_string="-mul 2 -add",
                                             out_data_type="char"),
                              iterfield=["in_file", "in_file2"],
                              name="addconfmasks")

    # Overlay and slice the confound mask overlaied on mean func for reporting
    confoverlay = pe.MapNode(fsl.Overlay(auto_thresh_bg=True,
                                         stat_thresh=(.7, 2)),
                             iterfield=["background_image", "stat_image"],
                             name="confoverlay")

    confslice = pe.MapNode(fsl.Slicer(image_width=800, label_slices=False),
                           iterfield=["in_file"],
                           name="confslice")
    confslice.inputs.sample_axial = 2

    # Extract the mean signal from white matter and CSF masks
    wmtcourse = pe.MapNode(fs.SegStats(exclude_id=0, avgwf_txt_file=True),
                           iterfield=["segmentation_file", "in_file"],
                           name="wmtcourse")

    csftcourse = pe.MapNode(fs.SegStats(exclude_id=0, avgwf_txt_file=True),
                            iterfield=["segmentation_file", "in_file"],
                            name="csftcourse")

    # Extract the mean signal from over the whole brain
    globaltcourse = pe.MapNode(fs.SegStats(exclude_id=0, avgwf_txt_file=True),
                               iterfield=["segmentation_file", "in_file"],
                               name="globaltcourse")

    # Build the confound design matrix
    conf_inputs = [
        "motion_params", "global_waveform", "wm_waveform", "csf_waveform"
    ]
    confmatrix = pe.MapNode(util.Function(input_names=conf_inputs,
                                          output_names=["confound_matrix"],
                                          function=make_confound_matrix),
                            iterfield=conf_inputs,
                            name="confmatrix")

    # Regress the confounds out of the timeseries
    confregress = pe.MapNode(fsl.FilterRegressor(filter_all=True),
                             iterfield=["in_file", "design_file", "mask"],
                             name="confregress")

    # Rename the confound mask png
    renamepng = pe.MapNode(util.Rename(format_string="confound_sources.png"),
                           iterfield=["in_file"],
                           name="renamepng")

    # Define the outputs
    outputnode = pe.Node(
        util.IdentityInterface(fields=["timeseries", "confound_sources"]),
        name="outputs")

    # Define and connect the confound workflow
    confound = pe.Workflow(name=workflow_name)

    confound.connect([
        (inputnode, meanfunc, [("timeseries", "in_file")]),
        (inputnode, getaseg, [("subject_id", "subject_id")]),
        (getaseg, extractwm, [("aseg", "in_file")]),
        (getaseg, extractcsf, [("aseg", "in_file")]),
        (getaseg, asegmask, [("aseg", "in_file")]),
        (extractwm, regwm, [("binary_file", "target_file")]),
        (extractcsf, regcsf, [("binary_file", "target_file")]),
        (asegmask, regbrain, [("binary_file", "target_file")]),
        (meanfunc, regwm, [("out_file", "source_file")]),
        (meanfunc, regcsf, [("out_file", "source_file")]),
        (meanfunc, regbrain, [("out_file", "source_file")]),
        (inputnode, regwm, [("reg_file", "reg_file")]),
        (inputnode, regcsf, [("reg_file", "reg_file")]),
        (inputnode, regbrain, [("reg_file", "reg_file")]),
        (regwm, convertwm, [("transformed_file", "in_file")]),
        (regcsf, convertcsf, [("transformed_file", "in_file")]),
        (regbrain, convertbrain, [("transformed_file", "in_file")]),
        (convertwm, addconfmasks, [("out_file", "in_file")]),
        (convertcsf, addconfmasks, [("out_file", "in_file2")]),
        (addconfmasks, confoverlay, [("out_file", "stat_image")]),
        (meanfunc, confoverlay, [("out_file", "background_image")]),
        (confoverlay, confslice, [("out_file", "in_file")]),
        (confslice, renamepng, [("out_file", "in_file")]),
        (regwm, wmtcourse, [("transformed_file", "segmentation_file")]),
        (inputnode, wmtcourse, [("timeseries", "in_file")]),
        (regcsf, csftcourse, [("transformed_file", "segmentation_file")]),
        (inputnode, csftcourse, [("timeseries", "in_file")]),
        (regbrain, globaltcourse, [("transformed_file", "segmentation_file")]),
        (inputnode, globaltcourse, [("timeseries", "in_file")]),
        (inputnode, confmatrix, [("motion_parameters", "motion_params")]),
        (wmtcourse, confmatrix, [("avgwf_txt_file", "wm_waveform")]),
        (csftcourse, confmatrix, [("avgwf_txt_file", "csf_waveform")]),
        (globaltcourse, confmatrix, [("avgwf_txt_file", "global_waveform")]),
        (confmatrix, confregress, [("confound_matrix", "design_file")]),
        (inputnode, confregress, [("timeseries", "in_file")]),
        (convertbrain, confregress, [("out_file", "mask")]),
        (confregress, outputnode, [("out_file", "timeseries")]),
        (renamepng, outputnode, [("out_file", "confound_sources")]),
    ])

    return confound
def create_spm_preproc(c, name='preproc'):
    """
"""

    from nipype.workflows.smri.freesurfer.utils import create_getmask_flow
    import nipype.algorithms.rapidart as ra
    import nipype.interfaces.spm as spm
    import nipype.interfaces.utility as niu
    import nipype.pipeline.engine as pe
    import nipype.interfaces.io as nio
    import nipype.interfaces.freesurfer as fs

    workflow = pe.Workflow(name=name)

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'functionals', 'subject_id', 'subjects_dir', 'fwhm', 'norm_threshold',
        'zintensity_threshold', 'tr', 'do_slicetime', 'sliceorder',
        'parameters', 'node', 'csf_prob', 'wm_prob', 'gm_prob'
    ]),
                        name='inputspec')

    poplist = lambda x: x.pop()

    sym_func = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_link'],
                                    function=do_symlink),
                       name='func_symlink')

    # REALIGN

    realign = pe.Node(niu.Function(
        input_names=[
            'node', 'in_file', 'tr', 'do_slicetime', 'sliceorder', 'parameters'
        ],
        output_names=['out_file', 'par_file', 'parameter_source'],
        function=mod_realign),
                      name="mod_realign")
    workflow.connect(inputnode, 'parameters', realign, 'parameters')
    workflow.connect(inputnode, 'functionals', realign, 'in_file')
    workflow.connect(inputnode, 'tr', realign, 'tr')
    workflow.connect(inputnode, 'do_slicetime', realign, 'do_slicetime')
    workflow.connect(inputnode, 'sliceorder', realign, 'sliceorder')
    workflow.connect(inputnode, 'node', realign, 'node')

    # TAKE MEAN IMAGE

    mean = art_mean_workflow()
    workflow.connect(realign, 'out_file', mean, 'inputspec.realigned_files')
    workflow.connect(realign, 'par_file', mean,
                     'inputspec.realignment_parameters')
    workflow.connect(realign, 'parameter_source', mean,
                     'inputspec.parameter_source')

    # CREATE BRAIN MASK

    maskflow = create_getmask_flow()
    workflow.connect([(inputnode, maskflow,
                       [('subject_id', 'inputspec.subject_id'),
                        ('subjects_dir', 'inputspec.subjects_dir')])])
    maskflow.inputs.inputspec.contrast_type = 't2'
    workflow.connect(mean, 'outputspec.mean_image', maskflow,
                     'inputspec.source_file')

    # SEGMENT

    segment = pe.Node(spm.Segment(csf_output_type=[True, True, False],
                                  gm_output_type=[True, True, False],
                                  wm_output_type=[True, True, False]),
                      name='segment')
    mergefunc = lambda in1, in2, in3: [in1, in2, in3]

    merge = pe.Node(niu.Function(input_names=['in1', 'in2', 'in3'],
                                 output_names=['out'],
                                 function=mergefunc),
                    name='merge')
    workflow.connect(inputnode, 'csf_prob', merge, 'in3')
    workflow.connect(inputnode, 'wm_prob', merge, 'in2')
    workflow.connect(inputnode, 'gm_prob', merge, 'in1')

    sym_prob = sym_func
    workflow.connect(merge, 'out', sym_prob, 'in_file')
    workflow.connect(sym_prob, 'out_link', segment, 'tissue_prob_maps')

    xform_mask = pe.Node(fs.ApplyVolTransform(fs_target=True),
                         name='transform_mask')
    workflow.connect(maskflow, ('outputspec.reg_file', pickfirst), xform_mask,
                     'reg_file')
    workflow.connect(maskflow, ('outputspec.mask_file', pickfirst), xform_mask,
                     'source_file')
    workflow.connect(xform_mask, "transformed_file", segment, 'mask_image')

    fssource = maskflow.get_node('fssource')
    convert2nii = pe.Node(fs.MRIConvert(in_type='mgz', out_type='nii'),
                          name='convert2nii')
    workflow.connect(fssource, 'brain', convert2nii, 'in_file')
    workflow.connect(convert2nii, 'out_file', segment, 'data')

    # NORMALIZE

    normalize = pe.MapNode(spm.Normalize(jobtype='write'),
                           name='normalize',
                           iterfield=['apply_to_files'])
    normalize_struct = normalize.clone('normalize_struct')
    normalize_mask = normalize.clone('normalize_mask')

    workflow.connect(segment, 'transformation_mat', normalize,
                     'parameter_file')
    workflow.connect(segment, 'transformation_mat', normalize_mask,
                     'parameter_file')
    workflow.connect(segment, 'transformation_mat', normalize_struct,
                     'parameter_file')
    workflow.connect(convert2nii, 'out_file', normalize_struct,
                     'apply_to_files')
    workflow.connect(xform_mask, "transformed_file", normalize_mask,
                     'apply_to_files')

    xform_image = pe.MapNode(fs.ApplyVolTransform(fs_target=True),
                             name='xform_image',
                             iterfield=['source_file'])
    workflow.connect(maskflow, ('outputspec.reg_file', pickfirst), xform_image,
                     'reg_file')
    workflow.connect(realign, 'out_file', xform_image, "source_file")
    workflow.connect(xform_image, "transformed_file", normalize,
                     "apply_to_files")

    #SMOOTH

    smooth = pe.Node(spm.Smooth(), name='smooth')

    workflow.connect(inputnode, 'fwhm', smooth, 'fwhm')
    workflow.connect(normalize, 'normalized_files', smooth, 'in_files')

    # ART

    artdetect = pe.Node(ra.ArtifactDetect(mask_type='file',
                                          use_differences=[True, False],
                                          use_norm=True,
                                          save_plot=True),
                        name='artdetect')
    workflow.connect(realign, 'parameter_source', artdetect,
                     'parameter_source')
    workflow.connect([(inputnode, artdetect,
                       [('norm_threshold', 'norm_threshold'),
                        ('zintensity_threshold', 'zintensity_threshold')])])
    workflow.connect([(realign, artdetect, [('out_file', 'realigned_files'),
                                            ('par_file',
                                             'realignment_parameters')])])
    workflow.connect(maskflow, ('outputspec.mask_file', poplist), artdetect,
                     'mask_file')

    # OUTPUTS

    outputnode = pe.Node(niu.IdentityInterface(fields=[
        "realignment_parameters", "smoothed_files", "mask_file", "mean_image",
        "reg_file", "reg_cost", 'outlier_files', 'outlier_stats',
        'outlier_plots', 'norm_components', 'mod_csf', 'unmod_csf', 'mod_wm',
        'unmod_wm', 'mod_gm', 'unmod_gm', 'mean', 'normalized_struct',
        'normalization_parameters', 'reverse_normalize_parameters'
    ]),
                         name="outputspec")
    workflow.connect([
        (maskflow, outputnode, [("outputspec.reg_file", "reg_file")]),
        (maskflow, outputnode, [("outputspec.reg_cost", "reg_cost")]),
        (realign, outputnode, [('par_file', 'realignment_parameters')]),
        (smooth, outputnode, [('smoothed_files', 'smoothed_files')]),
        (artdetect, outputnode, [('outlier_files', 'outlier_files'),
                                 ('statistic_files', 'outlier_stats'),
                                 ('plot_files', 'outlier_plots'),
                                 ('norm_files', 'norm_components')])
    ])
    workflow.connect(normalize_mask, "normalized_files", outputnode,
                     "mask_file")
    workflow.connect(segment, 'modulated_csf_image', outputnode, 'mod_csf')
    workflow.connect(segment, 'modulated_wm_image', outputnode, 'mod_wm')
    workflow.connect(segment, 'modulated_gm_image', outputnode, 'mod_gm')
    workflow.connect(segment, 'normalized_csf_image', outputnode, 'unmod_csf')
    workflow.connect(segment, 'normalized_wm_image', outputnode, 'unmod_wm')
    workflow.connect(segment, 'normalized_gm_image', outputnode, 'unmod_gm')
    workflow.connect(mean, 'outputspec.mean_image', outputnode, 'mean')
    workflow.connect(normalize_struct, 'normalized_files', outputnode,
                     'normalized_struct')
    workflow.connect(segment, 'transformation_mat', outputnode,
                     'normalization_parameters')
    workflow.connect(segment, 'inverse_transformation_mat', outputnode,
                     'reverse_normalize_parameters')

    # CONNECT TO CONFIG

    workflow.inputs.inputspec.fwhm = c.fwhm
    workflow.inputs.inputspec.subjects_dir = c.surf_dir
    workflow.inputs.inputspec.norm_threshold = c.norm_thresh
    workflow.inputs.inputspec.zintensity_threshold = c.z_thresh
    workflow.inputs.inputspec.node = c.motion_correct_node
    workflow.inputs.inputspec.tr = c.TR
    workflow.inputs.inputspec.do_slicetime = c.do_slicetiming
    workflow.inputs.inputspec.sliceorder = c.SliceOrder
    workflow.inputs.inputspec.csf_prob = c.csf_prob
    workflow.inputs.inputspec.gm_prob = c.grey_prob
    workflow.inputs.inputspec.wm_prob = c.white_prob
    workflow.inputs.inputspec.parameters = {"order": c.order}
    workflow.base_dir = c.working_dir
    workflow.config = {'execution': {'crashdump_dir': c.crash_dir}}

    datagrabber = get_dataflow(c)

    workflow.connect(datagrabber, 'func', inputnode, 'functionals')

    infosource = pe.Node(niu.IdentityInterface(fields=['subject_id']),
                         name='subject_names')
    if not c.test_mode:
        infosource.iterables = ('subject_id', c.subjects)
    else:
        infosource.iterables = ('subject_id', c.subjects[:1])

    workflow.connect(infosource, 'subject_id', inputnode, 'subject_id')
    workflow.connect(infosource, 'subject_id', datagrabber, 'subject_id')
    sub = lambda x: [('_subject_id_%s' % x, '')]

    sinker = pe.Node(nio.DataSink(), name='sinker')
    workflow.connect(infosource, 'subject_id', sinker, 'container')
    workflow.connect(infosource, ('subject_id', sub), sinker, 'substitutions')
    sinker.inputs.base_directory = c.sink_dir
    outputspec = workflow.get_node('outputspec')
    workflow.connect(outputspec, 'realignment_parameters', sinker,
                     'spm_preproc.realignment_parameters')
    workflow.connect(outputspec, 'smoothed_files', sinker,
                     'spm_preproc.smoothed_outputs')
    workflow.connect(outputspec, 'outlier_files', sinker,
                     'spm_preproc.art.@outlier_files')
    workflow.connect(outputspec, 'outlier_stats', sinker,
                     'spm_preproc.art.@outlier_stats')
    workflow.connect(outputspec, 'outlier_plots', sinker,
                     'spm_preproc.art.@outlier_plots')
    workflow.connect(outputspec, 'norm_components', sinker,
                     'spm_preproc.art.@norm')
    workflow.connect(outputspec, 'reg_file', sinker,
                     'spm_preproc.bbreg.@reg_file')
    workflow.connect(outputspec, 'reg_cost', sinker,
                     'spm_preproc.bbreg.@reg_cost')
    workflow.connect(outputspec, 'mask_file', sinker,
                     'spm_preproc.mask.@mask_file')
    workflow.connect(outputspec, 'mod_csf', sinker,
                     'spm_preproc.segment.mod.@csf')
    workflow.connect(outputspec, 'mod_wm', sinker,
                     'spm_preproc.segment.mod.@wm')
    workflow.connect(outputspec, 'mod_gm', sinker,
                     'spm_preproc.segment.mod.@gm')
    workflow.connect(outputspec, 'unmod_csf', sinker,
                     'spm_preproc.segment.unmod.@csf')
    workflow.connect(outputspec, 'unmod_wm', sinker,
                     'spm_preproc.segment.unmod.@wm')
    workflow.connect(outputspec, 'unmod_gm', sinker,
                     'spm_preproc.segment.unmod.@gm')
    workflow.connect(outputspec, 'mean', sinker, 'spm_preproc.mean')
    workflow.connect(outputspec, 'normalized_struct', sinker,
                     'spm_preproc.normalized_struct')
    workflow.connect(outputspec, 'normalization_parameters', sinker,
                     'spm_preproc.normalization_parameters.@forward')
    workflow.connect(outputspec, 'reverse_normalize_parameters', sinker,
                     'spm_preproc.normalization_parameters.@reverse')

    return workflow
Example #22
0
preproc_wf.connect(coregister, 'out_fsl_file', outputspec, 'fsl_reg_file')
preproc_wf.connect(coregister, 'min_cost_file', outputspec, 'reg_cost')

# Register a source file to fs space
fssource = pe.Node(nio.FreeSurferSource(subjects_dir=subjects_dir),
                   name='fssource')
preproc_wf.connect(subj_iterable, 'subject_id', fssource, 'subject_id')

# Extract aparc+aseg brain mask and binarize
fs_threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'),
                       name='fs_threshold')
preproc_wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), fs_threshold,
                   'in_file')

# Transform the binarized aparc+aseg file to the 1st volume of 1st run space
fs_voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True,
                                                  subjects_dir=subjects_dir),
                             iterfield=['source_file', 'reg_file'],
                             name='fs_transform')
preproc_wf.connect(extractref, 'roi_file', fs_voltransform, 'source_file')
preproc_wf.connect(coregister, 'out_reg_file', fs_voltransform, 'reg_file')
preproc_wf.connect(fs_threshold, 'binary_file', fs_voltransform, 'target_file')

# Dilate the binarized mask by 1 voxel that is now in the EPI space
fs_threshold2 = pe.MapNode(fs.Binarize(min=0.5, out_type='nii', dilate=1),
                           iterfield=['in_file'],
                           name='fs_threshold2')
preproc_wf.connect(fs_voltransform, 'transformed_file', fs_threshold2,
                   'in_file')
preproc_wf.connect(fs_threshold2, 'binary_file', outputspec, 'mask_file')

# Mask the functional runs with the extracted mask
Example #23
0
# Transform right hemisphere
surf2volNode_rh = surf2volNode_lh.clone('surf2vol_rh')
surf2volNode_rh.inputs.hemi = 'rh'

# Merge the hemispheres
mergeHemisNode = Node(fsl.BinaryMaths(), name='mergeHemis')
mergeHemisNode.inputs.operation = 'add'
mergeHemisNode.inputs.output_type = 'NIFTI_GZ'

# ### Registration

# In[ ]:

# Rotate high-res (1mm) WM-border to match dwi data w/o resampling
applyReg_anat2diff_1mm = Node(freesurfer.ApplyVolTransform(),
                              name='wmoutline2diff_1mm')
applyReg_anat2diff_1mm.inputs.inverse = True
applyReg_anat2diff_1mm.inputs.interp = 'nearest'
applyReg_anat2diff_1mm.inputs.no_resample = True
applyReg_anat2diff_1mm.inputs.args = '--no-save-reg'

# Rotate high-res (1mm) WM-border to match dwi data with resampling
applyReg_anat2diff = applyReg_anat2diff_1mm.clone('wmoutline2diff')
applyReg_anat2diff.inputs.no_resample = False
applyReg_anat2diff.inputs.interp = 'trilin'
# Filter out low voxels produced by trilin. interp.
thresholdNode = Node(fsl.maths.Threshold(), name='remove_interp_residuals')
thresholdNode.inputs.thresh = 0.1
thresholdNode.inputs.output_type = 'NIFTI_GZ'
Example #24
0
def create_spm_preproc(c, name='preproc'):
    """Create an spm preprocessing workflow with freesurfer registration and
artifact detection.

The workflow realigns and smooths and registers the functional images with
the subject's freesurfer space.

Example
-------

>>> preproc = create_spm_preproc()
>>> preproc.base_dir = '.'
>>> preproc.inputs.inputspec.fwhm = 6
>>> preproc.inputs.inputspec.subject_id = 's1'
>>> preproc.inputs.inputspec.subjects_dir = '.'
>>> preproc.inputs.inputspec.functionals = ['f3.nii', 'f5.nii']
>>> preproc.inputs.inputspec.norm_threshold = 1
>>> preproc.inputs.inputspec.zintensity_threshold = 3

Inputs::

inputspec.functionals : functional runs use 4d nifti
inputspec.subject_id : freesurfer subject id
inputspec.subjects_dir : freesurfer subjects dir
inputspec.fwhm : smoothing fwhm
inputspec.norm_threshold : norm threshold for outliers
inputspec.zintensity_threshold : intensity threshold in z-score

Outputs::

outputspec.realignment_parameters : realignment parameter files
outputspec.smoothed_files : smoothed functional files
outputspec.outlier_files : list of outliers
outputspec.outlier_stats : statistics of outliers
outputspec.outlier_plots : images of outliers
outputspec.mask_file : binary mask file in reference image space
outputspec.reg_file : registration file that maps reference image to
freesurfer space
outputspec.reg_cost : cost of registration (useful for detecting misalignment)
"""
    from nipype.workflows.smri.freesurfer.utils import create_getmask_flow
    import nipype.algorithms.rapidart as ra
    import nipype.interfaces.spm as spm
    import nipype.interfaces.utility as niu
    import nipype.pipeline.engine as pe
    import nipype.interfaces.io as nio
    """
Initialize the workflow
"""

    workflow = pe.Workflow(name=name)
    """
Define the inputs to this workflow
"""

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'functionals', 'subject_id', 'subjects_dir', 'fwhm', 'norm_threshold',
        'zintensity_threshold', 'tr', 'do_slicetime', 'sliceorder', 'node',
        'csf_prob', 'wm_prob', 'gm_prob'
    ]),
                        name='inputspec')
    """
Setup the processing nodes and create the mask generation and coregistration
workflow
"""

    poplist = lambda x: x.pop()
    #realign = pe.Node(spm.Realign(), name='realign')

    sym_func = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_link'],
                                    function=do_symlink),
                       name='func_symlink')

    realign = pe.Node(niu.Function(
        input_names=['node', 'in_file', 'tr', 'do_slicetime', 'sliceorder'],
        output_names=['out_file', 'par_file'],
        function=mod_realign),
                      name="mod_realign")

    mean = art_mean_workflow()
    workflow.connect(realign, 'out_file', mean, 'inputspec.realigned_files')
    workflow.connect(realign, 'par_file', mean,
                     'inputspec.realignment_parameters')
    mean.inputs.inputspec.parameter_source = 'FSL'  # Modular realign puts it in FSL format for consistency

    #workflow.connect(inputnode, 'functionals', realign, 'in_file')
    workflow.connect(inputnode, 'functionals', sym_func, 'in_file')
    workflow.connect(sym_func, 'out_link', realign, 'in_file')

    workflow.connect(inputnode, 'tr', realign, 'tr')
    workflow.connect(inputnode, 'do_slicetime', realign, 'do_slicetime')
    workflow.connect(inputnode, 'sliceorder', realign, 'sliceorder')
    workflow.connect(inputnode, 'node', realign, 'node')

    maskflow = create_getmask_flow()
    workflow.connect([(inputnode, maskflow,
                       [('subject_id', 'inputspec.subject_id'),
                        ('subjects_dir', 'inputspec.subjects_dir')])])
    maskflow.inputs.inputspec.contrast_type = 't2'
    workflow.connect(mean, 'outputspec.mean_image', maskflow,
                     'inputspec.source_file')
    smooth = pe.Node(spm.Smooth(), name='smooth')

    normalize = pe.Node(spm.Normalize(jobtype='write'), name='normalize')
    normalize_struct = normalize.clone('normalize_struct')
    segment = pe.Node(spm.Segment(csf_output_type=[True, True, False],
                                  gm_output_type=[True, True, False],
                                  wm_output_type=[True, True, False]),
                      name='segment')

    mergefunc = lambda in1, in2, in3: [in1, in2, in3]

    # merge = pe.Node(niu.Merge(),name='merge')
    merge = pe.Node(niu.Function(input_names=['in1', 'in2', 'in3'],
                                 output_names=['out'],
                                 function=mergefunc),
                    name='merge')
    workflow.connect(inputnode, 'csf_prob', merge, 'in3')
    workflow.connect(inputnode, 'wm_prob', merge, 'in2')
    workflow.connect(inputnode, 'gm_prob', merge, 'in1')

    #workflow.connect(merge,'out', segment,'tissue_prob_maps')

    sym_prob = sym_func.clone('sym_prob')
    workflow.connect(merge, 'out', sym_prob, 'in_file')
    workflow.connect(sym_prob, 'out_link', segment, 'tissue_prob_maps')

    workflow.connect(maskflow, ('outputspec.mask_file', pickfirst), segment,
                     'mask_image')
    workflow.connect(inputnode, 'fwhm', smooth, 'fwhm')

    #sym_brain = sym_func.clone('sym_brain')
    #workflow.connect(realign, 'mean_image', normalize, 'source')
    #workflow.connect(maskflow,'fssource.brain',segment,'data')
    fssource = maskflow.get_node('fssource')
    import nipype.interfaces.freesurfer as fs
    convert_brain = pe.Node(interface=fs.ApplyVolTransform(inverse=True),
                            name='convert')
    workflow.connect(fssource, 'brain', convert_brain, 'target_file')
    workflow.connect(maskflow, ('outputspec.reg_file', pickfirst),
                     convert_brain, 'reg_file')
    workflow.connect(mean, 'outputspec.mean_image', convert_brain,
                     'source_file')
    convert2nii = pe.Node(fs.MRIConvert(in_type='mgz', out_type='nii'),
                          name='convert2nii')
    workflow.connect(convert_brain, 'transformed_file', convert2nii, 'in_file')
    workflow.connect(convert2nii, 'out_file', segment, 'data')

    workflow.connect(segment, 'transformation_mat', normalize,
                     'parameter_file')
    workflow.connect(segment, 'transformation_mat', normalize_struct,
                     'parameter_file')
    workflow.connect(convert2nii, 'out_file', normalize_struct,
                     'apply_to_files')
    workflow.connect(realign, 'out_file', normalize, 'apply_to_files')
    #normalize.inputs.template='/software/spm8/templates/EPI.nii'
    workflow.connect(normalize, 'normalized_files', smooth, 'in_files')
    #workflow.connect(realign, 'realigned_files', smooth, 'in_files')

    artdetect = pe.Node(ra.ArtifactDetect(mask_type='file',
                                          parameter_source='FSL',
                                          use_differences=[True, False],
                                          use_norm=True,
                                          save_plot=True),
                        name='artdetect')
    workflow.connect([(inputnode, artdetect,
                       [('norm_threshold', 'norm_threshold'),
                        ('zintensity_threshold', 'zintensity_threshold')])])
    workflow.connect([(realign, artdetect, [('out_file', 'realigned_files'),
                                            ('par_file',
                                             'realignment_parameters')])])
    workflow.connect(maskflow, ('outputspec.mask_file', poplist), artdetect,
                     'mask_file')
    """
Define the outputs of the workflow and connect the nodes to the outputnode
"""

    outputnode = pe.Node(niu.IdentityInterface(fields=[
        "realignment_parameters", "smoothed_files", "mask_file", "mean_image",
        "reg_file", "reg_cost", 'outlier_files', 'outlier_stats',
        'outlier_plots', 'norm_components', 'mod_csf', 'unmod_csf', 'mod_wm',
        'unmod_wm', 'mod_gm', 'unmod_gm', 'mean', 'normalized_struct',
        'struct_in_functional_space', 'normalization_parameters',
        'reverse_normalize_parameters'
    ]),
                         name="outputspec")
    workflow.connect([
        (maskflow, outputnode, [("outputspec.reg_file", "reg_file")]),
        (maskflow, outputnode, [("outputspec.reg_cost", "reg_cost")]),
        (maskflow, outputnode, [(("outputspec.mask_file", poplist),
                                 "mask_file")]),
        (realign, outputnode, [('par_file', 'realignment_parameters')]),
        (smooth, outputnode, [('smoothed_files', 'smoothed_files')]),
        (artdetect, outputnode, [('outlier_files', 'outlier_files'),
                                 ('statistic_files', 'outlier_stats'),
                                 ('plot_files', 'outlier_plots'),
                                 ('norm_files', 'norm_components')])
    ])
    workflow.connect(segment, 'modulated_csf_image', outputnode, 'mod_csf')
    workflow.connect(segment, 'modulated_wm_image', outputnode, 'mod_wm')
    workflow.connect(segment, 'modulated_gm_image', outputnode, 'mod_gm')
    workflow.connect(segment, 'normalized_csf_image', outputnode, 'unmod_csf')
    workflow.connect(segment, 'normalized_wm_image', outputnode, 'unmod_wm')
    workflow.connect(segment, 'normalized_gm_image', outputnode, 'unmod_gm')
    workflow.connect(mean, 'outputspec.mean_image', outputnode, 'mean')
    workflow.connect(normalize_struct, 'normalized_files', outputnode,
                     'normalized_struct')
    workflow.connect(segment, 'transformation_mat', outputnode,
                     'normalization_parameters')
    workflow.connect(segment, 'inverse_transformation_mat', outputnode,
                     'reverse_normalize_parameters')
    workflow.connect(convert2nii, 'out_file', outputnode,
                     'struct_in_functional_space')

    workflow.inputs.inputspec.fwhm = c.fwhm
    workflow.inputs.inputspec.subjects_dir = c.surf_dir
    workflow.inputs.inputspec.norm_threshold = c.norm_thresh
    workflow.inputs.inputspec.zintensity_threshold = c.z_thresh
    workflow.inputs.inputspec.node = c.motion_correct_node
    workflow.inputs.inputspec.tr = c.TR
    workflow.inputs.inputspec.do_slicetime = c.do_slicetiming
    workflow.inputs.inputspec.sliceorder = c.SliceOrder
    workflow.inputs.inputspec.csf_prob = c.csf_prob
    workflow.inputs.inputspec.gm_prob = c.grey_prob
    workflow.inputs.inputspec.wm_prob = c.white_prob
    workflow.base_dir = c.working_dir
    workflow.config = {'execution': {'crashdump_dir': c.crash_dir}}

    datagrabber = get_dataflow(c)

    workflow.connect(datagrabber, 'func', inputnode, 'functionals')

    infosource = pe.Node(niu.IdentityInterface(fields=['subject_id']),
                         name='subject_names')
    if not c.test_mode:
        infosource.iterables = ('subject_id', c.subjects)
    else:
        infosource.iterables = ('subject_id', c.subjects[:1])

    workflow.connect(infosource, 'subject_id', inputnode, 'subject_id')
    workflow.connect(infosource, 'subject_id', datagrabber, 'subject_id')
    sub = lambda x: [('_subject_id_%s' % x, '')]

    sinker = pe.Node(nio.DataSink(), name='sinker')
    workflow.connect(infosource, 'subject_id', sinker, 'container')
    workflow.connect(infosource, ('subject_id', sub), sinker, 'substitutions')
    sinker.inputs.base_directory = c.sink_dir
    outputspec = workflow.get_node('outputspec')
    workflow.connect(outputspec, 'realignment_parameters', sinker,
                     'spm_preproc.realignment_parameters')
    workflow.connect(outputspec, 'smoothed_files', sinker,
                     'spm_preproc.smoothed_outputs')
    workflow.connect(outputspec, 'outlier_files', sinker,
                     'spm_preproc.art.@outlier_files')
    workflow.connect(outputspec, 'outlier_stats', sinker,
                     'spm_preproc.art.@outlier_stats')
    workflow.connect(outputspec, 'outlier_plots', sinker,
                     'spm_preproc.art.@outlier_plots')
    workflow.connect(outputspec, 'norm_components', sinker,
                     'spm_preproc.art.@norm')
    workflow.connect(outputspec, 'reg_file', sinker,
                     'spm_preproc.bbreg.@reg_file')
    workflow.connect(outputspec, 'reg_cost', sinker,
                     'spm_preproc.bbreg.@reg_cost')
    workflow.connect(outputspec, 'mask_file', sinker,
                     'spm_preproc.mask.@mask_file')
    workflow.connect(outputspec, 'mod_csf', sinker,
                     'spm_preproc.segment.mod.@csf')
    workflow.connect(outputspec, 'mod_wm', sinker,
                     'spm_preproc.segment.mod.@wm')
    workflow.connect(outputspec, 'mod_gm', sinker,
                     'spm_preproc.segment.mod.@gm')
    workflow.connect(outputspec, 'unmod_csf', sinker,
                     'spm_preproc.segment.unmod.@csf')
    workflow.connect(outputspec, 'unmod_wm', sinker,
                     'spm_preproc.segment.unmod.@wm')
    workflow.connect(outputspec, 'unmod_gm', sinker,
                     'spm_preproc.segment.unmod.@gm')
    workflow.connect(outputspec, 'mean', sinker, 'spm_preproc.mean')
    workflow.connect(outputspec, 'normalized_struct', sinker,
                     'spm_preproc.normalized_struct')
    workflow.connect(outputspec, 'normalization_parameters', sinker,
                     'spm_preproc.normalization_parameters.@forward')
    workflow.connect(outputspec, 'reverse_normalize_parameters', sinker,
                     'spm_preproc.normalization_parameters.@reverse')
    workflow.connect(outputspec, 'struct_in_functional_space', sinker,
                     'spm_preproc.struct_in_func_space')

    return workflow
Example #25
0
def create_denoise_pipeline(name='denoise'):
    # workflow
    denoise = Workflow(name='denoise')
    # Define nodes
    inputnode = Node(interface=util.IdentityInterface(fields=[
        'anat_brain', 'brain_mask', 'epi2anat_dat', 'unwarped_mean',
        'epi_coreg', 'moco_par', 'highpass_sigma', 'lowpass_sigma', 'tr'
    ]),
                     name='inputnode')
    outputnode = Node(interface=util.IdentityInterface(fields=[
        'wmcsf_mask', 'brain_mask_resamp', 'brain_mask2epi', 'combined_motion',
        'outlier_files', 'intensity_files', 'outlier_stats', 'outlier_plots',
        'mc_regressor', 'mc_F', 'mc_pF', 'comp_regressor', 'comp_F', 'comp_pF',
        'normalized_file'
    ]),
                      name='outputnode')
    # run fast to get tissue probability classes
    fast = Node(fsl.FAST(), name='fast')
    denoise.connect([(inputnode, fast, [('anat_brain', 'in_files')])])

    # functions to select tissue classes
    def selectindex(files, idx):
        import numpy as np
        from nipype.utils.filemanip import filename_to_list, list_to_filename
        return list_to_filename(
            np.array(filename_to_list(files))[idx].tolist())

    def selectsingle(files, idx):
        return files[idx]

    # resample tissue classes
    resample_tissue = MapNode(afni.Resample(resample_mode='NN',
                                            outputtype='NIFTI_GZ'),
                              iterfield=['in_file'],
                              name='resample_tissue')
    denoise.connect([
        (inputnode, resample_tissue, [('epi_coreg', 'master')]),
        (fast, resample_tissue, [(('partial_volume_files', selectindex,
                                   [0, 2]), 'in_file')]),
    ])
    # binarize tissue classes
    binarize_tissue = MapNode(
        fsl.ImageMaths(op_string='-nan -thr 0.99 -ero -bin'),
        iterfield=['in_file'],
        name='binarize_tissue')
    denoise.connect([
        (resample_tissue, binarize_tissue, [('out_file', 'in_file')]),
    ])
    # combine tissue classes to noise mask
    wmcsf_mask = Node(fsl.BinaryMaths(operation='add',
                                      out_file='wmcsf_mask_lowres.nii.gz'),
                      name='wmcsf_mask')
    denoise.connect([(binarize_tissue, wmcsf_mask,
                      [(('out_file', selectsingle, 0), 'in_file'),
                       (('out_file', selectsingle, 1), 'operand_file')]),
                     (wmcsf_mask, outputnode, [('out_file', 'wmcsf_mask')])])
    # resample brain mask
    resample_brain = Node(afni.Resample(
        resample_mode='NN',
        outputtype='NIFTI_GZ',
        out_file='T1_brain_mask_lowres.nii.gz'),
                          name='resample_brain')
    denoise.connect([(inputnode, resample_brain, [('brain_mask', 'in_file'),
                                                  ('epi_coreg', 'master')]),
                     (resample_brain, outputnode, [('out_file',
                                                    'brain_mask_resamp')])])
    # project brain mask into original epi space fpr quality assessment
    brainmask2epi = Node(fs.ApplyVolTransform(
        interp='nearest',
        inverse=True,
        transformed_file='T1_brain_mask2epi.nii.gz',
    ),
                         name='brainmask2epi')
    denoise.connect([
        (inputnode, brainmask2epi, [('brain_mask', 'target_file'),
                                    ('epi2anat_dat', 'reg_file'),
                                    ('unwarped_mean', 'source_file')]),
        (brainmask2epi, outputnode, [('transformed_file', 'brain_mask2epi')])
    ])
    # perform artefact detection
    artefact = Node(ra.ArtifactDetect(save_plot=True,
                                      use_norm=True,
                                      parameter_source='FSL',
                                      mask_type='file',
                                      norm_threshold=1,
                                      zintensity_threshold=3,
                                      use_differences=[True, False]),
                    name='artefact')
    artefact.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (inputnode, artefact, [('epi_coreg', 'realigned_files'),
                               ('moco_par', 'realignment_parameters')]),
        (resample_brain, artefact, [('out_file', 'mask_file')]),
        (artefact, outputnode, [('norm_files', 'combined_motion'),
                                ('outlier_files', 'outlier_files'),
                                ('intensity_files', 'intensity_files'),
                                ('statistic_files', 'outlier_stats'),
                                ('plot_files', 'outlier_plots')])
    ])
    # Compute motion regressors
    motreg = Node(util.Function(
        input_names=['motion_params', 'order', 'derivatives'],
        output_names=['out_files'],
        function=motion_regressors),
                  name='getmotionregress')
    motreg.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(inputnode, motreg, [('moco_par', 'motion_params')])])
    # Create a filter to remove motion and art confounds
    createfilter1 = Node(util.Function(
        input_names=['motion_params', 'comp_norm', 'outliers', 'detrend_poly'],
        output_names=['out_files'],
        function=build_filter1),
                         name='makemotionbasedfilter')
    createfilter1.inputs.detrend_poly = 2
    createfilter1.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (motreg, createfilter1, [('out_files', 'motion_params')]),
        (
            artefact,
            createfilter1,
            [  #('norm_files', 'comp_norm'),
                ('outlier_files', 'outliers')
            ]),
        (createfilter1, outputnode, [('out_files', 'mc_regressor')])
    ])
    # regress out motion and art confounds
    filter1 = Node(fsl.GLM(out_f_name='F_mcart.nii.gz',
                           out_pf_name='pF_mcart.nii.gz',
                           out_res_name='rest_mc_denoised.nii.gz',
                           demean=True),
                   name='filtermotion')
    filter1.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(inputnode, filter1, [('epi_coreg', 'in_file')]),
                     (createfilter1, filter1,
                      [(('out_files', list_to_filename), 'design')]),
                     (filter1, outputnode, [('out_f', 'mc_F'),
                                            ('out_pf', 'mc_pF')])])
    # create filter with compcor components
    createfilter2 = Node(util.Function(input_names=[
        'realigned_file', 'mask_file', 'num_components', 'extra_regressors'
    ],
                                       output_names=['out_files'],
                                       function=extract_noise_components),
                         name='makecompcorfilter')
    createfilter2.inputs.num_components = 6
    createfilter2.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (createfilter1, createfilter2, [(('out_files', list_to_filename),
                                         'extra_regressors')]),
        (filter1, createfilter2, [('out_res', 'realigned_file')]),
        (wmcsf_mask, createfilter2, [('out_file', 'mask_file')]),
        (createfilter2, outputnode, [('out_files', 'comp_regressor')]),
    ])
    # regress compcor and other noise components
    filter2 = Node(fsl.GLM(out_f_name='F_noise.nii.gz',
                           out_pf_name='pF_noise.nii.gz',
                           out_res_name='rest2anat_denoised.nii.gz',
                           demean=True),
                   name='filternoise')
    filter2.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(filter1, filter2, [('out_res', 'in_file')]),
                     (createfilter2, filter2, [('out_files', 'design')]),
                     (resample_brain, filter2, [('out_file', 'mask')]),
                     (filter2, outputnode, [('out_f', 'comp_F'),
                                            ('out_pf', 'comp_pF')])])
    # bandpass filter denoised file
    bandpass_filter = Node(
        fsl.TemporalFilter(out_file='rest_denoised_bandpassed.nii.gz'),
        name='bandpass_filter')
    bandpass_filter.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(inputnode, bandpass_filter,
                      [('highpass_sigma', 'highpass_sigma'),
                       ('lowpass_sigma', 'lowpass_sigma')]),
                     (filter2, bandpass_filter, [('out_res', 'in_file')])])
    # time-normalize scans
    normalize_time = Node(util.Function(input_names=['in_file', 'tr'],
                                        output_names=['out_file'],
                                        function=time_normalizer),
                          name='normalize_time')
    normalize_time.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (inputnode, normalize_time, [('tr', 'tr')]),
        (bandpass_filter, normalize_time, [('out_file', 'in_file')]),
        (normalize_time, outputnode, [('out_file', 'normalized_file')])
    ])
    return denoise
Example #26
0
datasource.inputs.base_directory = datadir
datasource.inputs.template = '%s/*%s.nii.gz'
datasource.inputs.template_args = dict(
    filtered_func=[['subject_id', 'filtered']],
    mean_image=[['subject_id', 'mean']])

roiproc.connect(inputnode, 'subject_id', datasource, 'subject_id')

fssource = pe.Node(nio.FreeSurferSource(), name='fssource')
fssource.inputs.subjects_dir = surfacedir

register = pe.Node(fs.BBRegister(init='fsl', contrast_type='t2'),
                   name='register')
register.inputs.subjects_dir = surfacedir

voltransform = pe.Node(fs.ApplyVolTransform(inverse=True, interp='nearest'),
                       name='transform')
voltransform.inputs.subjects_dir = surfacedir


def choose_aseg(aparc_files):
    from glob import glob
    import os
    all_files = glob(os.path.join(aparc_files[0].split('aparc')[0], '*yeo*'))
    for fname in all_files:
        if 'aparc+yeo17' in fname:
            return fname
    raise ValueError('No aparc+aseg file found')


"""
def create_reg_workflow(name='registration'):
    """Create a FEAT preprocessing workflow together with freesurfer

    Parameters
    ----------

        name : name of workflow (default: 'registration')

    Inputs::

        inputspec.source_files : files (filename or list of filenames to register)
        inputspec.mean_image : reference image to use
        inputspec.anatomical_image : anatomical image to coregister to
        inputspec.target_image : registration target

    Outputs::

        outputspec.func2anat_transform : FLIRT transform
        outputspec.anat2target_transform : FLIRT+FNIRT transform
        outputspec.transformed_files : transformed files in target space
        outputspec.transformed_mean : mean image in target space
    """

    register = Workflow(name=name)

    inputnode = Node(interface=IdentityInterface(fields=[
        'source_files', 'mean_image', 'subject_id', 'subjects_dir',
        'target_image'
    ]),
                     name='inputspec')

    outputnode = Node(interface=IdentityInterface(fields=[
        'func2anat_transform', 'out_reg_file', 'anat2target_transform',
        'transforms', 'transformed_mean', 'segmentation_files', 'anat2target',
        'aparc'
    ]),
                      name='outputspec')

    # Get the subject's freesurfer source directory
    fssource = Node(FreeSurferSource(), name='fssource')
    fssource.run_without_submitting = True
    register.connect(inputnode, 'subject_id', fssource, 'subject_id')
    register.connect(inputnode, 'subjects_dir', fssource, 'subjects_dir')

    convert = Node(freesurfer.MRIConvert(out_type='nii'), name="convert")
    register.connect(fssource, 'T1', convert, 'in_file')

    # Coregister the median to the surface
    bbregister = Node(freesurfer.BBRegister(), name='bbregister')
    bbregister.inputs.init = 'fsl'
    bbregister.inputs.contrast_type = 't2'
    bbregister.inputs.out_fsl_file = True
    bbregister.inputs.epi_mask = True
    register.connect(inputnode, 'subject_id', bbregister, 'subject_id')
    register.connect(inputnode, 'mean_image', bbregister, 'source_file')
    register.connect(inputnode, 'subjects_dir', bbregister, 'subjects_dir')
    """
    Estimate the tissue classes from the anatomical image. But use spm's segment
    as FSL appears to be breaking.
    """

    stripper = Node(fsl.BET(), name='stripper')
    register.connect(convert, 'out_file', stripper, 'in_file')
    fast = Node(fsl.FAST(), name='fast')
    register.connect(stripper, 'out_file', fast, 'in_files')
    """
    Binarize the segmentation
    """

    binarize = MapNode(fsl.ImageMaths(op_string='-nan -thr 0.9 -ero -bin'),
                       iterfield=['in_file'],
                       name='binarize')
    register.connect(fast, 'partial_volume_files', binarize, 'in_file')
    """
    Apply inverse transform to take segmentations to functional space
    """

    applyxfm = MapNode(freesurfer.ApplyVolTransform(inverse=True,
                                                    interp='nearest'),
                       iterfield=['target_file'],
                       name='inverse_transform')
    register.connect(inputnode, 'subjects_dir', applyxfm, 'subjects_dir')
    register.connect(bbregister, 'out_reg_file', applyxfm, 'reg_file')
    register.connect(binarize, 'out_file', applyxfm, 'target_file')
    register.connect(inputnode, 'mean_image', applyxfm, 'source_file')
    """
    Apply inverse transform to aparc file
    """

    aparcxfm = Node(freesurfer.ApplyVolTransform(inverse=True,
                                                 interp='nearest'),
                    name='aparc_inverse_transform')
    register.connect(inputnode, 'subjects_dir', aparcxfm, 'subjects_dir')
    register.connect(bbregister, 'out_reg_file', aparcxfm, 'reg_file')
    register.connect(fssource, ('aparc_aseg', get_aparc_aseg), aparcxfm,
                     'target_file')
    register.connect(inputnode, 'mean_image', aparcxfm, 'source_file')
    """
    Convert the BBRegister transformation to ANTS ITK format
    """

    convert2itk = Node(C3dAffineTool(), name='convert2itk')
    convert2itk.inputs.fsl2ras = True
    convert2itk.inputs.itk_transform = True
    register.connect(bbregister, 'out_fsl_file', convert2itk, 'transform_file')
    register.connect(inputnode, 'mean_image', convert2itk, 'source_file')
    register.connect(stripper, 'out_file', convert2itk, 'reference_file')
    """
    Compute registration between the subject's structural and MNI template
    This is currently set to perform a very quick registration. However, the
    registration can be made significantly more accurate for cortical
    structures by increasing the number of iterations
    All parameters are set using the example from:
    #https://github.com/stnava/ANTs/blob/master/Scripts/newAntsExample.sh
    """

    reg = Node(ants.Registration(), name='antsRegister')
    reg.inputs.output_transform_prefix = "output_"
    reg.inputs.transforms = ['Rigid', 'Affine', 'SyN']
    reg.inputs.transform_parameters = [(0.1, ), (0.1, ), (0.2, 3.0, 0.0)]
    reg.inputs.number_of_iterations = [[10000, 11110, 11110]] * 2 + [[
        100, 30, 20
    ]]
    reg.inputs.dimension = 3
    reg.inputs.write_composite_transform = True
    reg.inputs.collapse_output_transforms = True
    reg.inputs.initial_moving_transform_com = True
    reg.inputs.metric = ['Mattes'] * 2 + [['Mattes', 'CC']]
    reg.inputs.metric_weight = [1] * 2 + [[0.5, 0.5]]
    reg.inputs.radius_or_number_of_bins = [32] * 2 + [[32, 4]]
    reg.inputs.sampling_strategy = ['Regular'] * 2 + [[None, None]]
    reg.inputs.sampling_percentage = [0.3] * 2 + [[None, None]]
    reg.inputs.convergence_threshold = [1.e-8] * 2 + [-0.01]
    reg.inputs.convergence_window_size = [20] * 2 + [5]
    reg.inputs.smoothing_sigmas = [[4, 2, 1]] * 2 + [[1, 0.5, 0]]
    reg.inputs.sigma_units = ['vox'] * 3
    reg.inputs.shrink_factors = [[3, 2, 1]] * 2 + [[4, 2, 1]]
    reg.inputs.use_estimate_learning_rate_once = [True] * 3
    reg.inputs.use_histogram_matching = [False] * 2 + [True]
    reg.inputs.winsorize_lower_quantile = 0.005
    reg.inputs.winsorize_upper_quantile = 0.995
    reg.inputs.float = True
    reg.inputs.output_warped_image = 'output_warped_image.nii.gz'
    reg.inputs.num_threads = 4
    reg.plugin_args = {'qsub_args': '-l nodes=1:ppn=4'}
    register.connect(stripper, 'out_file', reg, 'moving_image')
    register.connect(inputnode, 'target_image', reg, 'fixed_image')
    """
    Concatenate the affine and ants transforms into a list
    """

    merge = Node(Merge(2), iterfield=['in2'], name='mergexfm')
    register.connect(convert2itk, 'itk_transform', merge, 'in2')
    register.connect(reg, 'composite_transform', merge, 'in1')
    """
    Transform the mean image. First to anatomical and then to target
    """

    warpmean = Node(ants.ApplyTransforms(), name='warpmean')
    warpmean.inputs.input_image_type = 3
    warpmean.inputs.interpolation = 'Linear'
    warpmean.inputs.invert_transform_flags = [False, False]
    warpmean.inputs.terminal_output = 'file'
    warpmean.inputs.args = '--float'
    warpmean.inputs.num_threads = 4

    register.connect(inputnode, 'target_image', warpmean, 'reference_image')
    register.connect(inputnode, 'mean_image', warpmean, 'input_image')
    register.connect(merge, 'out', warpmean, 'transforms')
    """
    Assign all the output files
    """

    register.connect(reg, 'warped_image', outputnode, 'anat2target')
    register.connect(warpmean, 'output_image', outputnode, 'transformed_mean')
    register.connect(applyxfm, 'transformed_file', outputnode,
                     'segmentation_files')
    register.connect(aparcxfm, 'transformed_file', outputnode, 'aparc')
    register.connect(bbregister, 'out_fsl_file', outputnode,
                     'func2anat_transform')
    register.connect(bbregister, 'out_reg_file', outputnode, 'out_reg_file')
    register.connect(reg, 'composite_transform', outputnode,
                     'anat2target_transform')
    register.connect(merge, 'out', outputnode, 'transforms')

    return register
Example #28
0
surfregister.inputs.init = 'fsl'
surfregister.inputs.contrast_type = 't2'

"""
Use :class:`nipype.interfaces.io.FreeSurferSource` to retrieve various image
files that are automatically generated by the recon-all process.
"""

FreeSurferSource = pe.Node(interface=nio.FreeSurferSource(), name='fssource')

"""
Use :class:`nipype.interfaces.freesurfer.ApplyVolTransform` to convert the
brainmask generated by freesurfer into the realigned functional space.
"""

ApplyVolTransform = pe.Node(interface=fs.ApplyVolTransform(),
                            name='applyreg')
ApplyVolTransform.inputs.inverse = True

"""
Use :class:`nipype.interfaces.freesurfer.Binarize` to extract a binary brain
mask.
"""

Threshold = pe.Node(interface=fs.Binarize(),name='threshold')
Threshold.inputs.min = 10
Threshold.inputs.out_type = 'nii'

"""
Two different types of functional data smoothing are performed in this
workflow. The volume smoothing option performs a standard SPM smoothin. using
Example #29
0
def create_get_stats_flow(name='getstats', withreg=False):
    """Retrieves stats from labels

    Parameters
    ----------

    name : string
        name of workflow
    withreg : boolean
        indicates whether to register source to label

    Example
    -------


    Inputs::

           inputspec.source_file : reference image for mask generation
           inputspec.label_file : label file from which to get ROIs

           (optionally with registration)
           inputspec.reg_file : bbreg file (assumes reg from source to label
           inputspec.inverse : boolean whether to invert the registration
           inputspec.subjects_dir : freesurfer subjects directory

    Outputs::

           outputspec.stats_file : stats file
    """
    import nipype.pipeline.engine as pe
    import nipype.interfaces.freesurfer as fs
    import nipype.interfaces.utility as niu

    """
    Initialize the workflow
    """

    getstats = pe.Workflow(name=name)

    """
    Define the inputs to the workflow.
    """

    if withreg:
        inputnode = pe.Node(niu.IdentityInterface(fields=['source_file',
                                                          'label_file',
                                                          'reg_file',
                                                          'subjects_dir','inverse']),
            name='inputspec')
    else:
        inputnode = pe.Node(niu.IdentityInterface(fields=['source_file',
                                                          'label_file']),
            name='inputspec')


    statnode = pe.MapNode(fs.SegStats(),
        iterfield=['segmentation_file','in_file'],
        name='segstats')

    """
    Convert between source and label spaces if registration info is provided

    """
    if withreg:
        voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp='nearest'),
            iterfield=['source_file', 'reg_file'],
            name='transform')
        getstats.connect(inputnode, 'reg_file', voltransform, 'reg_file')
        getstats.connect(inputnode, 'source_file', voltransform, 'source_file')
        getstats.connect(inputnode, 'label_file', voltransform, 'target_file')
        getstats.connect(inputnode, 'subjects_dir', voltransform, 'subjects_dir')

        def switch_labels(inverse, transform_output, source_file, label_file):
            if inverse:
                return transform_output, source_file
            else:
                return label_file, transform_output

        chooser = pe.MapNode(niu.Function(input_names = ['inverse',
                                                         'transform_output',
                                                         'source_file',
                                                         'label_file'],
            output_names = ['label_file',
                            'source_file'],
            function=switch_labels),
            iterfield=['transform_output','source_file'],
            name='chooser')
        getstats.connect(inputnode,'source_file', chooser, 'source_file')
        getstats.connect(inputnode,'label_file', chooser, 'label_file')
        getstats.connect(inputnode,'inverse', chooser, 'inverse')
        getstats.connect(voltransform, 'transformed_file', chooser, 'transform_output')
        getstats.connect(chooser, 'label_file', statnode, 'segmentation_file')
        getstats.connect(chooser, 'source_file', statnode, 'in_file')
    else:
        getstats.connect(inputnode, 'label_file', statnode, 'segmentation_file')
        getstats.connect(inputnode, 'source_file', statnode, 'in_file')

    """
    Setup an outputnode that defines relevant inputs of the workflow.
    """

    outputnode = pe.Node(niu.IdentityInterface(fields=["stats_file"
    ]),
        name="outputspec")
    getstats.connect([
        (statnode, outputnode, [("summary_file", "stats_file")]),
    ])
    return getstats
Example #30
0
def freesurfer_preproc(wf, cfg, strat_pool, pipe_num, opt=None):
    '''
    {"name": "freesurfer_preproc",
     "config": ["surface_analysis"],
     "switch": ["run_freesurfer"],
     "option_key": "None",
     "option_val": "None",
     "inputs": [["desc-preproc_T1w", "desc-reorient_T1w", "T1w"]],
     "outputs": ["space-T1w_desc-brain_mask",
                 "freesurfer_subject_dir",
                 "label-CSF_mask",
                 "label-WM_mask",
                 "label-GM_mask",
                 "surface_curvature",
                 "pial_surface_mesh",
                 "smoothed_surface_mesh",
                 "spherical_surface_mesh",
                 "sulcal_depth_surface_maps",
                 "cortical_thickness_surface_maps",
                 "cortical_volume_surface_maps",
                 "white_matter_surface_mesh",
                 "raw_average"]}
    '''

    reconall = pe.Node(interface=freesurfer.ReconAll(),
                       name=f'anat_freesurfer_{pipe_num}')

    freesurfer_subject_dir = os.path.join(
        cfg.pipeline_setup['working_directory']['path'],
        f'anat_preproc_freesurfer_{pipe_num}', 'anat_freesurfer')

    if not os.path.exists(freesurfer_subject_dir):
        os.makedirs(freesurfer_subject_dir)

    reconall.inputs.directive = 'all'
    reconall.inputs.subjects_dir = freesurfer_subject_dir
    reconall.inputs.openmp = cfg.pipeline_setup['system_config'][
        'num_OMP_threads']

    node, out = strat_pool.get_data(
        ["desc-preproc_T1w", "desc-reorient_T1w", "T1w"])
    wf.connect(node, out, reconall, 'T1_files')

    # register FS brain mask to native space
    fs_brain_mask_to_native = pe.Node(interface=freesurfer.ApplyVolTransform(),
                                      name='fs_brain_mask_to_native')
    fs_brain_mask_to_native.inputs.reg_header = True

    wf.connect(reconall, 'brainmask', fs_brain_mask_to_native, 'source_file')
    wf.connect(reconall, 'rawavg', fs_brain_mask_to_native, 'target_file')
    wf.connect(reconall, 'subjects_dir', fs_brain_mask_to_native,
               'subjects_dir')

    # convert brain mask file from .mgz to .nii.gz
    fs_brain_mask_to_nifti = pe.Node(util.Function(input_names=['in_file'],
                                                   output_names=['out_file'],
                                                   function=mri_convert),
                                     name='fs_brainmask_to_nifti')
    wf.connect(fs_brain_mask_to_native, 'transformed_file',
               fs_brain_mask_to_nifti, 'in_file')

    # binarize the brain mask
    binarize_fs_brain_mask = pe.Node(interface=fsl.maths.MathsCommand(),
                                     name='binarize_fs_brainmask')
    binarize_fs_brain_mask.inputs.args = '-bin'
    wf.connect(fs_brain_mask_to_nifti, 'out_file', binarize_fs_brain_mask,
               'in_file')

    # fill holes
    fill_fs_brain_mask = pe.Node(interface=afni.MaskTool(),
                                 name='fill_fs_brainmask')
    fill_fs_brain_mask.inputs.fill_holes = True
    fill_fs_brain_mask.inputs.outputtype = 'NIFTI_GZ'
    wf.connect(binarize_fs_brain_mask, 'out_file', fill_fs_brain_mask,
               'in_file')

    # register FS segmentations (aseg.mgz) to native space
    fs_aseg_to_native = pe.Node(interface=freesurfer.ApplyVolTransform(),
                                name='fs_aseg_to_native')
    fs_aseg_to_native.inputs.reg_header = True
    fs_aseg_to_native.inputs.interp = 'nearest'
    fs_aseg_to_native.inputs.subjects_dir = freesurfer_subject_dir

    wf.connect(reconall, 'aseg', fs_aseg_to_native, 'source_file')
    wf.connect(reconall, 'rawavg', fs_aseg_to_native, 'target_file')

    # convert registered FS segmentations from .mgz to .nii.gz
    fs_aseg_to_nifti = pe.Node(util.Function(input_names=['in_file'],
                                             output_names=['out_file'],
                                             function=mri_convert),
                               name='fs_aseg_to_nifti')
    fs_aseg_to_nifti.inputs.args = '-rt nearest'

    wf.connect(fs_aseg_to_native, 'transformed_file', fs_aseg_to_nifti,
               'in_file')

    pick_tissue = pe.Node(util.Function(
        input_names=['multiatlas_Labels'],
        output_names=['csf_mask', 'gm_mask', 'wm_mask'],
        function=pick_tissue_from_labels_file),
                          name=f'anat_preproc_freesurfer_tissue_mask')
    pick_tissue.inputs.include_ventricles = True

    wf.connect(fs_aseg_to_nifti, 'out_file', pick_tissue, 'multiatlas_Labels')

    outputs = {
        'space-T1w_desc-brain_mask': (fill_fs_brain_mask, 'out_file'),
        'freesurfer_subject_dir': (reconall, 'subjects_dir'),
        'label-CSF_mask': (pick_tissue, 'csf_mask'),
        'label-WM_mask': (pick_tissue, 'wm_mask'),
        'label-GM_mask': (pick_tissue, 'gm_mask'),
        'surface_curvature': (reconall, 'curv'),
        'pial_surface_mesh': (reconall, 'pial'),
        'smoothed_surface_mesh': (reconall, 'smoothwm'),
        'spherical_surface_mesh': (reconall, 'sphere'),
        'sulcal_depth_surface_maps': (reconall, 'sulc'),
        'cortical_thickness_surface_maps': (reconall, 'thickness'),
        'cortical_volume_surface_maps': (reconall, 'volume'),
        'white_matter_surface_mesh': (reconall, 'white'),
        'raw_average': (reconall, 'rawavg')
    }

    return (wf, outputs)