Beispiel #1
0
def epi_mni_align(name='SpatialNormalization', ants_nthreads=6, testing=False, resolution=2):
    """
    Uses FSL FLIRT with the BBR cost function to find the transform that
    maps the EPI space into the MNI152-nonlinear-symmetric atlas.

    The input epi_mean is the averaged and brain-masked EPI timeseries

    Returns the EPI mean resampled in MNI space (for checking out registration) and
    the associated "lobe" parcellation in EPI space.

    """
    from nipype.interfaces.ants import ApplyTransforms, N4BiasFieldCorrection
    from niworkflows.data import get_mni_icbm152_nlin_asym_09c as get_template
    from niworkflows.interfaces.registration import RobustMNINormalizationRPT as RobustMNINormalization
    mni_template = get_template()

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=['epi_mean', 'epi_mask']),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['epi_mni', 'epi_parc', 'report']), name='outputnode')

    epimask = pe.Node(fsl.ApplyMask(), name='EPIApplyMask')

    n4itk = pe.Node(N4BiasFieldCorrection(dimension=3), name='SharpenEPI')
    # Mask T2 template image
    brainmask = pe.Node(fsl.ApplyMask(
        in_file=op.join(mni_template, '%dmm_T2.nii.gz' % resolution),
        mask_file=op.join(mni_template, '%dmm_brainmask.nii.gz' % resolution)),
        name='MNIApplyMask')

    norm = pe.Node(RobustMNINormalization(
        num_threads=ants_nthreads, template='mni_icbm152_nlin_asym_09c',
        testing=testing, moving='EPI', generate_report=True),
                   name='EPI2MNI')

    # Warp segmentation into EPI space
    invt = pe.Node(ApplyTransforms(
        input_image=op.join(mni_template, '%dmm_parc.nii.gz' % resolution),
        dimension=3, default_value=0, interpolation='NearestNeighbor'),
                   name='ResampleSegmentation')

    workflow.connect([
        (inputnode, invt, [('epi_mean', 'reference_image')]),
        (inputnode, n4itk, [('epi_mean', 'input_image')]),
        (inputnode, epimask, [('epi_mask', 'mask_file')]),
        (n4itk, epimask, [('output_image', 'in_file')]),
        (brainmask, norm, [('out_file', 'reference_image')]),
        (epimask, norm, [('out_file', 'moving_image')]),
        (norm, invt, [
            ('reverse_transforms', 'transforms'),
            ('reverse_invert_flags', 'invert_transform_flags')]),
        (invt, outputnode, [('output_image', 'epi_parc')]),
        (norm, outputnode, [('warped_image', 'epi_mni'),
                            ('out_report', 'report')]),

    ])
    return workflow
Beispiel #2
0
def spatial_normalization(settings,
                          mod='T1w',
                          name='SpatialNormalization',
                          resolution=2):
    """
    A simple workflow to perform spatial normalization

    """
    # Have some settings handy
    tpl_id = settings.get('template_id', 'MNI152NLin2009cAsym')

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(
        niu.IdentityInterface(fields=['moving_image', 'moving_mask']),
        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['inverse_composite_transform', 'out_report']),
                         name='outputnode')

    # Spatial normalization
    norm = pe.Node(
        RobustMNINormalization(
            flavor='testing' if settings.get('testing', False) else 'fast',
            num_threads=settings.get('ants_nthreads'),
            float=settings.get('ants_float', False),
            template=tpl_id,
            template_resolution=2,
            reference=mod,
            generate_report=True,
        ),
        name='SpatialNormalization',
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=min(
            settings.get('ants_nthreads', DEFAULTS['ants_nthreads']),
            settings.get('n_procs', 1)),
        mem_gb=3)
    norm.inputs.reference_mask = str(
        get_template(tpl_id,
                     resolution=resolution,
                     desc='brain',
                     suffix='mask'))

    workflow.connect([
        (inputnode, norm, [('moving_image', 'moving_image'),
                           ('moving_mask', 'moving_mask')]),
        (norm, outputnode, [('inverse_composite_transform',
                             'inverse_composite_transform'),
                            ('out_report', 'out_report')]),
    ])
    return workflow
