Example #1
0
def apply_all_corrections(name='UnwarpArtifacts'):
    """
    Combines two lists of linear transforms with the deformation field
    map obtained typically after the SDC process.
    Additionally, computes the corresponding bspline coefficients and
    the map of determinants of the jacobian.
    """

    inputnode = pe.Node(niu.IdentityInterface(fields=['in_sdc',
                        'in_hmc', 'in_ecc', 'in_dwi']), name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_warp',
                         'out_coeff', 'out_jacobian']), name='outputnode')
    warps = pe.MapNode(fsl.ConvertWarp(relwarp=True),
                       iterfield=['premat', 'postmat'],
                       name='ConvertWarp')

    selref = pe.Node(niu.Select(index=[0]), name='Reference')

    split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
    unwarp = pe.MapNode(fsl.ApplyWarp(), iterfield=['in_file', 'field_file'],
                        name='UnwarpDWIs')

    coeffs = pe.MapNode(fsl.WarpUtils(out_format='spline'),
                        iterfield=['in_file'], name='CoeffComp')
    jacobian = pe.MapNode(fsl.WarpUtils(write_jacobian=True),
                          iterfield=['in_file'], name='JacobianComp')
    jacmult = pe.MapNode(fsl.MultiImageMaths(op_string='-mul %s'),
                         iterfield=['in_file', 'operand_files'],
                         name='ModulateDWIs')

    thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'],
                       name='RemoveNegative')
    merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')

    wf = pe.Workflow(name=name)
    wf.connect([
        (inputnode,   warps,      [('in_sdc', 'warp1'),
                                   ('in_hmc', 'premat'),
                                   ('in_ecc', 'postmat'),
                                   ('in_dwi', 'reference')]),
        (inputnode,   split,      [('in_dwi', 'in_file')]),
        (split,       selref,     [('out_files', 'inlist')]),
        (warps,       unwarp,     [('out_file', 'field_file')]),
        (split,       unwarp,     [('out_files', 'in_file')]),
        (selref,      unwarp,     [('out', 'ref_file')]),
        (selref,      coeffs,     [('out', 'reference')]),
        (warps,       coeffs,     [('out_file', 'in_file')]),
        (selref,      jacobian,   [('out', 'reference')]),
        (coeffs,      jacobian,   [('out_file', 'in_file')]),
        (unwarp,      jacmult,    [('out_file', 'in_file')]),
        (jacobian,    jacmult,    [('out_jacobian', 'operand_files')]),
        (jacmult,     thres,      [('out_file', 'in_file')]),
        (thres,       merge,      [('out_file', 'in_files')]),
        (warps,       outputnode, [('out_file', 'out_warp')]),
        (coeffs,      outputnode, [('out_file', 'out_coeff')]),
        (jacobian,    outputnode, [('out_jacobian', 'out_jacobian')]),
        (merge,       outputnode, [('merged_file', 'out_file')])
    ])
    return wf
Example #2
0
def _gen_coeff(in_file, in_ref, in_movpar):
    """Convert to a valid fieldcoeff"""
    from shutil import copy
    import numpy as np
    import nibabel as nb
    from nipype.interfaces import fsl

    def _get_fname(in_file):
        import os.path as op
        fname, fext = op.splitext(op.basename(in_file))
        if fext == '.gz':
            fname, _ = op.splitext(fname)
        return op.abspath(fname)

    out_topup = _get_fname(in_file)

    # 1. Add one dimension (4D image) of 3D coordinates
    im0 = nb.load(in_file)
    data = np.zeros_like(im0.get_data())
    sizes = data.shape[:3]
    spacings = im0.get_header().get_zooms()[:3]
    im1 = nb.Nifti1Image(data, im0.get_affine(), im0.get_header())
    im4d = nb.concat_images([im0, im1, im1])
    im4d_fname = '{}_{}'.format(out_topup, 'field4D.nii.gz')
    im4d.to_filename(im4d_fname)

    # 2. Warputils to compute bspline coefficients
    to_coeff = fsl.WarpUtils(out_format='spline', knot_space=(2, 2, 2))
    to_coeff.inputs.in_file = im4d_fname
    to_coeff.inputs.reference = in_ref

    # 3. Remove unnecessary dims (Y and Z)
    get_first = fsl.ExtractROI(t_min=0, t_size=1)
    get_first.inputs.in_file = to_coeff.run().outputs.out_file

    # 4. Set correct header
    # see https://github.com/poldracklab/preprocessing-workflow/issues/92
    img = nb.load(get_first.run().outputs.roi_file)
    hdr = img.get_header().copy()
    hdr['intent_p1'] = spacings[0]
    hdr['intent_p2'] = spacings[1]
    hdr['intent_p3'] = spacings[2]
    hdr['intent_code'] = 2016

    sform = np.eye(4)
    sform[:3, 3] = sizes
    hdr.set_sform(sform, code='scanner')
    hdr['qform_code'] = 1

    # For some reason, MCFLIRT's parameters
    # are not compatible, fill with zeroes for now
    mpar = np.loadtxt(in_movpar)
    out_movpar = '{}_movpar.txt'.format(out_topup)
    np.savetxt(out_movpar, np.zeros_like(mpar))
    #copy(in_movpar, out_movpar)
    out_fieldcoef = '{}_fieldcoef.nii.gz'.format(out_topup)
    nb.Nifti1Image(img.get_data(), None, hdr).to_filename(out_fieldcoef)

    return out_fieldcoef, out_movpar
