Exemple #1
0
    def _list_outputs(self):
        outputs = self._outputs().get()

        outputs['out_file'] = self._gen_outfilename()
        output_dir = os.path.dirname(outputs['out_file'])

        if isdefined(self.inputs.stats_imgs) and self.inputs.stats_imgs:
            if LooseVersion(Info.version()) < LooseVersion('6.0.0'):
                # FSL <6.0 outputs have .nii.gz_variance.nii.gz as extension
                outputs['variance_img'] = self._gen_fname(
                    outputs['out_file'] + '_variance.ext', cwd=output_dir)
                outputs['std_img'] = self._gen_fname(
                    outputs['out_file'] + '_sigma.ext', cwd=output_dir)
            else:
                outputs['variance_img'] = self._gen_fname(
                    outputs['out_file'], suffix='_variance', cwd=output_dir)
                outputs['std_img'] = self._gen_fname(
                    outputs['out_file'], suffix='_sigma', cwd=output_dir)

        # The mean image created if -stats option is specified ('meanvol')
        # is missing the top and bottom slices. Therefore we only expose the
        # mean image created by -meanvol option ('mean_reg') which isn't
        # corrupted.
        # Note that the same problem holds for the std and variance image.

        if isdefined(self.inputs.mean_vol) and self.inputs.mean_vol:
            if LooseVersion(Info.version()) < LooseVersion('6.0.0'):
                # FSL <6.0 outputs have .nii.gz_mean_img.nii.gz as extension
                outputs['mean_img'] = self._gen_fname(
                    outputs['out_file'] + '_mean_reg.ext', cwd=output_dir)
            else:
                outputs['mean_img'] = self._gen_fname(
                    outputs['out_file'], suffix='_mean_reg', cwd=output_dir)

        if isdefined(self.inputs.save_mats) and self.inputs.save_mats:
            _, filename = os.path.split(outputs['out_file'])
            mat_dir = os.path.join(output_dir, filename + '.mat')
            outputs['mat_dir'] = mat_dir
            _, _, _, timepoints = load(self.inputs.in_file).shape
            outputs['mat_file'] = []
            for t in range(timepoints):
                outputs['mat_file'].append(
                    os.path.join(mat_dir, 'MAT_%04d' % t))
        if isdefined(self.inputs.save_plots) and self.inputs.save_plots:
            # Note - if e.g. out_file has .nii.gz, you get .nii.gz.par,
            # which is what mcflirt does!
            outputs['par_file'] = outputs['out_file'] + '.par'
        if isdefined(self.inputs.save_rms) and self.inputs.save_rms:
            outfile = outputs['out_file']
            outputs['rms_files'] = [outfile + '_abs.rms', outfile + '_rel.rms']
        return outputs
def test_bbregister(create_files_in_directory):
    filelist, outdir = create_files_in_directory
    bbr = freesurfer.BBRegister()

    # make sure command gets called
    assert bbr.cmd == "bbregister"

    # test raising error with mandatory args absent
    with pytest.raises(ValueError):
        bbr.cmdline

    bbr.inputs.subject_id = "fsaverage"
    bbr.inputs.source_file = filelist[0]
    bbr.inputs.contrast_type = "t2"

    # Check that 'init' is mandatory in FS < 6, but not in 6+
    if Info.looseversion() < LooseVersion("6.0.0"):
        with pytest.raises(ValueError):
            bbr.cmdline
    else:
        bbr.cmdline

    bbr.inputs.init = "fsl"

    base, ext = os.path.splitext(os.path.basename(filelist[0]))
    if ext == ".gz":
        base, _ = os.path.splitext(base)

    assert bbr.cmdline == ("bbregister --t2 --init-fsl "
                           "--reg {base}_bbreg_fsaverage.dat "
                           "--mov {full} --s fsaverage".format(
                               full=filelist[0], base=base))
from nipype.workflows.fmri.fsl import (create_featreg_preproc,
                                       create_modelfit_workflow,
                                       create_fixed_effects_flow)

from nipype import LooseVersion
from nipype import Workflow, Node, MapNode
from nipype.interfaces import (fsl, Function, ants, freesurfer)

from nipype.interfaces.utility import Rename, Merge, IdentityInterface
from nipype.utils.filemanip import filename_to_list
from nipype.interfaces.io import DataSink, FreeSurferSource
import nipype.interfaces.freesurfer as fs

version = 0
if fsl.Info.version() and \
    LooseVersion(fsl.Info.version()) > LooseVersion('5.0.6'):
    version = 507

fsl.FSLCommand.set_default_output_type('NIFTI_GZ')

imports = ['import os',
           'import nibabel as nb',
           'import numpy as np',
           'import scipy as sp',
           'from nipype.utils.filemanip import filename_to_list, list_to_filename, split_filename',
           'from scipy.special import legendre'
           ]

def median(in_files):
    """Computes an average of the median of each realigned timeseries
def test_FSVersion():
    """Check that FSVersion is a string that can be compared with LooseVersion"""
    assert isinstance(freesurfer.preprocess.FSVersion, str)
    assert LooseVersion(freesurfer.preprocess.FSVersion) >= LooseVersion("0")
def create_nuisance_modelfit_workflow(name='modelfit', f_contrasts=False):
    """
    Create an FSL  modelfitting workflow that returns also
    residual4d and sigmasquareds.

    Example
    -------