Beispiel #3
0
def spatial_normalization(settings,
                          mod='T1w',
                          name='SpatialNormalization',
                          resolution=2.0):
    """
    A simple workflow to perform spatial normalization

    """
    from niworkflows.data import getters as niwgetters

    # Have some settings handy
    tpl_id = settings.get('template_id', 'mni_icbm152_nlin_asym_09c')
    mni_template = getattr(niwgetters, 'get_{}'.format(tpl_id))()

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(
        niu.IdentityInterface(fields=['moving_image', 'moving_mask']),
        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['inverse_composite_transform', 'out_report']),
                         name='outputnode')

    # Spatial normalization
    norm = pe.Node(
        RobustMNINormalization(
            flavor='testing' if settings.get('testing', False) else 'fast',
            num_threads=settings.get('ants_nthreads'),
            float=settings.get('ants_float', False),
            template=tpl_id,
            template_resolution=2,
            reference=mod[:2],
            generate_report=True,
        ),
        name='SpatialNormalization',
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=min(
            settings.get('ants_nthreads', DEFAULTS['ants_nthreads']),
            settings.get('n_procs', 1)),
        estimated_memory_gb=3)
    norm.inputs.reference_mask = op.join(
        mni_template, '%dmm_brainmask.nii.gz' % int(resolution))

    workflow.connect([
        (inputnode, norm, [('moving_image', 'moving_image'),
                           ('moving_mask', 'moving_mask')]),
        (norm, outputnode, [('inverse_composite_transform',
                             'inverse_composite_transform'),
                            ('out_report', 'out_report')]),
    ])
    return workflow
Beispiel #4
0
def spatial_normalization(name='SpatialNormalization', resolution=2):
    """Create a simplied workflow to perform fast spatial normalization."""
    from niworkflows.interfaces.registration import (RobustMNINormalizationRPT
                                                     as RobustMNINormalization)

    # Have the template id handy
    tpl_id = config.workflow.template_id

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(
        fields=['moving_image', 'moving_mask', 'modality']),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['inverse_composite_transform', 'out_report']),
                         name='outputnode')

    # Spatial normalization
    norm = pe.Node(
        RobustMNINormalization(
            flavor=['testing', 'fast'][config.execution.debug],
            num_threads=config.nipype.omp_nthreads,
            float=config.execution.ants_float,
            template=tpl_id,
            template_resolution=resolution,
            generate_report=True,
        ),
        name='SpatialNormalization',
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=config.nipype.omp_nthreads,
        mem_gb=3)
    norm.inputs.reference_mask = str(
        get_template(tpl_id,
                     resolution=resolution,
                     desc='brain',
                     suffix='mask'))

    workflow.connect([
        (inputnode, norm, [('moving_image', 'moving_image'),
                           ('moving_mask', 'moving_mask'),
                           ('modality', 'reference')]),
        (norm, outputnode, [('inverse_composite_transform',
                             'inverse_composite_transform'),
                            ('out_report', 'out_report')]),
    ])
    return workflow
Beispiel #5
0
def spatial_normalization(settings, mod='T1w', name='SpatialNormalization',
                          resolution=0.25):
    """
    A simple workflow to perform spatial normalization

    """
    # Have some settings handy
    tpl_id = settings.get('template_id', 'MNI152NLin2009cAsym')

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'moving_image', 'moving_mask']), name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=[
        'inverse_composite_transform', 'out_report']), name='outputnode')

    # Spatial normalization
    norm = pe.Node(RobustMNINormalization(
        flavor='testing' if settings.get('testing', False) else 'fast',
        num_threads=settings.get('ants_nthreads'),
        float=settings.get('ants_float', False),
        template=tpl_id,    ## CHNAGE IF THE TEMPLATE SETTINGS ARE DIFFERENT
        template_resolution=1,   ## CHNAGE IF THE TEMPLATE SETTINGS ARE DIFFERENT
        reference=mod,
        generate_report=True,),
        name='SpatialNormalization',
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=min(settings.get('ants_nthreads', DEFAULTS['ants_nthreads']),
                        settings.get('n_procs', 1)),
        mem_gb=3)