Example #3
0
def process_vsm(name='VSM2DFM'):
    """
    A workflow that computes the inverse and the determinant of jacobians
    map
    """
    inputnode = pe.Node(niu.IdentityInterface(
        fields=['vsm', 'reference', 'scaling', 'enc_dir']),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['dfm', 'inv_dfm', 'jacobian', 'inv_jacobian']),
                         name='outputnode')

    vsm2dfm = nwu.vsm2warp()
    invwarp = pe.Node(fsl.InvWarp(relative=True), name='InvWarp')
    coeffs = pe.Node(fsl.WarpUtils(out_format='spline'), name='CoeffComp')
    jacobian = pe.Node(fsl.WarpUtils(write_jacobian=True), name='JacobianComp')
    invcoef = pe.Node(fsl.WarpUtils(out_format='spline'), name='InvCoeffComp')
    invjac = pe.Node(fsl.WarpUtils(write_jacobian=True),
                     name='InvJacobianComp')
    wf = pe.Workflow(name=name)
    wf.connect([(inputnode, vsm2dfm, [('reference', 'inputnode.in_ref'),
                                      ('enc_dir', 'inputnode.enc_dir'),
                                      ('vsm', 'inputnode.in_vsm'),
                                      ('scaling', 'inputnode.scaling')]),
                (vsm2dfm, invwarp, [('outputnode.out_warp', 'warp')]),
                (inputnode, invwarp, [('reference', 'reference')]),
                (vsm2dfm, coeffs, [('outputnode.out_warp', 'in_file')]),
                (inputnode, coeffs, [('reference', 'reference')]),
                (inputnode, jacobian, [('reference', 'reference')]),
                (coeffs, jacobian, [('out_file', 'in_file')]),
                (vsm2dfm, outputnode, [('outputnode.out_warp', 'dfm')]),
                (invwarp, outputnode, [('inverse_warp', 'inv_dfm')]),
                (jacobian, outputnode, [('out_jacobian', 'jacobian')]),
                (invwarp, invcoef, [('inverse_warp', 'in_file')]),
                (inputnode, invcoef, [('reference', 'reference')]),
                (inputnode, invjac, [('reference', 'reference')]),
                (invcoef, invjac, [('out_file', 'in_file')]),
                (invjac, outputnode, [('out_jacobian', 'inv_jacobian')])])
    return wf