#    >>> modelfit = create_modelfit_workflow()
#    >>> modelfit.base_dir = '.'
#    >>> info = dict()
#    >>> modelfit.inputs.inputspec.session_info = info
#    >>> modelfit.inputs.inputspec.interscan_interval = 3.
#    >>> modelfit.inputs.inputspec.film_threshold = 1000
#    >>> modelfit.run() #doctest: +SKIP

    Inputs::

         inputspec.session_info : info generated by modelgen.SpecifyModel
         inputspec.interscan_interval : interscan interval
         inputspec.contrasts : list of contrasts
         inputspec.film_threshold : image threshold for FILM estimation
         inputspec.model_serial_correlations
         inputspec.bases

    Outputs::

         outputspec.copes
         outputspec.varcopes
         outputspec.dof_file
         outputspec.pfiles
         outputspec.zfiles
         outputspec.parameter_estimates
         outputspec.residual4d
         outputspec.sigmasquareds

    """

    version = 0
    if fsl.Info.version() and \
                    LooseVersion(fsl.Info.version()) > LooseVersion('5.0.6'):
        version = 507

    modelfit = pe.Workflow(name=name)
    """
    Create the nodes
    """

    inputspec = pe.Node(util.IdentityInterface(fields=[
        'session_info', 'interscan_interval', 'contrasts', 'film_threshold',
        'functional_data', 'bases', 'model_serial_correlations'
    ]),
                        name='inputspec')
    level1design = pe.Node(interface=fsl.Level1Design(), name="level1design")
    modelgen = pe.MapNode(interface=fsl.FEATModel(),
                          name='modelgen',
                          iterfield=['fsf_file', 'ev_files'])
    if version < 507:
        modelestimate = pe.MapNode(interface=fsl.FILMGLS(smooth_autocorr=True,
                                                         mask_size=5),
                                   name='modelestimate',
                                   iterfield=['design_file', 'in_file'])
    else:
        if f_contrasts:
            iterfield = ['design_file', 'in_file', 'tcon_file', 'fcon_file']
        else:
            iterfield = ['design_file', 'in_file', 'tcon_file']
        modelestimate = pe.MapNode(interface=fsl.FILMGLS(smooth_autocorr=True,
                                                         mask_size=5),
                                   name='modelestimate',
                                   iterfield=iterfield)

    if version < 507:
        if f_contrasts:
            iterfield = [
                'tcon_file', 'fcon_file', 'param_estimates', 'sigmasquareds',
                'corrections', 'dof_file'
            ]
        else:
            iterfield = [
                'tcon_file', 'param_estimates', 'sigmasquareds', 'corrections',
                'dof_file'
            ]
        conestimate = pe.MapNode(interface=fsl.ContrastMgr(),
                                 name='conestimate',
                                 iterfield=[
                                     'tcon_file', 'fcon_file',
                                     'param_estimates', 'sigmasquareds',
                                     'corrections', 'dof_file'
                                 ])

    if f_contrasts:
        iterfield = ['in1', 'in2']
    else:
        iterfield = ['in1']
    merge_contrasts = pe.MapNode(interface=util.Merge(2),
                                 name='merge_contrasts',
                                 iterfield=iterfield)

    ztopval = pe.MapNode(interface=fsl.ImageMaths(op_string='-ztop',
                                                  suffix='_pval'),
                         nested=True,
                         name='ztop',
                         iterfield=['in_file'])

    outputspec = pe.Node(util.IdentityInterface(fields=[
        'copes', 'varcopes', 'dof_file', 'pfiles', 'zfiles',
        'parameter_estimates', 'residual4d', 'sigmasquareds'
    ]),
                         name='outputspec')
    """
    Setup the connections
    """

    modelfit.connect([
        (inputspec, level1design,
         [('interscan_interval', 'interscan_interval'),
          ('session_info', 'session_info'), ('contrasts', 'contrasts'),
          ('bases', 'bases'),
          ('model_serial_correlations', 'model_serial_correlations')]),
        (inputspec, modelestimate, [('film_threshold', 'threshold'),
                                    ('functional_data', 'in_file')]),
        (level1design, modelgen, [('fsf_files', 'fsf_file'),
                                  ('ev_files', 'ev_files')]),
        (modelgen, modelestimate, [('design_file', 'design_file')]),

        # connect also residual4d and sigmasquared
        (modelestimate, outputspec, [('param_estimates',
                                      'parameter_estimates'),
                                     ('dof_file', 'dof_file'),
                                     ('residual4d', 'residual4d'),
                                     ('sigmasquareds', 'sigmasquareds')]),
    ])
    if version < 507:
        modelfit.connect([
            (modelgen, conestimate, [('con_file', 'tcon_file'),
                                     ('fcon_file', 'fcon_file')]),
            (modelestimate, conestimate, [('param_estimates',
                                           'param_estimates'),
                                          ('sigmasquareds', 'sigmasquareds'),
                                          ('corrections', 'corrections'),
                                          ('dof_file', 'dof_file')]),
            (conestimate, outputspec, [('copes', 'copes'),
                                       ('varcopes', 'varcopes')]),
        ])
    else:
        modelfit.connect([
            (modelgen, modelestimate, [('con_file', 'tcon_file'),
                                       ('fcon_file', 'fcon_file')]),
            (modelestimate, outputspec, [('copes', 'copes'),
                                         ('varcopes', 'varcopes')]),
        ])
    return modelfit
Exemple #6
0
def create_workflow():
    featpreproc = pe.Workflow(name="featpreproc")

    featpreproc.base_dir = os.path.join(ds_root, 'workingdirs')

    # ===================================================================
    #                  _____                   _
    #                 |_   _|                 | |
    #                   | |  _ __  _ __  _   _| |_
    #                   | | | '_ \| '_ \| | | | __|
    #                  _| |_| | | | |_) | |_| | |_
    #                 |_____|_| |_| .__/ \__,_|\__|
    #                             | |
    #                             |_|
    # ===================================================================

    # ------------------ Specify variables
    inputnode = pe.Node(
        niu.IdentityInterface(fields=[
            'funcs',
            'subject_id',
            'session_id',
            'fwhm',  # smoothing
            'highpass'
        ]),
        name="inputspec")

    # SelectFiles
    templates = {
        'ref_manual_fmapmask':  # was: manual_fmapmask
        'derivatives/manual-masks/sub-eddy/ses-20170511/fmap/'
            'sub-eddy_ses-20170511_magnitude1_res-1x1x1_manualmask.nii.gz',

        'ref_fmap_magnitude':
        'derivatives/manual-masks/sub-eddy/ses-20170511/fmap/'
            'sub-eddy_ses-20170511_magnitude1_res-1x1x1_reference.nii.gz',

        'ref_fmap_phasediff':
        'derivatives/resampled-isotropic-1mm/sub-eddy/ses-20170511/fmap/'
            'sub-eddy_ses-20170511_phasediff_res-1x1x1_preproc'
            '.nii.gz',

        # 'manualweights':
        # 'manual-masks/sub-eddy/ses-20170511/func/'
        #     'sub-eddy_ses-20170511_task-curvetracing_run-01_frame-50_bold'
        #     '_res-1x1x1_manualweights.nii.gz',

        'ref_func':  # was: manualmask_func_ref
        'derivatives/manual-masks/sub-eddy/ses-20170607/func/'
            'sub-eddy_ses-20170607_task-RestingPRF_run-02_bold_'
            'res-1x1x1_fnirt_reference.nii.gz',

        'ref_funcmask':  # was: manualmask
        'derivatives/manual-masks/sub-eddy/ses-20170607/func/'
            'sub-eddy_ses-20170607_task-RestingPRF_run-02_bold_'
            'res-1x1x1_fnirt_mask.nii.gz',

        'ref_t1':
        'derivatives/manual-masks/sub-eddy/ses-20170511/anat/'
            'sub-eddy_ses-20170511_T1w_res-1x1x1_reference.nii.gz',

        'ref_t1mask':
        'derivatives/manual-masks/sub-eddy/ses-20170511/anat/'
            'sub-eddy_ses-20170511_T1w_res-1x1x1_manualmask.nii.gz',

        # 'funcs':
        # 'resampled-isotropic-1mm/sub-{subject_id}/ses-{session_id}/func/'
        #     # 'sub-{subject_id}_ses-{session_id}*_bold_res-1x1x1_preproc'
        #     'sub-{subject_id}_ses-{session_id}*run-01_bold_res-1x1x1_preproc'
        #     # '.nii.gz',
        #     '_nvol10.nii.gz',

        'fmap_phasediff':
        'derivatives/resampled-isotropic-1mm/sub-{subject_id}/ses-{session_id}/fmap/'
            'sub-{subject_id}_ses-{session_id}_phasediff_res-1x1x1_preproc'
            '.nii.gz',

        'fmap_magnitude':
        'derivatives/resampled-isotropic-1mm/sub-{subject_id}/ses-{session_id}/fmap/'
            'sub-{subject_id}_ses-{session_id}_magnitude1_res-1x1x1_preproc'
            '.nii.gz',

        # 'fmap_mask':
        # 'transformed-manual-fmap-mask/sub-{subject_id}/ses-{session_id}/fmap/'
        #     'sub-{subject_id}_ses-{session_id}_'
        #     'magnitude1_res-1x1x1_preproc.nii.gz',
    }

    inputfiles = pe.Node(nio.SelectFiles(templates, base_directory=data_dir),
                         name="input_files")

    featpreproc.connect([(inputnode, inputfiles, [
        ('subject_id', 'subject_id'),
        ('session_id', 'session_id'),
    ])])

    # ===================================================================
    #                   ____        _               _
    #                  / __ \      | |             | |
    #                 | |  | |_   _| |_ _ __  _   _| |_
    #                 | |  | | | | | __| '_ \| | | | __|
    #                 | |__| | |_| | |_| |_) | |_| | |_
    #                  \____/ \__,_|\__| .__/ \__,_|\__|
    #                                  | |
    #                                  |_|
    # ===================================================================

    # ------------------ Output Files
    # Datasink
    outputfiles = pe.Node(nio.DataSink(base_directory=ds_root,
                                       container='derivatives/featpreproc',
                                       parameterization=True),
                          name="output_files")

    # Use the following DataSink output substitutions
    # each tuple is only matched once per file
    outputfiles.inputs.substitutions = [
        ('/_mc_method_afni3dAllinSlices/', '/'),
        ('/_mc_method_afni3dAllinSlices/', '/'),  # needs to appear twice
        ('/oned_file/', '/'),
        ('/out_file/', '/'),
        ('/oned_matrix_save/', '/'),
        ('subject_id_', 'sub-'),
        ('session_id_', 'ses-'),
    ]
    # Put result into a BIDS-like format
    outputfiles.inputs.regexp_substitutions = [
        (r'_ses-([a-zA-Z0-9]+)_sub-([a-zA-Z0-9]+)', r'sub-\2/ses-\1'),
        (r'/_addmean[0-9]+/', r'/func/'),
        (r'/_funcbrains[0-9]+/', r'/func/'),
        (r'/_maskfunc[0-9]+/', r'/func/'),
        (r'/_mc[0-9]+/', r'/func/'),
        (r'/_meanfunc[0-9]+/', r'/func/'),
        (r'/_outliers[0-9]+/', r'/func/'),
        (r'_run_id_[0-9][0-9]', r''),
    ]
    outputnode = pe.Node(interface=util.IdentityInterface(fields=[
        'motion_parameters',
        'motion_corrected',
        'motion_plots',
        'motion_outlier_files',
        'mask',
        'smoothed_files',
        'highpassed_files',
        'mean',
        'func_unwarp',
        'ref_func',
        'ref_funcmask',
        'ref_t1',
        'ref_t1mask',
    ]),
                         name='outputspec')

    # ===================================================================
    #                  _____ _            _ _
    #                 |  __ (_)          | (_)
    #                 | |__) | _ __   ___| |_ _ __   ___
    #                 |  ___/ | '_ \ / _ \ | | '_ \ / _ \
    #                 | |   | | |_) |  __/ | | | | |  __/
    #                 |_|   |_| .__/ \___|_|_|_| |_|\___|
    #                         | |
    #                         |_|
    # ===================================================================

    #  ~|~ _ _  _  _ |` _  _ _ _    _ _  _  _|  _
    #   | | (_|| |_\~|~(_)| | | |  | | |(_|_\|<_\
    #
    # Transform manual skull-stripped masks to multiple images
    # --------------------------------------------------------
    # should just be used as input to motion correction,
    # after mc, all functionals should be aligned to reference
    transmanmask_mc = transform_manualmask.create_workflow()

    # - - - - - - Connections - - - - - - -
    featpreproc.connect([(inputfiles, transmanmask_mc, [
        ('subject_id', 'in.subject_id'),
        ('session_id', 'in.session_id'),
    ])])

    featpreproc.connect(inputfiles, 'ref_funcmask', transmanmask_mc,
                        'in.manualmask')
    featpreproc.connect(inputnode, 'funcs', transmanmask_mc, 'in.funcs')
    featpreproc.connect(inputfiles, 'ref_func', transmanmask_mc,
                        'in.manualmask_func_ref')

    # fieldmaps not being used
    if False:
        trans_fmapmask = transmanmask_mc.clone('trans_fmapmask')
        featpreproc.connect(inputfiles, 'ref_manual_fmapmask', trans_fmapmask,
                            'in.manualmask')
        featpreproc.connect(inputfiles, 'fmap_magnitude', trans_fmapmask,
                            'in.funcs')
        featpreproc.connect(inputfiles, 'ref_func', trans_fmapmask,
                            'in.manualmask_func_ref')

    #  |\/| _ _|_. _  _    _ _  _ _ _  __|_. _  _
    #  |  |(_) | |(_)| |  (_(_)| | (/_(_ | |(_)| |
    #
    # Perform motion correction, using some pipeline
    # --------------------------------------------------------
    # mc = motioncorrection_workflow.create_workflow_afni()

    # Register an image from the functionals to the reference image
    median_func = pe.MapNode(
        interface=fsl.maths.MedianImage(dimension="T"),
        name='median_func',
        iterfield=('in_file'),
    )
    pre_mc = motioncorrection_workflow.create_workflow_allin_slices(
        name='premotioncorrection')

    featpreproc.connect([
        (inputnode, median_func, [
            ('funcs', 'in_file'),
        ]),
        (median_func, pre_mc, [
            ('out_file', 'in.funcs'),
        ]),
        (
            inputfiles,
            pre_mc,
            [
                # median func image will be used a reference / base
                ('ref_func', 'in.ref_func'),
                ('ref_funcmask', 'in.ref_func_weights'),
            ]),
        (
            transmanmask_mc,
            pre_mc,
            [
                ('funcreg.out_file', 'in.funcs_masks'),  # use mask as weights
            ]),
        (pre_mc, outputnode, [
            ('mc.out_file', 'pre_motion_corrected'),
            ('mc.oned_file', 'pre_motion_parameters.oned_file'),
            ('mc.oned_matrix_save', 'pre_motion_parameters.oned_matrix_save'),
        ]),
        (
            outputnode,
            outputfiles,
            [
                ('pre_motion_corrected', 'pre_motion_corrected.out_file'),
                ('pre_motion_parameters.oned_file',
                 'pre_motion_corrected.oned_file'
                 ),  # warp parameters in ASCII (.1D)
                ('pre_motion_parameters.oned_matrix_save',
                 'pre_motion_corrected.oned_matrix_save'
                 ),  # transformation matrices for each sub-brick
            ]),
    ])

    mc = motioncorrection_workflow.create_workflow_allin_slices(
        name='motioncorrection',
        iterfield=('in_file', 'ref_file', 'in_weight_file'))
    # - - - - - - Connections - - - - - - -
    featpreproc.connect([
        (inputnode, mc, [
            ('funcs', 'in.funcs'),
        ]),
        (
            pre_mc,
            mc,
            [
                # the median image realigned to the reference functional will serve as reference
                #  this way motion correction is done to an image more similar to the functionals
                ('mc.out_file', 'in.ref_func'),
            ]),
        (
            inputfiles,
            mc,
            [
                # Check and make sure the ref func mask is close enough to the registered median
                # image.
                ('ref_funcmask', 'in.ref_func_weights'),
            ]),
        (
            transmanmask_mc,
            mc,
            [
                ('funcreg.out_file', 'in.funcs_masks'),  # use mask as weights
            ]),
        (mc, outputnode, [
            ('mc.out_file', 'motion_corrected'),
            ('mc.oned_file', 'motion_parameters.oned_file'),
            ('mc.oned_matrix_save', 'motion_parameters.oned_matrix_save'),
        ]),
        (
            outputnode,
            outputfiles,
            [
                ('motion_corrected', 'motion_corrected.out_file'),
                ('motion_parameters.oned_file', 'motion_corrected.oned_file'
                 ),  # warp parameters in ASCII (.1D)
                ('motion_parameters.oned_matrix_save',
                 'motion_corrected.oned_matrix_save'
                 ),  # transformation matrices for each sub-brick
            ]),
    ])

    #  |~. _ | _| _ _  _  _    _ _  _ _ _  __|_. _  _
    #  |~|(/_|(_|| | |(_||_)  (_(_)| | (/_(_ | |(_)| |
    #                    |
    # Unwarp EPI distortions
    # --------------------------------------------------------

    # Performing motion correction to a reference that is undistorted,
    # so b0_unwarp is currently not needed
    if False:
        b0_unwarp = undistort_workflow.create_workflow()

        featpreproc.connect([
            (
                inputfiles,
                b0_unwarp,
                [  # ('subject_id', 'in.subject_id'),
                    # ('session_id', 'in.session_id'),
                    ('fmap_phasediff', 'in.fmap_phasediff'),
                    ('fmap_magnitude', 'in.fmap_magnitude'),
                ]),
            (mc, b0_unwarp, [
                ('mc.out_file', 'in.funcs'),
            ]),
            (transmanmask_mc, b0_unwarp, [
                ('funcreg.out_file', 'in.funcmasks'),
            ]),
            (trans_fmapmask, b0_unwarp, [('funcreg.out_file', 'in.fmap_mask')
                                         ]),
            (b0_unwarp, outputfiles, [
                ('out.funcs', 'func_unwarp.funcs'),
                ('out.funcmasks', 'func_unwarp.funcmasks'),
            ]),
            (b0_unwarp, outputnode, [
                ('out.funcs', 'func_unwarp.funcs'),
                ('out.funcmasks', 'mask'),
            ]),
        ])

    # undistort the reference images
    if False:
        b0_unwarp_ref = b0_unwarp.clone('b0_unwarp_ref')
        featpreproc.connect([
            (
                inputfiles,
                b0_unwarp_ref,
                [  # ('subject_id', 'in.subject_id'),
                    # ('session_id', 'in.session_id'),
                    ('ref_fmap_phasediff', 'in.fmap_phasediff'),
                    ('ref_fmap_magnitude', 'in.fmap_magnitude'),
                    ('ref_manual_fmapmask', 'in.fmap_mask'),
                    ('ref_func', 'in.funcs'),
                    ('ref_funcmask', 'in.funcmasks'),
                ]),
            (b0_unwarp_ref, outputfiles, [
                ('out.funcs', 'func_unwarp_ref.func'),
                ('out.funcmasks', 'func_unwarp_ref.funcmask'),
            ]),
            (b0_unwarp_ref, outputnode, [
                ('out.funcs', 'ref_func'),
                ('out.funcmasks', 'ref_mask'),
            ]),
        ])
    else:
        featpreproc.connect([
            (inputfiles, outputfiles, [
                ('ref_func', 'reference/func'),
                ('ref_funcmask', 'reference/func_mask'),
            ]),
            (inputfiles, outputnode, [
                ('ref_func', 'ref_func'),
                ('ref_funcmask', 'ref_funcmask'),
            ]),
        ])

    # |~) _  _ . __|_ _  _  _|_ _   |~) _  |` _  _ _  _  _ _
    # |~\(/_(_||_\ | (/_|    | (_)  |~\(/_~|~(/_| (/_| |(_(/_
    #        _|
    # Register all functionals to common reference
    # --------------------------------------------------------
    if False:  # this is now done during motion correction
        # FLIRT cost: intermodal: corratio, intramodal: least squares and normcorr
        reg_to_ref = pe.MapNode(  # intra-modal
            # some runs need to be scaled along the anterior-posterior direction
            interface=fsl.FLIRT(dof=12, cost='normcorr'),
            name='reg_to_ref',
            iterfield=('in_file', 'in_weight'),
        )
        refEPI_to_refT1 = pe.Node(
            # some runs need to be scaled along the anterior-posterior direction
            interface=fsl.FLIRT(dof=12, cost='corratio'),
            name='refEPI_to_refT1',
        )
        # combine func -> ref_func and ref_func -> ref_T1
        reg_to_refT1 = pe.MapNode(
            interface=fsl.ConvertXFM(concat_xfm=True),
            name='reg_to_refT1',
            iterfield=('in_file'),
        )

        reg_funcs = pe.MapNode(
            interface=fsl.preprocess.ApplyXFM(),
            name='reg_funcs',
            iterfield=('in_file', 'in_matrix_file'),
        )
        reg_funcmasks = pe.MapNode(interface=fsl.preprocess.ApplyXFM(),
                                   name='reg_funcmasks',
                                   iterfield=('in_file', 'in_matrix_file'))

        def deref_list(x):
            assert len(x) == 1
            return x[0]

        featpreproc.connect([
            (
                b0_unwarp,
                reg_to_ref,  # --> reg_to_ref, (A)
                [
                    ('out.funcs', 'in_file'),
                    ('out.funcmasks', 'in_weight'),
                ]),
            (b0_unwarp_ref, reg_to_ref, [
                (('out.funcs', deref_list), 'reference'),
                (('out.funcmasks', deref_list), 'ref_weight'),
            ]),
            (
                b0_unwarp_ref,
                refEPI_to_refT1,  # --> refEPI_to_refT1 (B)
                [
                    (('out.funcs', deref_list), 'in_file'),
                    (('out.funcmasks', deref_list), 'in_weight'),
                ]),
            (inputfiles, refEPI_to_refT1, [
                ('ref_t1', 'reference'),
                ('ref_t1mask', 'ref_weight'),
            ]),
            (
                reg_to_ref,
                reg_to_refT1,  # --> reg_to_refT1 (A*B)
                [
                    ('out_matrix_file', 'in_file'),
                ]),
            (refEPI_to_refT1, reg_to_refT1, [
                ('out_matrix_file', 'in_file2'),
            ]),
            (
                reg_to_refT1,
                reg_funcs,  # --> reg_funcs
                [
                    # ('out_matrix_file', 'in_matrix_file'),
                    ('out_file', 'in_matrix_file'),
                ]),
            (b0_unwarp, reg_funcs, [
                ('out.funcs', 'in_file'),
            ]),
            (b0_unwarp_ref, reg_funcs, [
                (('out.funcs', deref_list), 'reference'),
            ]),
            (
                reg_to_refT1,
                reg_funcmasks,  # --> reg_funcmasks
                [
                    # ('out_matrix_file', 'in_matrix_file'),
                    ('out_file', 'in_matrix_file'),
                ]),
            (b0_unwarp, reg_funcmasks, [
                ('out.funcmasks', 'in_file'),
            ]),
            (b0_unwarp_ref, reg_funcmasks, [
                (('out.funcs', deref_list), 'reference'),
            ]),
            (reg_funcs, outputfiles, [
                ('out_file', 'common_ref.func'),
            ]),
            (reg_funcmasks, outputfiles, [
                ('out_file', 'common_ref.funcmask'),
            ]),
        ])

    #  |\/| _ _|_. _  _    _   _|_|. _  _ _
    #  |  |(_) | |(_)| |  (_)|_|| ||(/_| _\
    #
    # --------------------------------------------------------

    # Apply brain masks to functionals
    # --------------------------------------------------------

    # Dilate mask
    """
    Dilate the mask
    """
    if False:
        dilatemask = pe.MapNode(interface=fsl.ImageMaths(suffix='_dil',
                                                         op_string='-dilF'),
                                iterfield=['in_file'],
                                name='dilatemask')
        featpreproc.connect(reg_funcmasks, 'out_file', dilatemask, 'in_file')
    else:
        dilatemask = pe.Node(interface=fsl.ImageMaths(suffix='_dil',
                                                      op_string='-dilF'),
                             name='dilatemask')
        featpreproc.connect(inputfiles, 'ref_funcmask', dilatemask, 'in_file')

    featpreproc.connect(dilatemask, 'out_file', outputfiles, 'dilate_mask')

    funcbrains = pe.MapNode(fsl.BinaryMaths(operation='mul'),
                            iterfield=('in_file', 'operand_file'),
                            name='funcbrains')

    featpreproc.connect([
        (mc, funcbrains, [
            ('mc.out_file', 'in_file'),
        ]),
        (dilatemask, funcbrains, [
            ('out_file', 'operand_file'),
        ]),
        (funcbrains, outputfiles, [
            ('out_file', 'funcbrains'),
        ]),
    ])
    # Detect motion outliers
    # --------------------------------------------------------

    import nipype.algorithms.rapidart as ra
    outliers = pe.MapNode(
        ra.ArtifactDetect(
            mask_type='file',
            # trying to "disable" `norm_threshold`:
            use_norm=True,
            norm_threshold=10.0,  # combines translations in mm and rotations
            # use_norm=Undefined,
            # translation_threshold=1.0,  # translation in mm
            # rotation_threshold=0.02,  # rotation in radians
            zintensity_threshold=3.0,  # z-score
            parameter_source='AFNI',
            save_plot=True),
        iterfield=('realigned_files', 'realignment_parameters', 'mask_file'),
        name='outliers')

    featpreproc.connect([
        (
            mc,
            outliers,
            [  # ('mc.par_file', 'realignment_parameters'),
                ('mc.oned_file', 'realignment_parameters'),
            ]),
        (funcbrains, outliers, [
            ('out_file', 'realigned_files'),
        ]),
        (dilatemask, outliers, [
            ('out_file', 'mask_file'),
        ]),
        (
            outliers,
            outputfiles,
            [
                ('outlier_files', 'motion_outliers.@outlier_files'),
                ('plot_files', 'motion_outliers.@plot_files'),
                ('displacement_files', 'motion_outliers.@displacement_files'),
                ('intensity_files', 'motion_outliers.@intensity_files'),
                ('mask_files', 'motion_outliers.@mask_files'),
                ('statistic_files', 'motion_outliers.@statistic_files'),
                # ('norm_files', 'outliers.@norm_files'),
            ]),
        (mc, outputnode, [
            ('mc.oned_file', 'motion_parameters'),
        ]),
        (
            outliers,
            outputnode,
            [
                ('outlier_files', 'motion_outlier_files'),
                ('plot_files', 'motion_plots.@plot_files'),
                ('displacement_files', 'motion_outliers.@displacement_files'),
                ('intensity_files', 'motion_outliers.@intensity_files'),
                ('mask_files', 'motion_outliers.@mask_files'),
                ('statistic_files', 'motion_outliers.@statistic_files'),
                # ('norm_files', 'outliers.@norm_files'),
            ])
    ])
    """
    Determine the 2nd and 98th percentile intensities of each functional run
    """
    getthresh = pe.MapNode(interface=fsl.ImageStats(op_string='-p 2 -p 98'),
                           iterfield=['in_file'],
                           name='getthreshold')
    if False:
        featpreproc.connect(b0_unwarp, 'out.funcs', getthresh, 'in_file')
    else:
        featpreproc.connect(mc, 'mc.out_file', getthresh, 'in_file')
    """
    Threshold the first run of functional data at 10% of the 98th percentile
    """

    threshold = pe.MapNode(interface=fsl.ImageMaths(out_data_type='char',
                                                    suffix='_thresh'),
                           iterfield=['in_file', 'op_string'],
                           name='threshold')
    if False:
        featpreproc.connect(b0_unwarp, 'out.funcs', threshold, 'in_file')
    else:
        featpreproc.connect(mc, 'mc.out_file', threshold, 'in_file')
    """
    Define a function to get 10% of the intensity
    """
    def getthreshop(thresh):
        return ['-thr %.10f -Tmin -bin' % (0.1 * val[1]) for val in thresh]

    featpreproc.connect(getthresh, ('out_stat', getthreshop), threshold,
                        'op_string')
    """
    Determine the median value of the functional runs using the mask
    """
    medianval = pe.MapNode(interface=fsl.ImageStats(op_string='-k %s -p 50'),
                           iterfield=['in_file', 'mask_file'],
                           name='medianval')
    if False:
        featpreproc.connect(b0_unwarp, 'out.funcs', medianval, 'in_file')
    else:
        featpreproc.connect(mc, 'mc.out_file', medianval, 'in_file')

    featpreproc.connect(threshold, 'out_file', medianval, 'mask_file')

    # (~ _  _ _|_. _ |  (~ _ _  _  _ _|_|_ . _  _
    # _)|_)(_| | |(_||  _)| | |(_)(_) | | ||| |(_|
    #   |                                       _|
    # Spatial smoothing (SUSAN)
    # --------------------------------------------------------

    # create_susan_smooth takes care of calculating the mean and median
    #   functional, applying mask to functional, and running the smoothing
    smooth = create_susan_smooth(separate_masks=False)
    featpreproc.connect(inputnode, 'fwhm', smooth, 'inputnode.fwhm')

    # featpreproc.connect(b0_unwarp, 'out.funcs', smooth, 'inputnode.in_files')
    if False:
        featpreproc.connect(reg_funcs, 'out_file', smooth,
                            'inputnode.in_files')
    else:
        featpreproc.connect(mc, 'mc.out_file', smooth, 'inputnode.in_files')

    featpreproc.connect(dilatemask, 'out_file', smooth, 'inputnode.mask_file')

    # -------------------------------------------------------
    # The below is from workflows/fmri/fsl/preprocess.py
    """
    Mask the smoothed data with the dilated mask
    """

    maskfunc3 = pe.MapNode(interface=fsl.ImageMaths(suffix='_mask',
                                                    op_string='-mas'),
                           iterfield=['in_file', 'in_file2'],
                           name='maskfunc3')
    featpreproc.connect(smooth, 'outputnode.smoothed_files', maskfunc3,
                        'in_file')

    featpreproc.connect(dilatemask, 'out_file', maskfunc3, 'in_file2')

    concatnode = pe.Node(interface=util.Merge(2), name='concat')

    tolist = lambda x: [x]

    def chooseindex(fwhm):
        if fwhm < 1:
            return [0]
        else:
            return [1]

    # maskfunc2 is the functional data before SUSAN
    if False:
        featpreproc.connect(b0_unwarp, ('out.funcs', tolist), concatnode,
                            'in1')
    else:
        featpreproc.connect(mc, ('mc.out_file', tolist), concatnode, 'in1')
    # maskfunc3 is the functional data after SUSAN
    featpreproc.connect(maskfunc3, ('out_file', tolist), concatnode, 'in2')
    """
    The following nodes select smooth or unsmoothed data depending on the
    fwhm. This is because SUSAN defaults to smoothing the data with about the
    voxel size of the input data if the fwhm parameter is less than 1/3 of the
    voxel size.
    """
    selectnode = pe.Node(interface=util.Select(), name='select')

    featpreproc.connect(concatnode, 'out', selectnode, 'inlist')

    featpreproc.connect(inputnode, ('fwhm', chooseindex), selectnode, 'index')
    featpreproc.connect(selectnode, 'out', outputfiles, 'smoothed_files')
    """
    Scale the median value of the run is set to 10000.
    """

    meanscale = pe.MapNode(interface=fsl.ImageMaths(suffix='_gms'),
                           iterfield=['in_file', 'op_string'],
                           name='meanscale')
    featpreproc.connect(selectnode, 'out', meanscale, 'in_file')
    """
    Define a function to get the scaling factor for intensity normalization
    """

    featpreproc.connect(medianval, ('out_stat', getmeanscale), meanscale,
                        'op_string')

    # |_|. _ |_  _  _  _ _
    # | ||(_|| ||_)(_|_\_\
    #      _|   |
    # Temporal filtering
    # --------------------------------------------------------

    highpass = pe.MapNode(interface=fsl.ImageMaths(suffix='_tempfilt'),
                          iterfield=['in_file'],
                          name='highpass')
    highpass_operand = lambda x: '-bptf %.10f -1' % x
    featpreproc.connect(inputnode, ('highpass', highpass_operand), highpass,
                        'op_string')
    featpreproc.connect(meanscale, 'out_file', highpass, 'in_file')

    version = 0
    if fsl.Info.version() and \
            LooseVersion(fsl.Info.version()) > LooseVersion('5.0.6'):
        version = 507

    if version < 507:
        featpreproc.connect(highpass, 'out_file', outputnode,
                            'highpassed_files')
    else:
        """
        Add back the mean removed by the highpass filter operation as
            of FSL 5.0.7
        """
        meanfunc4 = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                        suffix='_mean'),
                               iterfield=['in_file'],
                               name='meanfunc4')

        featpreproc.connect(meanscale, 'out_file', meanfunc4, 'in_file')
        addmean = pe.MapNode(interface=fsl.BinaryMaths(operation='add'),
                             iterfield=['in_file', 'operand_file'],
                             name='addmean')
        featpreproc.connect(highpass, 'out_file', addmean, 'in_file')
        featpreproc.connect(meanfunc4, 'out_file', addmean, 'operand_file')
        featpreproc.connect(addmean, 'out_file', outputnode,
                            'highpassed_files')
    """
    Generate a mean functional image from the first run
    """
    meanfunc3 = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                    suffix='_mean'),
                           iterfield=['in_file'],
                           name='meanfunc3')

    featpreproc.connect(meanscale, 'out_file', meanfunc3, 'in_file')
    featpreproc.connect(meanfunc3, 'out_file', outputfiles, 'mean')

    featpreproc.connect(meanfunc3, 'out_file', outputnode, 'mean_highpassed')
    featpreproc.connect(outputnode, 'highpassed_files', outputfiles,
                        'highpassed_files')

    return (featpreproc)
Exemple #7
0
from nipype.algorithms.misc import TSNR, CalculateMedian
from nipype.interfaces.c3 import C3dAffineTool
from nipype.interfaces import fsl, Function, ants, freesurfer as fs
import nipype.interfaces.io as nio
from nipype.interfaces.io import FreeSurferSource
import nipype.interfaces.utility as niu
from nipype.interfaces.utility import Merge, IdentityInterface
from nipype.workflows.fmri.fsl import (create_featreg_preproc,
                                       create_modelfit_workflow,
                                       create_fixed_effects_flow)
from nipype.utils import NUMPY_MMAP

config.enable_provenance()
version = 0
if (fsl.Info.version()
        and LooseVersion(fsl.Info.version()) > LooseVersion('5.0.6')):
    version = 507

fsl.FSLCommand.set_default_output_type('NIFTI_GZ')

imports = [
    'import os', 'import nibabel as nb', 'import numpy as np',
    'import scipy as sp',
    'from nipype.utils.filemanip import filename_to_list, list_to_filename, split_filename',
    'from scipy.special import legendre'
]


def create_reg_workflow(name='registration'):
    """Create a FEAT preprocessing workflow together with freesurfer