#    norm.inputs.reference_mask = str(
#        get_template(tpl_id, resolution=resolution, desc='brain', suffix='mask'))
#   CHANGE HERE #
    norm.inputs.reference_mask  = op.abspath('/mnt/MD1200B/egarza/arun/Datasets/MONKEY_MRIQC/MONKEY_MRIQC/brainmask_template_onemm.nii.gz')
    workflow.connect([
        (inputnode, norm, [('moving_image', 'moving_image'),
                           ('moving_mask', 'moving_mask')]),
        (norm, outputnode, [('inverse_composite_transform', 'inverse_composite_transform'),
                            ('out_report', 'out_report')]),
    ])
    return workflow
Beispiel #6
0
def anat_qc_workflow(dataset, settings, name='anatMRIQC'):
    """
    One-subject-one-session-one-run pipeline to extract the NR-IQMs from
    anatomical images
    """

    workflow = pe.Workflow(name=name)
    WFLOGGER.info(
        'Building anatomical MRI QC workflow, datasets list: %s',
        sorted([d.replace(settings['bids_dir'] + '/', '') for d in dataset]))

    # Define workflow, inputs and outputs
    # 0. Get data
    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']),
                        name='inputnode')
    inputnode.iterables = [('in_file', dataset)]

    outputnode = pe.Node(niu.IdentityInterface(fields=['out_json']),
                         name='outputnode')

    meta = pe.Node(ReadSidecarJSON(), name='metadata')

    # 1a. Reorient anatomical image
    to_ras = pe.Node(ConformImage(), name='conform')
    # 1b. Estimate bias
    n4itk = pe.Node(ants.N4BiasFieldCorrection(dimension=3, save_bias=True),
                    name='Bias')
    # 2. Skull-stripping (afni)
    asw = skullstrip_wf()
    # 3. Head mask (including nasial-cerebelum mask)
    hmsk = headmsk_wf()
    # 4. Spatial Normalization, using ANTs
    norm = pe.Node(RobustMNINormalization(
        num_threads=settings.get('ants_nthreads', 6),
        template='mni_icbm152_nlin_asym_09c',
        testing=settings.get('testing', False),
        generate_report=True),
                   name='SpatialNormalization')
    # 5. Air mask (with and without artifacts)
    amw = airmsk_wf()
    # 6. Brain tissue segmentation
    segment = pe.Node(fsl.FAST(img_type=1,
                               segments=True,
                               out_basename='segment'),
                      name='segmentation')
    # 7. Compute IQMs
    iqmswf = compute_iqms(settings)
    # Reports
    repwf = individual_reports(settings)

    # Connect all nodes
    workflow.connect([
        (inputnode, to_ras, [('in_file', 'in_file')]),
        (inputnode, meta, [('in_file', 'in_file')]),
        (to_ras, n4itk, [('out_file', 'input_image')]),
        (meta, iqmswf, [('subject_id', 'inputnode.subject_id'),
                        ('session_id', 'inputnode.session_id'),
                        ('run_id', 'inputnode.run_id')]),
        (n4itk, asw, [('output_image', 'inputnode.in_file')]),
        (asw, segment, [('outputnode.out_file', 'in_files')]),
        (n4itk, hmsk, [('output_image', 'inputnode.in_file')]),
        (segment, hmsk, [('tissue_class_map', 'inputnode.in_segm')]),
        (n4itk, norm, [('output_image', 'moving_image')]),
        (asw, norm, [('outputnode.out_mask', 'moving_mask')]),
        (to_ras, amw, [('out_file', 'inputnode.in_file')]),
        (norm, amw, [('reverse_transforms', 'inputnode.reverse_transforms'),
                     ('reverse_invert_flags', 'inputnode.reverse_invert_flags')
                     ]),
        (norm, iqmswf, [('reverse_transforms', 'inputnode.reverse_transforms'),
                        ('reverse_invert_flags',
                         'inputnode.reverse_invert_flags')]),
        (norm, repwf, ([('out_report', 'inputnode.mni_report')])),
        (asw, amw, [('outputnode.out_mask', 'inputnode.in_mask')]),
        (hmsk, amw, [('outputnode.out_file', 'inputnode.head_mask')]),
        (to_ras, iqmswf, [('out_file', 'inputnode.orig')]),
        (n4itk, iqmswf, [('output_image', 'inputnode.inu_corrected'),
                         ('bias_image', 'inputnode.in_inu')]),
        (asw, iqmswf, [('outputnode.out_mask', 'inputnode.brainmask')]),
        (amw, iqmswf, [('outputnode.out_file', 'inputnode.airmask'),
                       ('outputnode.artifact_msk', 'inputnode.artmask')]),
        (segment, iqmswf, [('tissue_class_map', 'inputnode.segmentation'),
                           ('partial_volume_files', 'inputnode.pvms')]),
        (meta, iqmswf, [('out_dict', 'inputnode.metadata')]),
        (hmsk, iqmswf, [('outputnode.out_file', 'inputnode.headmask')]),
        (to_ras, repwf, [('out_file', 'inputnode.orig')]),
        (n4itk, repwf, [('output_image', 'inputnode.inu_corrected')]),
        (asw, repwf, [('outputnode.out_mask', 'inputnode.brainmask')]),
        (hmsk, repwf, [('outputnode.out_file', 'inputnode.headmask')]),
        (amw, repwf, [('outputnode.out_file', 'inputnode.airmask'),
                      ('outputnode.artifact_msk', 'inputnode.artmask')]),
        (segment, repwf, [('tissue_class_map', 'inputnode.segmentation')]),
        (iqmswf, repwf, [('outputnode.out_noisefit', 'inputnode.noisefit')]),
        (iqmswf, repwf, [('outputnode.out_file', 'inputnode.in_iqms')]),
        (iqmswf, outputnode, [('outputnode.out_file', 'out_json')])
    ])

    return workflow