def apply_all_corrections_using_ants(name='UnwarpArtifacts'):
    """
    Combines two lists of linear transforms with the deformation field
    map obtained epi_correction by Ants.
    Additionally, computes the corresponding bspline coefficients and
    the map of determinants of the jacobian.
    """
    import nipype.interfaces.fsl as fsl
    import nipype.interfaces.utility as niu
    import nipype.pipeline.engine as pe

    inputnode = pe.Node(niu.IdentityInterface(
        fields=['in_sdc_syb', 'in_hmc', 'in_ecc', 'in_dwi', 'in_t1']),
        name='inputnode')

    outputnode = pe.Node(niu.IdentityInterface(
        fields=['out_file', 'out_warp', 'out_coeff', 'out_jacobian']),
        name='outputnode')

    split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')

    concat_hmc_ecc = pe.MapNode(fsl.ConvertXFM(), name="concat_hmc_ecc",
                                iterfield=['in_file', 'in_file2'])
    concat_hmc_ecc.inputs.concat_xfm = True

    warps = pe.MapNode(fsl.ConvertWarp(), iterfield=['premat'],
                       name='ConvertWarp')

    unwarp = pe.MapNode(interface=fsl.ApplyWarp(),
                        iterfield=['in_file', 'field_file'],
                        name='unwarp_warp')
    unwarp.inputs.interp = 'spline'

    coeffs = pe.MapNode(fsl.WarpUtils(out_format='spline'),
                        iterfield=['in_file'], name='CoeffComp')
    jacobian = pe.MapNode(fsl.WarpUtils(write_jacobian=True),
                          iterfield=['in_file'], name='JacobianComp')
    jacmult = pe.MapNode(fsl.MultiImageMaths(op_string='-mul %s'),
                         iterfield=['in_file', 'operand_files'],
                         name='ModulateDWIs')

    thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'],
                       name='RemoveNegative')
    merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')

    wf = pe.Workflow(name=name)
    wf.connect([
        (inputnode, concat_hmc_ecc, [('in_ecc', 'in_file2')]),  # noqa
        (inputnode, concat_hmc_ecc, [('in_hmc', 'in_file')]),  # noqa

        (concat_hmc_ecc, warps, [('out_file',            'premat')]),  # noqa
        (inputnode,      warps, [('in_sdc_syb',           'warp1')]),  # noqa
        (inputnode,      warps, [('in_t1',            'reference')]),  # noqa
        (inputnode,      split, [('in_dwi',             'in_file')]),  # noqa
        (warps,         unwarp, [('out_file',        'field_file')]),  # noqa
        (split,         unwarp, [('out_files',          'in_file')]),  # noqa
        (inputnode,     unwarp, [('in_t1',             'ref_file')]),  # noqa
        (inputnode,     coeffs, [('in_t1',            'reference')]),  # noqa
        (warps,         coeffs, [('out_file',           'in_file')]),  # noqa
        (inputnode,   jacobian, [('in_t1',            'reference')]),  # noqa
        (coeffs,      jacobian, [('out_file',           'in_file')]),  # noqa
        (unwarp,       jacmult, [('out_file',           'in_file')]),  # noqa
        (jacobian,     jacmult, [('out_jacobian', 'operand_files')]),  # noqa
        (jacmult,        thres, [('out_file',           'in_file')]),  # noqa
        (thres,          merge, [('out_file',          'in_files')]),  # noqa
        (warps,     outputnode, [('out_file',          'out_warp')]),  # noqa
        (coeffs,    outputnode, [('out_file',         'out_coeff')]),  # noqa
        (jacobian,  outputnode, [('out_jacobian',  'out_jacobian')]),  # noqa
        (merge,     outputnode, [('merged_file',        'out_file')])  # noqa
    ])

    return wf