Exemple #8
0
    def looseversion(cls):
        """ Return a comparable version object

        If no version found, use LooseVersion('0.0.0')
        """
        return LooseVersion(cls.version() or '0.0.0')
Exemple #9
0
def create_featreg_preproc(name='featpreproc',
                           highpass=True,
                           whichvol='middle'):
    """Create a FEAT preprocessing workflow with registration to one volume of the first run

    Parameters
    ----------

    ::

        name : name of workflow (default: featpreproc)
        highpass : boolean (default: True)
        whichvol : which volume of the first run to register to ('first', 'middle', 'mean')

    Inputs::

        inputspec.func : functional runs (filename or list of filenames)
        inputspec.fwhm : fwhm for smoothing with SUSAN
        inputspec.highpass : HWHM in TRs (if created with highpass=True)

    Outputs::

        outputspec.reference : volume to which runs are realigned
        outputspec.motion_parameters : motion correction parameters
        outputspec.realigned_files : motion corrected files
        outputspec.motion_plots : plots of motion correction parameters
        outputspec.mask : mask file used to mask the brain
        outputspec.smoothed_files : smoothed functional data
        outputspec.highpassed_files : highpassed functional data (if highpass=True)
        outputspec.mean : mean file

    Example
    -------

    >>> preproc = create_featreg_preproc()
    >>> preproc.inputs.inputspec.func = ['f3.nii', 'f5.nii']
    >>> preproc.inputs.inputspec.fwhm = 5
    >>> preproc.inputs.inputspec.highpass = 128./(2*2.5)
    >>> preproc.base_dir = '/tmp'
    >>> preproc.run() # doctest: +SKIP

    >>> preproc = create_featreg_preproc(highpass=False, whichvol='mean')
    >>> preproc.inputs.inputspec.func = 'f3.nii'
    >>> preproc.inputs.inputspec.fwhm = 5
    >>> preproc.base_dir = '/tmp'
    >>> preproc.run() # doctest: +SKIP
    """

    version = 0
    if fsl.Info.version() and \
        LooseVersion(fsl.Info.version()) > LooseVersion('5.0.6'):
        version = 507

    featpreproc = pe.Workflow(name=name)
    """
    Set up a node to define all inputs required for the preprocessing workflow

    """

    if highpass:
        inputnode = pe.Node(interface=util.IdentityInterface(
            fields=['func', 'fwhm', 'highpass']),
                            name='inputspec')
        outputnode = pe.Node(interface=util.IdentityInterface(fields=[
            'reference', 'motion_parameters', 'realigned_files',
            'motion_plots', 'mask', 'smoothed_files', 'highpassed_files',
            'mean'
        ]),
                             name='outputspec')
    else:
        inputnode = pe.Node(
            interface=util.IdentityInterface(fields=['func', 'fwhm']),
            name='inputspec')
        outputnode = pe.Node(interface=util.IdentityInterface(fields=[
            'reference', 'motion_parameters', 'realigned_files',
            'motion_plots', 'mask', 'smoothed_files', 'mean'
        ]),
                             name='outputspec')
    """
    Set up a node to define outputs for the preprocessing workflow

    """
    """
    Convert functional images to float representation. Since there can
    be more than one functional run we use a MapNode to convert each
    run.
    """

    img2float = pe.MapNode(interface=fsl.ImageMaths(out_data_type='float',
                                                    op_string='',
                                                    suffix='_dtype'),
                           iterfield=['in_file'],
                           name='img2float')
    featpreproc.connect(inputnode, 'func', img2float, 'in_file')
    """
    Extract the first volume of the first run as the reference
    """

    if whichvol != 'mean':
        extract_ref = pe.Node(interface=fsl.ExtractROI(t_size=1),
                              iterfield=['in_file'],
                              name='extractref')
        featpreproc.connect(img2float, ('out_file', pickfirst), extract_ref,
                            'in_file')
        featpreproc.connect(img2float, ('out_file', pickvol, 0, whichvol),
                            extract_ref, 't_min')
        featpreproc.connect(extract_ref, 'roi_file', outputnode, 'reference')
    """
    Realign the functional runs to the reference (1st volume of first run)
    """

    motion_correct = pe.MapNode(interface=fsl.MCFLIRT(save_mats=True,
                                                      save_plots=True,
                                                      interpolation='spline'),
                                name='realign',
                                iterfield=['in_file'])
    featpreproc.connect(img2float, 'out_file', motion_correct, 'in_file')
    if whichvol != 'mean':
        featpreproc.connect(extract_ref, 'roi_file', motion_correct,
                            'ref_file')
    else:
        motion_correct.inputs.mean_vol = True
        featpreproc.connect(motion_correct, ('mean_img', pickfirst),
                            outputnode, 'reference')

    featpreproc.connect(motion_correct, 'par_file', outputnode,
                        'motion_parameters')
    featpreproc.connect(motion_correct, 'out_file', outputnode,
                        'realigned_files')
    """
    Plot the estimated motion parameters
    """

    plot_motion = pe.MapNode(interface=fsl.PlotMotionParams(in_source='fsl'),
                             name='plot_motion',
                             iterfield=['in_file'])
    plot_motion.iterables = ('plot_type', ['rotations', 'translations'])
    featpreproc.connect(motion_correct, 'par_file', plot_motion, 'in_file')
    featpreproc.connect(plot_motion, 'out_file', outputnode, 'motion_plots')
    """
    Extract the mean volume of the first functional run
    """

    meanfunc = pe.Node(interface=fsl.ImageMaths(op_string='-Tmean',
                                                suffix='_mean'),
                       name='meanfunc')
    featpreproc.connect(motion_correct, ('out_file', pickfirst), meanfunc,
                        'in_file')
    """
    Strip the skull from the mean functional to generate a mask
    """

    meanfuncmask = pe.Node(interface=fsl.BET(mask=True,
                                             no_output=True,
                                             frac=0.3),
                           name='meanfuncmask')
    featpreproc.connect(meanfunc, 'out_file', meanfuncmask, 'in_file')
    """
    Mask the functional runs with the extracted mask
    """

    maskfunc = pe.MapNode(interface=fsl.ImageMaths(suffix='_bet',
                                                   op_string='-mas'),
                          iterfield=['in_file'],
                          name='maskfunc')
    featpreproc.connect(motion_correct, 'out_file', maskfunc, 'in_file')
    featpreproc.connect(meanfuncmask, 'mask_file', maskfunc, 'in_file2')
    """
    Determine the 2nd and 98th percentile intensities of each functional run
    """

    getthresh = pe.MapNode(interface=fsl.ImageStats(op_string='-p 2 -p 98'),
                           iterfield=['in_file'],
                           name='getthreshold')
    featpreproc.connect(maskfunc, 'out_file', getthresh, 'in_file')
    """
    Threshold the first run of the functional data at 10% of the 98th percentile
    """

    threshold = pe.MapNode(interface=fsl.ImageMaths(out_data_type='char',
                                                    suffix='_thresh'),
                           iterfield=['in_file', 'op_string'],
                           name='threshold')
    featpreproc.connect(maskfunc, 'out_file', threshold, 'in_file')
    """
    Define a function to get 10% of the intensity
    """

    featpreproc.connect(getthresh, ('out_stat', getthreshop), threshold,
                        'op_string')
    """
    Determine the median value of the functional runs using the mask
    """

    medianval = pe.MapNode(interface=fsl.ImageStats(op_string='-k %s -p 50'),
                           iterfield=['in_file', 'mask_file'],
                           name='medianval')
    featpreproc.connect(motion_correct, 'out_file', medianval, 'in_file')
    featpreproc.connect(threshold, 'out_file', medianval, 'mask_file')
    """
    Dilate the mask
    """

    dilatemask = pe.MapNode(interface=fsl.ImageMaths(suffix='_dil',
                                                     op_string='-dilF'),
                            iterfield=['in_file'],
                            name='dilatemask')
    featpreproc.connect(threshold, 'out_file', dilatemask, 'in_file')
    featpreproc.connect(dilatemask, 'out_file', outputnode, 'mask')
    """
    Mask the motion corrected functional runs with the dilated mask
    """

    maskfunc2 = pe.MapNode(interface=fsl.ImageMaths(suffix='_mask',
                                                    op_string='-mas'),
                           iterfield=['in_file', 'in_file2'],
                           name='maskfunc2')
    featpreproc.connect(motion_correct, 'out_file', maskfunc2, 'in_file')
    featpreproc.connect(dilatemask, 'out_file', maskfunc2, 'in_file2')
    """
    Smooth each run using SUSAN with the brightness threshold set to 75%
    of the median value for each run and a mask constituting the mean
    functional
    """

    smooth = create_susan_smooth()

    featpreproc.connect(inputnode, 'fwhm', smooth, 'inputnode.fwhm')
    featpreproc.connect(maskfunc2, 'out_file', smooth, 'inputnode.in_files')
    featpreproc.connect(dilatemask, 'out_file', smooth, 'inputnode.mask_file')
    """
    Mask the smoothed data with the dilated mask
    """

    maskfunc3 = pe.MapNode(interface=fsl.ImageMaths(suffix='_mask',
                                                    op_string='-mas'),
                           iterfield=['in_file', 'in_file2'],
                           name='maskfunc3')
    featpreproc.connect(smooth, 'outputnode.smoothed_files', maskfunc3,
                        'in_file')

    featpreproc.connect(dilatemask, 'out_file', maskfunc3, 'in_file2')

    concatnode = pe.Node(interface=util.Merge(2), name='concat')
    featpreproc.connect(maskfunc2, ('out_file', tolist), concatnode, 'in1')
    featpreproc.connect(maskfunc3, ('out_file', tolist), concatnode, 'in2')
    """
    The following nodes select smooth or unsmoothed data depending on the
    fwhm. This is because SUSAN defaults to smoothing the data with about the
    voxel size of the input data if the fwhm parameter is less than 1/3 of the
    voxel size.
    """
    selectnode = pe.Node(interface=util.Select(), name='select')

    featpreproc.connect(concatnode, 'out', selectnode, 'inlist')

    featpreproc.connect(inputnode, ('fwhm', chooseindex), selectnode, 'index')
    featpreproc.connect(selectnode, 'out', outputnode, 'smoothed_files')
    """
    Scale the median value of the run is set to 10000
    """

    meanscale = pe.MapNode(interface=fsl.ImageMaths(suffix='_gms'),
                           iterfield=['in_file', 'op_string'],
                           name='meanscale')
    featpreproc.connect(selectnode, 'out', meanscale, 'in_file')
    """
    Define a function to get the scaling factor for intensity normalization
    """

    featpreproc.connect(medianval, ('out_stat', getmeanscale), meanscale,
                        'op_string')
    """
    Generate a mean functional image from the first run
    """

    meanfunc3 = pe.Node(interface=fsl.ImageMaths(op_string='-Tmean',
                                                 suffix='_mean'),
                        iterfield=['in_file'],
                        name='meanfunc3')

    featpreproc.connect(meanscale, ('out_file', pickfirst), meanfunc3,
                        'in_file')
    featpreproc.connect(meanfunc3, 'out_file', outputnode, 'mean')
    """
    Perform temporal highpass filtering on the data
    """

    if highpass:
        highpass = pe.MapNode(interface=fsl.ImageMaths(suffix='_tempfilt'),
                              iterfield=['in_file'],
                              name='highpass')
        featpreproc.connect(inputnode, ('highpass', highpass_operand),
                            highpass, 'op_string')
        featpreproc.connect(meanscale, 'out_file', highpass, 'in_file')

        if version < 507:
            featpreproc.connect(highpass, 'out_file', outputnode,
                                'highpassed_files')
        else:
            """
            Add back the mean removed by the highpass filter operation as of FSL 5.0.7
            """
            meanfunc4 = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                            suffix='_mean'),
                                   iterfield=['in_file'],
                                   name='meanfunc4')

            featpreproc.connect(meanscale, 'out_file', meanfunc4, 'in_file')
            addmean = pe.MapNode(interface=fsl.BinaryMaths(operation='add'),
                                 iterfield=['in_file', 'operand_file'],
                                 name='addmean')
            featpreproc.connect(highpass, 'out_file', addmean, 'in_file')
            featpreproc.connect(meanfunc4, 'out_file', addmean, 'operand_file')
            featpreproc.connect(addmean, 'out_file', outputnode,
                                'highpassed_files')

    return featpreproc