Beispiel #7
0
def epi_mni_align(name='SpatialNormalization'):
    """
    Estimate the transform that maps the EPI space into MNI152NLin2009cAsym.

    The input epi_mean is the averaged and brain-masked EPI timeseries

    Returns the EPI mean resampled in MNI space (for checking out registration) and
    the associated "lobe" parcellation in EPI space.

    .. workflow::

        from mriqc.workflows.functional import epi_mni_align
        from mriqc.testing import mock_config
        with mock_config():
            wf = epi_mni_align()

    """
    from nipype.interfaces.ants import ApplyTransforms, N4BiasFieldCorrection
    from templateflow.api import get as get_template
    from niworkflows.interfaces.registration import (RobustMNINormalizationRPT
                                                     as RobustMNINormalization)

    # Get settings
    testing = config.execution.debug
    n_procs = config.nipype.nprocs
    ants_nthreads = config.nipype.omp_nthreads

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=['epi_mean', 'epi_mask']),
                        name='inputnode')
    outputnode = pe.Node(
        niu.IdentityInterface(fields=['epi_mni', 'epi_parc', 'report']),
        name='outputnode')

    n4itk = pe.Node(N4BiasFieldCorrection(dimension=3, copy_header=True),
                    name='SharpenEPI')

    norm = pe.Node(RobustMNINormalization(
        explicit_masking=False,
        flavor='testing' if testing else 'precise',
        float=config.execution.ants_float,
        generate_report=True,
        moving='boldref',
        num_threads=ants_nthreads,
        reference='boldref',
        reference_image=str(
            get_template('MNI152NLin2009cAsym', resolution=2,
                         suffix='boldref')),
        reference_mask=str(
            get_template('MNI152NLin2009cAsym',
                         resolution=2,
                         desc='brain',
                         suffix='mask')),
        template='MNI152NLin2009cAsym',
        template_resolution=2,
    ),
                   name='EPI2MNI',
                   num_threads=n_procs,
                   mem_gb=3)

    # Warp segmentation into EPI space
    invt = pe.Node(ApplyTransforms(float=True,
                                   input_image=str(
                                       get_template('MNI152NLin2009cAsym',
                                                    resolution=1,
                                                    desc='carpet',
                                                    suffix='dseg')),
                                   dimension=3,
                                   default_value=0,
                                   interpolation='MultiLabel'),
                   name='ResampleSegmentation')

    workflow.connect([
        (inputnode, invt, [('epi_mean', 'reference_image')]),
        (inputnode, n4itk, [('epi_mean', 'input_image')]),
        (inputnode, norm, [('epi_mask', 'moving_mask')]),
        (n4itk, norm, [('output_image', 'moving_image')]),
        (norm, invt, [('inverse_composite_transform', 'transforms')]),
        (invt, outputnode, [('output_image', 'epi_parc')]),
        (norm, outputnode, [('warped_image', 'epi_mni'),
                            ('out_report', 'report')]),
    ])
    return workflow
