Beispiel #1
0
def parse_spaces(opts):
    """Ensures the spaces are correctly parsed"""
    from sys import stderr
    from collections import OrderedDict
    from templateflow.api import templates as get_templates
    # Set the default template to 'MNI152NLin2009cAsym'
    output_spaces = opts.output_spaces or OrderedDict(
        [('MNI152NLin2009cAsym', {})])

    if opts.template:
        print("""\
The ``--template`` option has been deprecated in version 1.4.0. Your selected template \
"%s" will be inserted at the front of the ``--output-spaces`` argument list. Please update \
your scripts to use ``--output-spaces``.""" % opts.template,
              file=stderr)
        deprecated_tpl_arg = [(opts.template, {})]
        # If output_spaces is not set, just replate the default - append otherwise
        if opts.output_spaces is not None:
            deprecated_tpl_arg += list(output_spaces.items())
        output_spaces = OrderedDict(deprecated_tpl_arg)

    if opts.output_space:
        print("""\
The ``--output_space`` option has been deprecated in version 1.4.0. Your selection of spaces \
"%s" will be inserted at the front of the ``--output-spaces`` argument list. Please update \
your scripts to use ``--output-spaces``.""" % ', '.join(opts.output_space),
              file=stderr)
        missing = set(opts.output_space)
        if 'template' in missing:
            missing.remove('template')
            if not opts.template:
                missing.add('MNI152NLin2009cAsym')
        missing = missing - set(output_spaces.keys())
        output_spaces.update({tpl: {} for tpl in missing})

    FS_SPACES = set(['fsnative', 'fsaverage', 'fsaverage6', 'fsaverage5'])
    if opts.run_reconall and not list(
            FS_SPACES.intersection(output_spaces.keys())):
        print("""\
Although ``--fs-no-reconall`` was not set (i.e., FreeSurfer is to be run), no FreeSurfer \
output space (valid values are: %s) was selected. Adding default "fsaverage5" to the \
list of output spaces.""" % ', '.join(FS_SPACES),
              file=stderr)
        output_spaces['fsaverage5'] = {}

    # Validity of some inputs
    # ERROR check if use_aroma was specified, but the correct template was not
    if opts.use_aroma and 'MNI152NLin6Asym' not in output_spaces:
        output_spaces['MNI152NLin6Asym'] = {'res': 2}
        print("""\
Option "--use-aroma" requires functional images to be resampled to MNI152NLin6Asym space. \
The argument "MNI152NLin6Asym:res-2" has been automatically added to the list of output spaces \
(option ``--output-spaces``).""",
              file=stderr)

    if opts.cifti_output and 'MNI152NLin2009cAsym' not in output_spaces:
        if 'MNI152NLin2009cAsym' not in output_spaces:
            output_spaces['MNI152NLin2009cAsym'] = {'res': 2}
            print(
                """Option ``--cifti-output`` requires functional images to be resampled to \
``MNI152NLin2009cAsym`` space. Such template identifier has been automatically added to the \
list of output spaces (option "--output-space").""",
                file=stderr)
        if not [s for s in output_spaces if s in ('fsaverage5', 'fsaverage6')]:
            output_spaces['fsaverage5'] = {}
            print(
                """Option ``--cifti-output`` requires functional images to be resampled to \
``fsaverage`` space. The argument ``fsaverage:den-10k`` (a.k.a ``fsaverage5``) has been \
automatically added to the list of output spaces (option ``--output-space``).""",
                file=stderr)

    if opts.template_resampling_grid is not None:
        print(
            """Option ``--template-resampling-grid`` is deprecated, please specify \
resampling grid options as modifiers to templates listed in ``--output-spaces``. \
The configuration value will be applied to ALL output standard spaces.""")
        if opts.template_resampling_grid != 'native':
            for key in output_spaces.keys():
                if key in get_templates():
                    output_spaces[key]['res'] = opts.template_resampling_grid[
                        0]

    return output_spaces