def susceptibility_distortion_correction_using_t1(
        name='susceptibility_distortion_correction_using_t1'):
    """
    Susceptibility distortion correction using the T1w image.

    This workflow allows to correct for echo-planar induced susceptibility
    artifacts without fieldmap (e.g. ADNI Database) by elastically register
    DWIs to their respective baseline T1-weighted structural scans using an
    inverse consistent registration algorithm with a mutual information cost
    function (SyN algorithm).

    Args:
        name (Optional[str]): Name of the workflow.

    Inputnode:
        in_t1 (str): T1w image.
        in_dwi (str): DWI dataset

    Outputnode:
        out_dwi (str): Corrected DWI dataset
        out_warp (str): Out warp allowing DWI to T1 registration and
            susceptibilty induced artifacts correction
        out_b0_to_t1_rigid_body_matrix (str): B0 to T1 image FLIRT rigid body
            FSL coregistration matrix
        out_t1_to_b0_rigid_body_matrix (str): T1 to B0 image FLIRT rigid body
            FSL coregistration matrix
        out_t1_coregistered_to_b0 (str): T1 image rigid body coregistered to
            the B0 image
        out_b0_to_t1_syn_deformation_field (str): B0 to T1 image ANTs SyN
            ITK warp
        out_b0_to_t1_affine_matrix (str): B0 to T1 image ANTs affine ITK
            coregistration matrix

    References:
      .. Nir et al. (Neurobiology of Aging 2015): Connectivity network measures
        predict volumetric atrophy in mild cognitive impairment

      .. Leow et al. (IEEE Trans Med Imaging 2007): Statistical Properties of
        Jacobian Maps and the Realization of Unbiased Large Deformation
        Nonlinear Image Registration


    Returns:
        The workflow

    Example:
        >>> epi = susceptibility_distortion_correction_using_t1()
        >>> epi.inputs.inputnode.in_dwi = 'dwi.nii'
        >>> epi.inputs.inputnode.in_t1 = 'T1w.nii'
        >>> epi.run() # doctest: +SKIP
    """
    import nipype
    import nipype.pipeline.engine as pe
    import nipype.interfaces.utility as niu
    import nipype.interfaces.fsl as fsl
    import clinica.pipelines.dwi_preprocessing_using_t1.dwi_preprocessing_using_t1_utils as utils

    def expend_matrix_list(in_matrix, in_bvec):
        import numpy as np

        bvecs = np.loadtxt(in_bvec).T
        out_matrix_list = [in_matrix]

        out_matrix_list = out_matrix_list * len(bvecs)

        return out_matrix_list

    def rotate_bvecs(in_bvec, in_matrix):
        """
        Rotates the input bvec file accordingly with a list of matrices.
        .. note:: the input affine matrix transforms points in the destination
          image to their corresponding coordinates in the original image.
          Therefore, this matrix should be inverted first, as we want to know
          the target position of :math:`\\vec{r}`.
        """
        import os
        import numpy as np

        name, fext = os.path.splitext(os.path.basename(in_bvec))
        if fext == '.gz':
            name, _ = os.path.splitext(name)
        out_file = os.path.abspath('%s_rotated.bvec' % name)
        bvecs = np.loadtxt(
            in_bvec).T  # Warning, bvecs.txt are not in the good configuration, need to put '.T'
        new_bvecs = []

        if len(bvecs) != len(in_matrix):
            raise RuntimeError(('Number of b-vectors (%d) and rotation '
                                'matrices (%d) should match.') %
                               (len(bvecs), len(in_matrix)))

        for bvec, mat in zip(bvecs, in_matrix):
            if np.all(bvec == 0.0):
                new_bvecs.append(bvec)
            else:
                invrot = np.linalg.inv(np.loadtxt(mat))[:3, :3]
                newbvec = invrot.dot(bvec)
                new_bvecs.append((newbvec / np.linalg.norm(newbvec)))

        np.savetxt(out_file, np.array(new_bvecs).T, fmt='%0.15f')
        return out_file

    inputnode = pe.Node(
        niu.IdentityInterface(fields=['in_t1', 'in_dwi', 'in_bvec']),
        name='inputnode')

    split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
    pick_ref = pe.Node(niu.Select(), name='Pick_b0')
    pick_ref.inputs.index = [0]

    flirt_b0_to_t1 = pe.Node(interface=fsl.FLIRT(dof=6),
                            name='flirt_b0_to_t1')
    flirt_b0_to_t1.inputs.interp = "spline"
    flirt_b0_to_t1.inputs.cost = 'normmi'
    flirt_b0_to_t1.inputs.cost_func = 'normmi'

    if nipype.__version__.split('.') < ['0', '13', '0']:
        apply_xfm = pe.Node(interface=fsl.ApplyXfm(),
                            name='apply_xfm')
    else:
        apply_xfm = pe.Node(interface=fsl.ApplyXFM(),
                            name='apply_xfm')
    apply_xfm.inputs.apply_xfm = True

    expend_matrix = pe.Node(
        interface=niu.Function(input_names=['in_matrix', 'in_bvec'],
                               output_names=['out_matrix_list'],
                               function=expend_matrix_list),
        name='expend_matrix')

    rot_bvec = pe.Node(niu.Function(input_names=['in_matrix', 'in_bvec'],
                                    output_names=['out_file'],
                                    function=rotate_bvecs),
                       name='Rotate_Bvec')

    ants_registration_syn_quick = pe.Node(interface=niu.Function(
        input_names=['fix_image', 'moving_image'],
        output_names=['image_warped', 'affine_matrix',
                      'warp', 'inverse_warped', 'inverse_warp'],
        function=utils.ants_registration_syn_quick),
        name='ants_registration_syn_quick')

    merge_transform = pe.Node(niu.Merge(2), name='MergeTransforms')

    combine_warp = pe.Node(interface=niu.Function(
        input_names=['in_file', 'transforms_list', 'reference'],
        output_names=['out_warp'],
        function=utils.ants_combine_transform), name='combine_warp')

    coeffs = pe.Node(fsl.WarpUtils(out_format='spline'), name='CoeffComp')

    fsl_transf = pe.Node(fsl.WarpUtils(out_format='field'),
                         name='fsl_transf')

    warp_epi = pe.Node(fsl.ConvertWarp(), name='warp_epi')

    apply_warp = pe.MapNode(interface=fsl.ApplyWarp(),
                            iterfield=['in_file'], name='apply_warp')
    apply_warp.inputs.interp = 'spline'

    thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'],
                       name='RemoveNegative')

    merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')

    outputnode = pe.Node(niu.IdentityInterface(
        fields=['dwi_to_t1_coregistration_matrix',
                'itk_dwi_t1_coregistration_matrix',
                'epi_correction_deformation_field',
                'epi_correction_affine_transform',
                'merge_epi_transform', 'out_dwi', 'out_warp',
                'out_bvec']), name='outputnode')

    wf = pe.Workflow(name=name)

    wf.connect([
        (inputnode, split, [('in_dwi', 'in_file')]),  # noqa

        (split, pick_ref, [('out_files', 'inlist')]),  # noqa

        (pick_ref,  flirt_b0_to_t1, [('out',     'in_file')]),  # noqa
        (inputnode, flirt_b0_to_t1, [('in_t1', 'reference')]),  # noqa

        (flirt_b0_to_t1, expend_matrix, [('out_matrix_file', 'in_matrix')]),  # noqa
        (inputnode,      expend_matrix, [('in_bvec',           'in_bvec')]),  # noqa

        (inputnode,     rot_bvec, [('in_bvec', 'in_bvec')]),  # noqa
        (expend_matrix, rot_bvec, [('out_matrix_list', 'in_matrix')]),  # noqa
        
        (inputnode,                   ants_registration_syn_quick, [('in_t1',       'fix_image')]),  # noqa
        (flirt_b0_to_t1,              ants_registration_syn_quick, [('out_file', 'moving_image')]),  # noqa

        (ants_registration_syn_quick, merge_transform, [('affine_matrix', 'in2'),  # noqa
                                                        ('warp',          'in1')]),  # noqa

        (flirt_b0_to_t1,  combine_warp, [('out_file',    'in_file')]),  # noqa
        (merge_transform, combine_warp, [('out', 'transforms_list')]),  # noqa
        (inputnode,       combine_warp, [('in_t1',     'reference')]),  # noqa

        (inputnode,    coeffs, [('in_t1',  'reference')]),  # noqa
        (combine_warp, coeffs, [('out_warp', 'in_file')]),  # noqa

        (coeffs,    fsl_transf, [('out_file', 'in_file')]),  # noqa
        (inputnode, fsl_transf, [('in_t1',  'reference')]),  # noqa

        (inputnode,      warp_epi, [('in_t1',        'reference')]),  # noqa
        (flirt_b0_to_t1, warp_epi, [('out_matrix_file', 'premat')]),  # noqa
        (fsl_transf,     warp_epi, [('out_file',         'warp1')]),  # noqa

        (warp_epi,  apply_warp, [('out_file', 'field_file')]),  # noqa
        (split,     apply_warp, [('out_files',   'in_file')]),  # noqa
        (inputnode, apply_warp, [('in_t1',      'ref_file')]),  # noqa

        (apply_warp, thres, [('out_file', 'in_file')]),  # noqa

        (thres, merge, [('out_file', 'in_files')]),  # noqa
        # Outputnode
        (merge,                       outputnode, [('merged_file',                             'out_dwi')]),  # noqa
        (flirt_b0_to_t1,              outputnode, [('out_matrix_file', 'dwi_to_t1_coregistration_matrix')]),  # noqa
        (ants_registration_syn_quick, outputnode, [('warp',             'epi_correction_deformation_field'),  # noqa
                                                   ('affine_matrix',   'epi_correction_affine_transform')]),  # noqa
        (warp_epi,                    outputnode, [('out_file',                               'out_warp')]),  # noqa
        (rot_bvec,                    outputnode, [('out_file',                               'out_bvec')]),  # noqa
    ])
    return wf