Beispiel #8
0
def epi_mni_align(settings, name='SpatialNormalization'):
    """
    Uses FSL FLIRT with the BBR cost function to find the transform that
    maps the EPI space into the MNI152-nonlinear-symmetric atlas.

    The input epi_mean is the averaged and brain-masked EPI timeseries

    Returns the EPI mean resampled in MNI space (for checking out registration) and
    the associated "lobe" parcellation in EPI space.

    .. workflow::

      from mriqc.workflows.functional import epi_mni_align
      wf = epi_mni_align({})

    """
    from niworkflows.data import get_mni_icbm152_nlin_asym_09c as get_template
    from niworkflows.interfaces.registration import (RobustMNINormalizationRPT
                                                     as RobustMNINormalization)
    from pkg_resources import resource_filename as pkgrf

    # Get settings
    testing = settings.get('testing', False)
    n_procs = settings.get('n_procs', 1)
    ants_nthreads = settings.get('ants_nthreads', DEFAULTS['ants_nthreads'])

    # Init template
    mni_template = get_template()

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=['epi_mean', 'epi_mask']),
                        name='inputnode')
    outputnode = pe.Node(
        niu.IdentityInterface(fields=['epi_mni', 'epi_parc', 'report']),
        name='outputnode')

    epimask = pe.Node(fsl.ApplyMask(), name='EPIApplyMask')

    n4itk = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='SharpenEPI')

    norm = pe.Node(RobustMNINormalization(
        num_threads=ants_nthreads,
        float=settings.get('ants_float', False),
        template='mni_icbm152_nlin_asym_09c',
        reference_image=pkgrf('mriqc', 'data/mni/2mm_T2_brain.nii.gz'),
        flavor='testing' if testing else 'precise',
        moving='EPI',
        generate_report=True,
    ),
                   name='EPI2MNI',
                   num_threads=n_procs,
                   mem_gb=3)

    # Warp segmentation into EPI space
    invt = pe.Node(ants.ApplyTransforms(float=True,
                                        input_image=op.join(
                                            mni_template, '1mm_parc.nii.gz'),
                                        dimension=3,
                                        default_value=0,
                                        interpolation='NearestNeighbor'),
                   name='ResampleSegmentation')

    workflow.connect([
        (inputnode, invt, [('epi_mean', 'reference_image')]),
        (inputnode, n4itk, [('epi_mean', 'input_image')]),
        (inputnode, epimask, [('epi_mask', 'mask_file')]),
        (n4itk, epimask, [('output_image', 'in_file')]),
        (epimask, norm, [('out_file', 'moving_image')]),
        (norm, invt, [('inverse_composite_transform', 'transforms')]),
        (invt, outputnode, [('output_image', 'epi_parc')]),
        (norm, outputnode, [('warped_image', 'epi_mni'),
                            ('out_report', 'report')]),
    ])
    return workflow