Beispiel #2
0
def init_anat_norm_wf(
    debug,
    omp_nthreads,
    templates,
):
    """
    Build an individual spatial normalization workflow using ``antsRegistration``.

    .. workflow ::
        :graph2use: orig
        :simple_form: yes

        from smriprep.workflows.norm import init_anat_norm_wf
        wf = init_anat_norm_wf(
            debug=False,
            omp_nthreads=1,
            templates=[('MNI152NLin2009cAsym', {}), ('MNI152NLin6Asym', {})],
        )

    **Parameters**

        debug : bool
            Apply sloppy arguments to speed up processing. Use with caution,
            registration processes will be very inaccurate.
        omp_nthreads : int
            Maximum number of threads an individual process may use.
        templates : list of tuples
            List of tuples containing TemplateFlow identifiers (e.g. ``MNI152NLin6Asym``)
            and corresponding specs, which specify target templates
            for spatial normalization.

    **Inputs**

        moving_image
            The input image that will be normalized to standard space.
        moving_mask
            A precise brain mask separating skull/skin/fat from brain
            structures.
        moving_segmentation
            A brain tissue segmentation of the ``moving_image``.
        moving_tpms
            tissue probability maps (TPMs) corresponding to the
            ``moving_segmentation``.
        lesion_mask
            (optional) A mask to exclude regions from the cost-function
            input domain to enable standardization of lesioned brains.
        orig_t1w
            The original T1w image from the BIDS structure.

    **Outputs**

        standardized
            The T1w after spatial normalization, in template space.
        anat2std_xfm
            The T1w-to-template transform.
        std2anat_xfm
            The template-to-T1w transform.
        std_mask
            The ``moving_mask`` in template space (matches ``standardized`` output).
        std_dseg
            The ``moving_segmentation`` in template space (matches ``standardized``
            output).
        std_tpms
            The ``moving_tpms`` in template space (matches ``standardized`` output).
        template
            The input parameter ``template`` for further use in nodes depending
            on this
            workflow.

    """
    templateflow = get_templates()
    missing_tpls = [
        template for template, _ in templates if template not in templateflow
    ]
    if missing_tpls:
        raise ValueError("""\
One or more templates were not found (%s). Please make sure TemplateFlow is \
correctly installed and contains the given template identifiers.""" %
                         ', '.join(missing_tpls))

    ntpls = len(templates)
    workflow = Workflow('anat_norm_wf')
    workflow.__desc__ = """\
Volume-based spatial normalization to {targets} ({targets_id}) was performed through
nonlinear registration with `antsRegistration` (ANTs {ants_ver}),
using brain-extracted versions of both T1w reference and the T1w template.
The following template{tpls} selected for spatial normalization:
""".format(ants_ver=ANTsInfo.version() or '(version unknown)',
           targets='%s standard space%s' %
           (defaultdict('several'.format, {
               1: 'one',
               2: 'two',
               3: 'three',
               4: 'four'
           })[ntpls], 's' * (ntpls != 1)),
           targets_id=', '.join((t for t, _ in templates)),
           tpls=(' was', 's were')[ntpls != 1])

    # Append template citations to description
    for template, _ in templates:
        template_meta = get_metadata(template)
        template_refs = ['@%s' % template.lower()]

        if template_meta.get('RRID', None):
            template_refs += ['RRID:%s' % template_meta['RRID']]

        workflow.__desc__ += """\
*{template_name}* [{template_refs}; TemplateFlow ID: {template}]""".format(
            template=template,
            template_name=template_meta['Name'],
            template_refs=', '.join(template_refs))
        workflow.__desc__ += (', ', '.')[template == templates[-1][0]]

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'moving_image', 'moving_mask', 'moving_segmentation', 'moving_tpms',
        'lesion_mask', 'orig_t1w', 'template'
    ]),
                        name='inputnode')
    inputnode.iterables = [('template', templates)]
    out_fields = [
        'standardized', 'anat2std_xfm', 'std2anat_xfm', 'std_mask', 'std_dseg',
        'std_tpms', 'template'
    ]
    poutputnode = pe.Node(niu.IdentityInterface(fields=out_fields),
                          name='poutputnode')

    tf_select = pe.Node(TemplateFlowSelect(resolution=1 + debug),
                        name='tf_select',
                        run_without_submitting=True)

    # With the improvements from poldracklab/niworkflows#342 this truncation is now necessary
    trunc_mov = pe.Node(ImageMath(operation='TruncateImageIntensity',
                                  op2='0.01 0.999 256'),
                        name='trunc_mov')

    registration = pe.Node(RobustMNINormalization(
        float=True,
        flavor=['precise', 'testing'][debug],
    ),
                           name='registration',
                           n_procs=omp_nthreads,
                           mem_gb=2)

    # Resample T1w-space inputs
    tpl_moving = pe.Node(ApplyTransforms(dimension=3,
                                         default_value=0,
                                         float=True,
                                         interpolation='LanczosWindowedSinc'),
                         name='tpl_moving')
    std_mask = pe.Node(ApplyTransforms(dimension=3,
                                       default_value=0,
                                       float=True,
                                       interpolation='MultiLabel'),
                       name='std_mask')

    std_dseg = pe.Node(ApplyTransforms(dimension=3,
                                       default_value=0,
                                       float=True,
                                       interpolation='MultiLabel'),
                       name='std_dseg')

    std_tpms = pe.MapNode(ApplyTransforms(dimension=3,
                                          default_value=0,
                                          float=True,
                                          interpolation='Gaussian'),
                          iterfield=['input_image'],
                          name='std_tpms')

    workflow.connect([
        (inputnode, tf_select, [(('template', _get_name), 'template'),
                                (('template', _get_spec), 'template_spec')]),
        (inputnode, registration, [(('template', _get_name), 'template'),
                                   (('template', _get_spec), 'template_spec')
                                   ]),
        (inputnode, trunc_mov, [('moving_image', 'op1')]),
        (inputnode, registration, [('moving_mask', 'moving_mask'),
                                   ('lesion_mask', 'lesion_mask')]),
        (inputnode, tpl_moving, [('moving_image', 'input_image')]),
        (inputnode, std_mask, [('moving_mask', 'input_image')]),
        (tf_select, tpl_moving, [('t1w_file', 'reference_image')]),
        (tf_select, std_mask, [('t1w_file', 'reference_image')]),
        (tf_select, std_dseg, [('t1w_file', 'reference_image')]),
        (tf_select, std_tpms, [('t1w_file', 'reference_image')]),
        (trunc_mov, registration, [('output_image', 'moving_image')]),
        (registration, tpl_moving, [('composite_transform', 'transforms')]),
        (registration, std_mask, [('composite_transform', 'transforms')]),
        (inputnode, std_dseg, [('moving_segmentation', 'input_image')]),
        (registration, std_dseg, [('composite_transform', 'transforms')]),
        (inputnode, std_tpms, [('moving_tpms', 'input_image')]),
        (registration, std_tpms, [('composite_transform', 'transforms')]),
        (registration, poutputnode, [('composite_transform', 'anat2std_xfm'),
                                     ('inverse_composite_transform',
                                      'std2anat_xfm')]),
        (tpl_moving, poutputnode, [('output_image', 'standardized')]),
        (std_mask, poutputnode, [('output_image', 'std_mask')]),
        (std_dseg, poutputnode, [('output_image', 'std_dseg')]),
        (std_tpms, poutputnode, [('output_image', 'std_tpms')]),
        (inputnode, poutputnode, [('template', 'template')]),
    ])

    # Provide synchronized output
    outputnode = pe.JoinNode(niu.IdentityInterface(fields=out_fields),
                             name='outputnode',
                             joinsource='inputnode')
    workflow.connect([
        (poutputnode, outputnode, [(f, f) for f in out_fields]),
    ])

    return workflow