Exemple #10
0
from os import path as osp
from time import time

import nipype.interfaces.fsl as fsl
from nipype import LooseVersion
from nipype.algorithms.misc import Gunzip
from nipype.interfaces.io import SelectFiles, DataSink
from nipype.interfaces.matlab import MatlabCommand
from nipype.interfaces.utility import IdentityInterface, Merge
from nipype.pipeline.engine import Workflow, Node, MapNode

t_start = time()

# Check FSL version
version = 0
if fsl.Info.version() and LooseVersion(
        fsl.Info.version()) > LooseVersion('5.0.6'):
    version = 507

# Set up interface defaults
MatlabCommand.set_default_paths('/usr/local/matlabtools/2016a/spm12')
MatlabCommand.set_default_matlab_cmd("matlab -nodesktop -nosplash")

# Disabled default output type as this will force all other file extensions to NIFTI as well
# fsl.FSLCommand.set_default_output_type('NIFTI')

BASE_DIR = '/data/wbbruin/Desktop/resting-state_nipype/testset'
DATA_DIR = osp.join(BASE_DIR, 'data')
WORKING_DIR = osp.join(BASE_DIR, 'workdir')

# Configure pre processing parameters
template = fsl.Info.standard_image('MNI152_T1_2mm.nii.gz')
def create_workflow(undist):
    featpreproc = pe.Workflow(name="featpreproc")

    featpreproc.base_dir = os.path.join(ds_root, 'workingdirs')

    # ===================================================================
    #                  _____                   _
    #                 |_   _|                 | |
    #                   | |  _ __  _ __  _   _| |_
    #                   | | | '_ \| '_ \| | | | __|
    #                  _| |_| | | | |_) | |_| | |_
    #                 |_____|_| |_| .__/ \__,_|\__|
    #                             | |
    #                             |_|
    # ===================================================================

    # ------------------ Specify variables
    inputnode = pe.Node(
        niu.IdentityInterface(fields=[
            'funcs',
            'subject_id',
            'session_id',
            'refsubject_id',
            'fwhm',  # smoothing
            'highpass'
        ]),
        name="inputspec")

    if undist:
        ud_flag = '_undist_PLUS'
    else:
        ud_flag = ''

    # SelectFiles
    templates = {
        # EPI ========
        'ref_func':
        'reference-vols/sub-{refsubject_id}/func/'
        'sub-{subject_id}_ref_func_res-1x1x1' + ud_flag + '.nii.gz',
        'ref_funcmask':
        'reference-vols/sub-{refsubject_id}/func/'
        'sub-{subject_id}_ref_func_mask_res-1x1x1.nii.gz',

        # T1 ========
        # 0.5 mm iso ---
        'ref_t1':
        'reference-vols/sub-{refsubject_id}/anat/'
        'sub-{subject_id}_ref_anat_res-0.5x0.5x0.5.nii.gz',
        'ref_t1mask':
        'reference-vols/sub-{refsubject_id}/anat/'
        'sub-{subject_id}_ref_anat_mask_res-0.5x0.5x0.5.nii.gz',
    }

    inputfiles = pe.Node(nio.SelectFiles(templates, base_directory=data_dir),
                         name="input_files")

    featpreproc.connect([(inputnode, inputfiles, [
        ('subject_id', 'subject_id'),
        ('session_id', 'session_id'),
        ('refsubject_id', 'refsubject_id'),
    ])])

    # ===================================================================
    #                   ____        _               _
    #                  / __ \      | |             | |
    #                 | |  | |_   _| |_ _ __  _   _| |_
    #                 | |  | | | | | __| '_ \| | | | __|
    #                 | |__| | |_| | |_| |_) | |_| | |_
    #                  \____/ \__,_|\__| .__/ \__,_|\__|
    #                                  | |
    #                                  |_|
    # ===================================================================

    # Datasink
    outputfiles = pe.Node(nio.DataSink(base_directory=ds_root,
                                       container='derivatives/featpreproc',
                                       parameterization=True),
                          name="output_files")

    # Use the following DataSink output substitutions
    # each tuple is only matched once per file
    outputfiles.inputs.substitutions = [
        ('/_mc_method_afni3dAllinSlices/', '/'),
        ('/_mc_method_afni3dAllinSlices/', '/'),  # needs to appear twice
        ('/oned_file/', '/'),
        ('/out_file/', '/'),
        ('/oned_matrix_save/', '/'),
        ('refsubject_id_', 'ref-'),
        ('subject_id_', 'sub-'),
        ('session_id_', 'ses-'),
    ]
    # Put result into a BIDS-like format
    outputfiles.inputs.regexp_substitutions = [
        (r'_ses-([a-zA-Z0-9]+)_sub-([a-zA-Z0-9]+)', r'sub-\2/ses-\1'),
        (r'/_addmean[0-9]+/', r'/func/'),
        (r'/_funcbrains[0-9]+/', r'/func/'),
        (r'/_maskfunc[0-9]+/', r'/func/'),
        (r'/_mc[0-9]+/', r'/func/'),
        (r'/_meanfunc[0-9]+/', r'/func/'),
        (r'/_outliers[0-9]+/', r'/func/'),
        (r'_ref-([a-zA-Z0-9]+)_run_id_[0-9][0-9]', r''),
    ]
    outputnode = pe.Node(interface=util.IdentityInterface(fields=[
        'motion_parameters',
        'motion_corrected',
        'motion_plots',
        'motion_outlier_files',
        'mask',
        'smoothed_files',
        'highpassed_files',
        'mean',
        'func_unwarp',
        'ref_func',
        'ref_funcmask',
        'ref_t1',
        'ref_t1mask',
    ]),
                         name='outputspec')

    # ===================================================================
    #                  _____ _            _ _
    #                 |  __ (_)          | (_)
    #                 | |__) | _ __   ___| |_ _ __   ___
    #                 |  ___/ | '_ \ / _ \ | | '_ \ / _ \
    #                 | |   | | |_) |  __/ | | | | |  __/
    #                 |_|   |_| .__/ \___|_|_|_| |_|\___|
    #                         | |
    #                         |_|
    # ===================================================================

    #  ~|~ _ _  _  _ |` _  _ _ _    _ _  _  _|  _
    #   | | (_|| |_\~|~(_)| | | |  | | |(_|_\|<_\
    #
    # Transform manual skull-stripped masks to multiple images
    # --------------------------------------------------------
    # should just be used as input to motion correction,
    # after mc, all functionals should be aligned to reference
    transmanmask_mc = transform_manualmask.create_workflow()

    # - - - - - - Connections - - - - - - -
    featpreproc.connect([(inputfiles, transmanmask_mc, [
        ('subject_id', 'in.subject_id'),
        ('session_id', 'in.session_id'),
        ('refsubject_id', 'in.refsubject_id'),
    ])])

    #featpreproc.connect(inputfiles, 'ref_funcmask',
    #                    transmanmask_mc, 'in.manualmask')
    featpreproc.connect(inputfiles, 'ref_funcmask', transmanmask_mc,
                        'in.ref_funcmask')
    featpreproc.connect(inputnode, 'funcs', transmanmask_mc, 'in.funcs')

    featpreproc.connect(inputfiles, 'ref_func', transmanmask_mc, 'in.ref_func')

    #  |\/| _ _|_. _  _    _ _  _ _ _  __|_. _  _
    #  |  |(_) | |(_)| |  (_(_)| | (/_(_ | |(_)| |
    #
    # Perform motion correction, using some pipeline
    # --------------------------------------------------------

    # Register an image from the functionals to the reference image
    median_func = pe.MapNode(
        interface=fsl.maths.MedianImage(dimension="T"),
        name='median_func',
        iterfield=('in_file'),
    )
    #     pre_mc = motioncorrection_workflow.create_workflow_allin_slices(
    #         name='premotioncorrection')

    pre_mc = create_workflow_allin_slices(name='premotioncorrection')

    featpreproc.connect([
        (inputnode, median_func, [
            ('funcs', 'in_file'),
        ]),
        (median_func, pre_mc, [
            ('out_file', 'in.funcs'),
        ]),
        (
            inputfiles,
            pre_mc,
            [
                # median func image will be used a reference / base
                ('ref_func', 'in.ref_func'),
                ('ref_funcmask', 'in.ref_func_weights'),
            ]),
        (
            transmanmask_mc,
            pre_mc,
            [
                ('funcreg.out_file', 'in.funcs_masks'
                 ),  # use mask as weights >>>> are we sure this is correct?
            ]),
        (pre_mc, outputnode, [
            ('mc.out_file', 'pre_motion_corrected'),
            ('mc.oned_file', 'pre_motion_parameters.oned_file'),
            ('mc.oned_matrix_save', 'pre_motion_parameters.oned_matrix_save'),
        ]),
        (
            outputnode,
            outputfiles,
            [
                ('pre_motion_corrected', 'pre_motion_corrected.out_file'),
                ('pre_motion_parameters.oned_file',
                 'pre_motion_corrected.oned_file'),
                # warp parameters in ASCII (.1D)
                ('pre_motion_parameters.oned_matrix_save',
                 'pre_motion_corrected.oned_matrix_save'),
                # transformation matrices for each sub-brick
            ]),
    ])

    #     mc = motioncorrection_workflow.create_workflow_allin_slices(
    #         name='motioncorrection',
    #         iterfield=('in_file', 'ref_file', 'in_weight_file'))

    mc = create_workflow_allin_slices(name='motioncorrection',
                                      iterfield=('in_file', 'ref_file',
                                                 'in_weight_file'))

    # - - - - - - Connections - - - - - - -
    featpreproc.connect([
        (inputnode, mc, [
            ('funcs', 'in.funcs'),
        ]),
        (
            pre_mc,
            mc,
            [
                # the median image realigned to the reference functional
                # will serve as reference. This way motion correction is
                #  done to an image more similar to the functionals
                ('mc.out_file', 'in.ref_func'),
            ]),
        (
            inputfiles,
            mc,
            [
                # Check and make sure the ref func mask is close enough
                # to the registered median image.
                ('ref_funcmask', 'in.ref_func_weights'),
            ]),
        (
            transmanmask_mc,
            mc,
            [
                ('funcreg.out_file', 'in.funcs_masks'),  # use mask as weights
            ]),
        (mc, outputnode, [
            ('mc.out_file', 'motion_corrected'),
            ('mc.oned_file', 'motion_parameters.oned_file'),
            ('mc.oned_matrix_save', 'motion_parameters.oned_matrix_save'),
        ]),
        (
            outputnode,
            outputfiles,
            [
                ('motion_corrected', 'motion_corrected.out_file'),
                ('motion_parameters.oned_file', 'motion_corrected.oned_file'),
                # warp parameters in ASCII (.1D)
                ('motion_parameters.oned_matrix_save',
                 'motion_corrected.oned_matrix_save'),
                # transformation matrices for each sub-brick
            ]),
    ])

    #  |~. _ | _| _ _  _  _    _ _  _ _ _  __|_. _  _
    #  |~|(/_|(_|| | |(_||_)  (_(_)| | (/_(_ | |(_)| |
    #                    |
    # Unwarp EPI distortions
    # --------------------------------------------------------

    # Performing motion correction to a reference that is undistorted,
    # So b0_unwarp is currently not needed or used.

    # we have moved this to a separate workflow and use the blip-up/down
    # method now (reverse phase-encoding directions). This has also been
    # done for the new reference images.

    featpreproc.connect([
        (inputfiles, outputfiles, [
            ('ref_func', 'reference/func'),
            ('ref_funcmask', 'reference/func_mask'),
        ]),
        (inputfiles, outputnode, [
            ('ref_func', 'ref_func'),
            ('ref_funcmask', 'ref_funcmask'),
        ]),
    ])

    #  |\/| _ _|_. _  _    _   _|_|. _  _ _
    #  |  |(_) | |(_)| |  (_)|_|| ||(/_| _\
    #
    # --------------------------------------------------------

    # Apply brain masks to functionals
    # --------------------------------------------------------

    # Dilate mask
    dilatemask = pe.Node(interface=fsl.ImageMaths(suffix='_dil',
                                                  op_string='-dilF'),
                         name='dilatemask')
    featpreproc.connect(inputfiles, 'ref_funcmask', dilatemask, 'in_file')
    featpreproc.connect(dilatemask, 'out_file', outputfiles, 'dilate_mask')

    funcbrains = pe.MapNode(fsl.BinaryMaths(operation='mul'),
                            iterfield=('in_file', 'operand_file'),
                            name='funcbrains')

    featpreproc.connect([
        (mc, funcbrains, [
            ('mc.out_file', 'in_file'),
        ]),
        (dilatemask, funcbrains, [
            ('out_file', 'operand_file'),
        ]),
        (funcbrains, outputfiles, [
            ('out_file', 'funcbrains'),
        ]),
    ])
    # Detect motion outliers
    # --------------------------------------------------------

    import nipype.algorithms.rapidart as ra
    outliers = pe.MapNode(
        ra.ArtifactDetect(
            mask_type='file',
            use_norm=True,
            norm_threshold=10.0,  # combines translations in mm and rotations
            zintensity_threshold=3.0,  # z-score
            parameter_source='AFNI',
            save_plot=True),
        iterfield=('realigned_files', 'realignment_parameters', 'mask_file'),
        name='outliers')

    featpreproc.connect([
        (
            mc,
            outliers,
            [  # ('mc.par_file', 'realignment_parameters'),
                ('mc.oned_file', 'realignment_parameters'),
            ]),
        (funcbrains, outliers, [
            ('out_file', 'realigned_files'),
        ]),
        (dilatemask, outliers, [
            ('out_file', 'mask_file'),
        ]),
        (
            outliers,
            outputfiles,
            [
                ('outlier_files', 'motion_outliers.@outlier_files'),
                ('plot_files', 'motion_outliers.@plot_files'),
                ('displacement_files', 'motion_outliers.@displacement_files'),
                ('intensity_files', 'motion_outliers.@intensity_files'),
                ('mask_files', 'motion_outliers.@mask_files'),
                ('statistic_files', 'motion_outliers.@statistic_files'),
                # ('norm_files', 'outliers.@norm_files'),
            ]),
        (mc, outputnode, [
            ('mc.oned_file', 'motion_parameters'),
        ]),
        (
            outliers,
            outputnode,
            [
                ('outlier_files', 'motion_outlier_files'),
                ('plot_files', 'motion_plots.@plot_files'),
                ('displacement_files', 'motion_outliers.@displacement_files'),
                ('intensity_files', 'motion_outliers.@intensity_files'),
                ('mask_files', 'motion_outliers.@mask_files'),
                ('statistic_files', 'motion_outliers.@statistic_files'),
                # ('norm_files', 'outliers.@norm_files'),
            ])
    ])
    """
    Determine the 2nd and 98th percentile intensities of each functional run
    """
    getthresh = pe.MapNode(interface=fsl.ImageStats(op_string='-p 2 -p 98'),
                           iterfield=['in_file'],
                           name='getthreshold')

    featpreproc.connect(mc, 'mc.out_file', getthresh, 'in_file')
    """
    Threshold the first run of functional data at 10% of the 98th percentile
    """

    threshold = pe.MapNode(interface=fsl.ImageMaths(out_data_type='char',
                                                    suffix='_thresh'),
                           iterfield=['in_file', 'op_string'],
                           name='threshold')

    featpreproc.connect(mc, 'mc.out_file', threshold, 'in_file')
    """
    Define a function to get 10% of the intensity
    """
    def getthreshop(thresh):
        return ['-thr %.10f -Tmin -bin' % (0.1 * val[1]) for val in thresh]

    featpreproc.connect(getthresh, ('out_stat', getthreshop), threshold,
                        'op_string')
    """
    Determine the median value of the functional runs using the mask
    """
    medianval = pe.MapNode(interface=fsl.ImageStats(op_string='-k %s -p 50'),
                           iterfield=['in_file', 'mask_file'],
                           name='medianval')

    featpreproc.connect(mc, 'mc.out_file', medianval, 'in_file')
    featpreproc.connect(threshold, 'out_file', medianval, 'mask_file')

    # (~ _  _ _|_. _ |  (~ _ _  _  _ _|_|_ . _  _
    # _)|_)(_| | |(_||  _)| | |(_)(_) | | ||| |(_|
    #   |                                       _|
    # Spatial smoothing (SUSAN)
    # --------------------------------------------------------

    # create_susan_smooth takes care of calculating the mean and median
    #   functional, applying mask to functional, and running the smoothing
    smooth = create_susan_smooth(separate_masks=False)

    featpreproc.connect(inputnode, 'fwhm', smooth, 'inputnode.fwhm')

    featpreproc.connect(mc, 'mc.out_file', smooth, 'inputnode.in_files')

    featpreproc.connect(dilatemask, 'out_file', smooth, 'inputnode.mask_file')

    # -------------------------------------------------------
    # The below is from workflows/fmri/fsl/preprocess.py
    """
    Mask the smoothed data with the dilated mask
    """

    maskfunc3 = pe.MapNode(interface=fsl.ImageMaths(suffix='_mask',
                                                    op_string='-mas'),
                           iterfield=['in_file', 'in_file2'],
                           name='maskfunc3')
    featpreproc.connect(smooth, 'outputnode.smoothed_files', maskfunc3,
                        'in_file')

    featpreproc.connect(dilatemask, 'out_file', maskfunc3, 'in_file2')

    concatnode = pe.Node(interface=util.Merge(2), name='concat')

    tolist = lambda x: [x]

    def chooseindex(fwhm):
        if fwhm < 1:
            return [0]
        else:
            return [1]

    # maskfunc2 is the functional data before SUSAN
    featpreproc.connect(mc, ('mc.out_file', tolist), concatnode, 'in1')

    # maskfunc3 is the functional data after SUSAN
    featpreproc.connect(maskfunc3, ('out_file', tolist), concatnode, 'in2')
    """
    The following nodes select smooth or unsmoothed data depending on the
    fwhm. This is because SUSAN defaults to smoothing the data with about the
    voxel size of the input data if the fwhm parameter is less than 1/3 of the
    voxel size.
    """
    selectnode = pe.Node(interface=util.Select(), name='select')

    featpreproc.connect(concatnode, 'out', selectnode, 'inlist')

    featpreproc.connect(inputnode, ('fwhm', chooseindex), selectnode, 'index')
    featpreproc.connect(selectnode, 'out', outputfiles, 'smoothed_files')
    """
    Scale the median value of the run is set to 10000.
    """

    meanscale = pe.MapNode(interface=fsl.ImageMaths(suffix='_gms'),
                           iterfield=['in_file', 'op_string'],
                           name='meanscale')
    featpreproc.connect(selectnode, 'out', meanscale, 'in_file')
    """
    Define a function to get the scaling factor for intensity normalization
    """

    featpreproc.connect(medianval, ('out_stat', getmeanscale), meanscale,
                        'op_string')

    # |_|. _ |_  _  _  _ _
    # | ||(_|| ||_)(_|_\_\
    #      _|   |
    # Temporal filtering
    # --------------------------------------------------------

    highpass = pe.MapNode(interface=fsl.ImageMaths(suffix='_tempfilt'),
                          iterfield=['in_file'],
                          name='highpass')
    highpass_operand = lambda x: '-bptf %.10f -1' % x
    featpreproc.connect(inputnode, ('highpass', highpass_operand), highpass,
                        'op_string')
    featpreproc.connect(meanscale, 'out_file', highpass, 'in_file')

    version = 0
    if fsl.Info.version() and \
            LooseVersion(fsl.Info.version()) > LooseVersion('5.0.6'):
        version = 507

    if version < 507:
        featpreproc.connect(highpass, 'out_file', outputnode,
                            'highpassed_files')
    else:
        """
        Add back the mean removed by the highpass filter operation as
            of FSL 5.0.7
        """
        meanfunc4 = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                        suffix='_mean'),
                               iterfield=['in_file'],
                               name='meanfunc4')

        featpreproc.connect(meanscale, 'out_file', meanfunc4, 'in_file')
        addmean = pe.MapNode(interface=fsl.BinaryMaths(operation='add'),
                             iterfield=['in_file', 'operand_file'],
                             name='addmean')
        featpreproc.connect(highpass, 'out_file', addmean, 'in_file')
        featpreproc.connect(meanfunc4, 'out_file', addmean, 'operand_file')
        featpreproc.connect(addmean, 'out_file', outputnode,
                            'highpassed_files')
    """
    Generate a mean functional image from the first run
    """
    meanfunc3 = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                    suffix='_mean'),
                           iterfield=['in_file'],
                           name='meanfunc3')

    featpreproc.connect(meanscale, 'out_file', meanfunc3, 'in_file')
    featpreproc.connect(meanfunc3, 'out_file', outputfiles, 'mean')

    featpreproc.connect(meanfunc3, 'out_file', outputnode, 'mean_highpassed')
    featpreproc.connect(outputnode, 'highpassed_files', outputfiles,
                        'highpassed_files')

    return (featpreproc)