Beispiel #9
0
def spatial_normalization(settings,
                          mod='T1w',
                          name='SpatialNormalization',
                          resolution=2.0):
    """
    A simple workflow to perform spatial normalization

    """
    from mriqc.interfaces.common import EnsureSize
    from nipype.interfaces.ants import AffineInitializer
    from niworkflows.data import getters as niwgetters

    # Have some settings handy
    tpl_id = settings.get('template_id', 'mni_icbm152_nlin_asym_09c')
    mni_template = getattr(niwgetters, 'get_{}'.format(tpl_id))()

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(
        niu.IdentityInterface(fields=['moving_image', 'moving_mask']),
        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['inverse_composite_transform', 'out_report']),
                         name='outputnode')

    # Mask inputs for initialization
    mmask = pe.Node(fsl.ApplyMask(), name='MovingApplyMask')
    fmask = pe.Node(fsl.ApplyMask(), name='FixedApplyMask')
    fmask.inputs.in_file = op.join(
        mni_template, '%dmm_%s.nii.gz' % (int(resolution), mod[:2]))
    fmask.inputs.mask_file = op.join(mni_template,
                                     '%dmm_brainmask.nii.gz' % int(resolution))

    # Ensure resolution
    resample = pe.Node(EnsureSize(pixel_size=resolution), 'EnsureSize')

    # Initializer
    init = pe.Node(
        AffineInitializer(num_threads=settings.get('ants_nthreads')),
        name='NormalizationInit')

    # Spatial normalization
    norm = pe.Node(
        RobustMNINormalization(
            flavor='testing' if settings.get('testing', False) else 'fast',
            num_threads=settings.get('ants_nthreads'),
            template=tpl_id,
            template_resolution=2,
            reference=mod[:2],
            generate_report=True,
        ),
        name='SpatialNormalization',
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=min(
            settings.get('ants_nthreads', DEFAULTS['ants_nthreads']),
            settings.get('n_procs', 1)),
        estimated_memory_gb=3)

    workflow.connect([
        (inputnode, resample, [('moving_image', 'in_file'),
                               ('moving_mask', 'in_mask')]),
        (resample, mmask, [('out_file', 'in_file'),
                           ('out_mask', 'mask_file')]),
        (mmask, init, [('out_file', 'moving_image')]),
        (fmask, init, [('out_file', 'fixed_image')]),
        (init, norm, [('out_file', 'initial_moving_transform')]),
        (resample, norm, [('out_file', 'moving_image'),
                          ('out_mask', 'moving_mask')]),
        (norm, outputnode, [('inverse_composite_transform',
                             'inverse_composite_transform'),
                            ('out_report', 'out_report')]),
    ])
    return workflow
Beispiel #10
0
def anat_qc_workflow(dataset, settings, mod='T1w', name='anatMRIQC'):
    """
    One-subject-one-session-one-run pipeline to extract the NR-IQMs from
    anatomical images

    .. workflow::

        import os.path as op
        from mriqc.workflows.anatomical import anat_qc_workflow
        datadir = op.abspath('data')
        wf = anat_qc_workflow([op.join(datadir, 'sub-001/anat/sub-001_T1w.nii.gz')],
                              settings={'bids_dir': datadir,
                                        'output_dir': op.abspath('out')})

    """

    workflow = pe.Workflow(name=name + mod)
    WFLOGGER.info(
        'Building anatomical MRI QC workflow, datasets list: %s',
        sorted([d.replace(settings['bids_dir'] + '/', '') for d in dataset]))

    # Define workflow, inputs and outputs
    # 0. Get data
    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']),
                        name='inputnode')
    inputnode.iterables = [('in_file', dataset)]

    outputnode = pe.Node(niu.IdentityInterface(fields=['out_json']),
                         name='outputnode')

    meta = pe.Node(ReadSidecarJSON(), name='metadata')

    # 1. Reorient anatomical image
    to_ras = pe.Node(ConformImage(), name='conform')
    # 2. Skull-stripping (afni)
    asw = skullstrip_wf()
    # 3. Head mask
    hmsk = headmsk_wf()
    # 4. Spatial Normalization, using ANTs
    norm = pe.Node(RobustMNINormalization(
        num_threads=settings.get('ants_nthreads', 6),
        template='mni_icbm152_nlin_asym_09c',
        testing=settings.get('testing', False),
        generate_report=True),
                   name='SpatialNormalization')
    norm.interface.num_threads = settings.get('ants_nthreads', 6)

    if mod == 'T1w':
        norm.inputs.reference = 'T1'
    elif mod == 'T2w':
        norm.inputs.reference = 'T2'

    # 5. Air mask (with and without artifacts)
    amw = airmsk_wf()
    # 6. Brain tissue segmentation
    segment = pe.Node(fsl.FAST(segments=True, out_basename='segment'),
                      name='segmentation')
    if mod == 'T1w':
        segment.inputs.img_type = 1
    elif mod == 'T2w':
        segment.inputs.img_type = 2
    # 7. Compute IQMs
    iqmswf = compute_iqms(settings, modality=mod)
    # Reports
    repwf = individual_reports(settings)

    # Connect all nodes
    workflow.connect([
        (inputnode, to_ras, [('in_file', 'in_file')]),
        (inputnode, meta, [('in_file', 'in_file')]),
        (meta, iqmswf, [('subject_id', 'inputnode.subject_id'),
                        ('session_id', 'inputnode.session_id'),
                        ('acq_id', 'inputnode.acq_id'),
                        ('rec_id', 'inputnode.rec_id'),
                        ('run_id', 'inputnode.run_id')]),
        (to_ras, asw, [('out_file', 'inputnode.in_file')]),
        (asw, segment, [('outputnode.out_file', 'in_files')]),
        (asw, hmsk, [('outputnode.bias_corrected', 'inputnode.in_file')]),
        (segment, hmsk, [('tissue_class_map', 'inputnode.in_segm')]),
        (asw, norm, [('outputnode.bias_corrected', 'moving_image'),
                     ('outputnode.out_mask', 'moving_mask')]),
        (to_ras, amw, [('out_file', 'inputnode.in_file')]),
        (norm, amw, [('inverse_composite_transform',
                      'inputnode.inverse_composite_transform')]),
        (norm, iqmswf, [('inverse_composite_transform',
                         'inputnode.inverse_composite_transform')]),
        (norm, repwf, ([('out_report', 'inputnode.mni_report')])),
        (asw, amw, [('outputnode.out_mask', 'inputnode.in_mask')]),
        (hmsk, amw, [('outputnode.out_file', 'inputnode.head_mask')]),
        (to_ras, iqmswf, [('out_file', 'inputnode.orig')]),
        (asw, iqmswf, [('outputnode.bias_corrected',
                        'inputnode.inu_corrected'),
                       ('outputnode.bias_image', 'inputnode.in_inu'),
                       ('outputnode.out_mask', 'inputnode.brainmask')]),
        (amw, iqmswf, [('outputnode.out_file', 'inputnode.airmask'),
                       ('outputnode.artifact_msk', 'inputnode.artmask')]),
        (segment, iqmswf, [('tissue_class_map', 'inputnode.segmentation'),
                           ('partial_volume_files', 'inputnode.pvms')]),
        (meta, iqmswf, [('out_dict', 'inputnode.metadata')]),
        (hmsk, iqmswf, [('outputnode.out_file', 'inputnode.headmask')]),
        (to_ras, repwf, [('out_file', 'inputnode.orig')]),
        (asw, repwf, [('outputnode.bias_corrected', 'inputnode.inu_corrected'),
                      ('outputnode.out_mask', 'inputnode.brainmask')]),
        (hmsk, repwf, [('outputnode.out_file', 'inputnode.headmask')]),
        (amw, repwf, [('outputnode.out_file', 'inputnode.airmask'),
                      ('outputnode.artifact_msk', 'inputnode.artmask')]),
        (segment, repwf, [('tissue_class_map', 'inputnode.segmentation')]),
        (iqmswf, repwf, [('outputnode.out_noisefit', 'inputnode.noisefit')]),
        (iqmswf, repwf, [('outputnode.out_file', 'inputnode.in_iqms')]),
        (iqmswf, outputnode, [('outputnode.out_file', 'out_json')])
    ])

    return workflow