예제 #1
0
def init_phdiff_wf(omp_nthreads, name='phdiff_wf'):
    r"""
    Distortion correction of EPI sequences using phase-difference maps.

    Estimates the fieldmap using a phase-difference image and one or more
    magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)`
    acquisitions.
    The most delicate bit of this workflow is the phase-unwrapping process: phase maps
    are clipped in the range :math:`[0 \dotsb 2\pi )`.
    To find the integer number of offsets that make a region continously smooth with
    its neighbour, FSL PRELUDE is run [Jenkinson2003]_.
    FSL PRELUDE takes wrapped maps in the range 0 to 6.28, `as per the user guide
    <https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE/Guide#Step_2_-_Getting_.28wrapped.29_phase_in_radians>`__.
    For the phase-difference maps, recentering back to :math:`[-\pi \dotsb \pi )` is necessary.
    After some massaging and the application of the effective echo spacing parameter,
    the phase-difference maps can be converted into a *B0 field map* in Hz units.
    The `original code was taken from nipype
    <https://github.com/nipy/nipype/blob/0.12.1/nipype/workflows/dmri/fsl/artifacts.py#L514>`_.

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

            from sdcflows.workflows.phdiff import init_phdiff_wf
            wf = init_phdiff_wf(omp_nthreads=1)

    Parameters
    ----------
    omp_nthreads : int
        Maximum number of threads an individual process may use

    Inputs
    ------
    magnitude : list of os.pathlike
        List of path(s) the GRE magnitude maps.
    phasediff : list of tuple(os.pathlike, dict)
        List containing one GRE phase-difference map with its corresponding metadata
        (requires ``EchoTime1`` and ``EchoTime2``), or the phase maps for the two
        subsequent echoes, with their metadata (requires ``EchoTime``).

    Outputs
    -------
    fmap_ref : pathlike
        The average magnitude image, skull-stripped
    fmap_mask : pathlike
        The brain mask applied to the fieldmap
    fmap : pathlike
        The estimated fieldmap in Hz

    References
    ----------
    .. [Jenkinson2003] Jenkinson, M. (2003) Fast, automated, N-dimensional phase-unwrapping
        algorithm. MRM 49(1):193-197. doi:`10.1002/mrm.10354 <10.1002/mrm.10354>`__.

    """
    workflow = Workflow(name=name)
    workflow.__desc__ = """\
A B0-nonuniformity map (or *fieldmap*) was estimated based on a phase-difference map
calculated with a dual-echo GRE (gradient-recall echo) sequence, processed with a
custom workflow of *SDCFlows* inspired by the
[`epidewarp.fsl` script](http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl)
and further improvements in HCP Pipelines [@hcppipelines].
"""

    inputnode = pe.Node(niu.IdentityInterface(fields=['magnitude', 'phasediff']),
                        name='inputnode')

    outputnode = pe.Node(niu.IdentityInterface(
        fields=['fmap', 'fmap_ref', 'fmap_mask']), name='outputnode')

    split = pe.MapNode(niu.Function(function=_split, output_names=['map_file', 'meta']),
                       iterfield=['phasediff'], run_without_submitting=True, name='split')

    magnitude_wf = init_magnitude_wf(omp_nthreads=omp_nthreads)

    # phase diff -> radians
    phmap2rads = pe.MapNode(PhaseMap2rads(), name='phmap2rads',
                            iterfield=['in_file'], run_without_submitting=True)
    # FSL PRELUDE will perform phase-unwrapping
    prelude = pe.Node(fsl.PRELUDE(), name='prelude')

    calc_phdiff = pe.Node(SubtractPhases(), name='calc_phdiff',
                          run_without_submitting=True)

    fmap_postproc_wf = init_fmap_postproc_wf(omp_nthreads=omp_nthreads,
                                             fmap_bspline=False)
    compfmap = pe.Node(Phasediff2Fieldmap(), name='compfmap')

    workflow.connect([
        (inputnode, split, [('phasediff', 'phasediff')]),
        (inputnode, magnitude_wf, [('magnitude', 'inputnode.magnitude')]),
        (magnitude_wf, prelude, [('outputnode.fmap_ref', 'magnitude_file'),
                                 ('outputnode.fmap_mask', 'mask_file')]),
        (split, phmap2rads, [('map_file', 'in_file')]),
        (phmap2rads, calc_phdiff, [('out_file', 'in_phases')]),
        (split, calc_phdiff, [('meta', 'in_meta')]),
        (calc_phdiff, prelude, [('phase_diff', 'phase_file')]),
        (prelude, fmap_postproc_wf, [('unwrapped_phase_file', 'inputnode.fmap')]),
        (calc_phdiff, fmap_postproc_wf, [('metadata', 'inputnode.metadata')]),
        (magnitude_wf, fmap_postproc_wf, [
            ('outputnode.fmap_mask', 'inputnode.fmap_mask'),
            ('outputnode.fmap_ref', 'inputnode.fmap_ref')]),
        (fmap_postproc_wf, compfmap, [('outputnode.out_fmap', 'in_file'),
                                      ('outputnode.metadata', 'metadata')]),
        (compfmap, outputnode, [('out_file', 'fmap')]),
        (magnitude_wf, outputnode, [('outputnode.fmap_ref', 'fmap_ref'),
                                    ('outputnode.fmap_mask', 'fmap_mask')]),
    ])

    return workflow
예제 #2
0
def init_fmap_wf(omp_nthreads, fmap_bspline, name='fmap_wf'):
    """
    Fieldmap workflow - when we have a sequence that directly measures the fieldmap
    we just need to mask it (using the corresponding magnitude image) to remove the
    noise in the surrounding air region, and ensure that units are Hz.

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

        from fmriprep.workflows.fieldmap.fmap import init_fmap_wf
        wf = init_fmap_wf(omp_nthreads=6, fmap_bspline=False)

    """

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(
        niu.IdentityInterface(fields=['magnitude', 'fieldmap']),
        name='inputnode')
    outputnode = pe.Node(
        niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']),
        name='outputnode')

    # Merge input magnitude images
    magmrg = pe.Node(IntraModalMerge(), name='magmrg')
    # Merge input fieldmap images
    fmapmrg = pe.Node(IntraModalMerge(zero_based_avg=False, hmc=False),
                      name='fmapmrg')

    # de-gradient the fields ("bias/illumination artifact")
    n4_correct = pe.Node(ants.N4BiasFieldCorrection(dimension=3,
                                                    copy_header=True),
                         name='n4_correct',
                         n_procs=omp_nthreads)
    bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True),
                  name='bet')
    ds_fmap_mask = pe.Node(DerivativesDataSink(suffix='fmap_mask'),
                           name='ds_report_fmap_mask',
                           run_without_submitting=True)

    workflow.connect([
        (inputnode, magmrg, [('magnitude', 'in_files')]),
        (inputnode, fmapmrg, [('fieldmap', 'in_files')]),
        (magmrg, n4_correct, [('out_file', 'input_image')]),
        (n4_correct, bet, [('output_image', 'in_file')]),
        (bet, outputnode, [('mask_file', 'fmap_mask'),
                           ('out_file', 'fmap_ref')]),
        (inputnode, ds_fmap_mask, [('fieldmap', 'source_file')]),
        (bet, ds_fmap_mask, [('out_report', 'in_file')]),
    ])

    if fmap_bspline:
        # despike_threshold=1.0, mask_erode=1),
        fmapenh = pe.Node(FieldEnhance(unwrap=False, despike=False),
                          name='fmapenh',
                          mem_gb=4,
                          n_procs=omp_nthreads)

        workflow.connect([
            (bet, fmapenh, [('mask_file', 'in_mask'),
                            ('out_file', 'in_magnitude')]),
            (fmapmrg, fmapenh, [('out_file', 'in_file')]),
            (fmapenh, outputnode, [('out_file', 'fmap')]),
        ])

    else:
        torads = pe.Node(FieldToRadS(), name='torads')
        prelude = pe.Node(fsl.PRELUDE(), name='prelude')
        tohz = pe.Node(FieldToHz(), name='tohz')

        denoise = pe.Node(fsl.SpatialFilter(operation='median',
                                            kernel_shape='sphere',
                                            kernel_size=3),
                          name='denoise')
        demean = pe.Node(niu.Function(function=demean_image), name='demean')
        cleanup_wf = cleanup_edge_pipeline(name='cleanup_wf')

        applymsk = pe.Node(fsl.ApplyMask(), name='applymsk')

        workflow.connect([
            (bet, prelude, [('mask_file', 'mask_file'),
                            ('out_file', 'magnitude_file')]),
            (fmapmrg, torads, [('out_file', 'in_file')]),
            (torads, tohz, [('fmap_range', 'range_hz')]),
            (torads, prelude, [('out_file', 'phase_file')]),
            (prelude, tohz, [('unwrapped_phase_file', 'in_file')]),
            (tohz, denoise, [('out_file', 'in_file')]),
            (denoise, demean, [('out_file', 'in_file')]),
            (demean, cleanup_wf, [('out', 'inputnode.in_file')]),
            (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]),
            (cleanup_wf, applymsk, [('outputnode.out_file', 'in_file')]),
            (bet, applymsk, [('mask_file', 'mask_file')]),
            (applymsk, outputnode, [('out_file', 'fmap')]),
        ])

    return workflow
예제 #3
0
def sdc_fmb(name='fmb_correction',
            interp='Linear',
            fugue_params=dict(smooth3d=2.0)):
    """
    SDC stands for susceptibility distortion correction. FMB stands for
    fieldmap-based.

    The fieldmap based (FMB) method implements SDC by using a mapping of the
    B0 field as proposed by [Jezzard95]_. This workflow uses the implementation
    of FSL (`FUGUE <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE>`_). Phase
    unwrapping is performed using `PRELUDE
    <http://fsl.fmrib.ox.ac.uk/fsl/fsl-4.1.9/fugue/prelude.html>`_
    [Jenkinson03]_. Preparation of the fieldmap is performed reproducing the
    script in FSL `fsl_prepare_fieldmap
    <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE/Guide#SIEMENS_data>`_.



    Example
    -------

    >>> from nipype.workflows.dmri.fsl.artifacts import sdc_fmb
    >>> fmb = sdc_fmb()
    >>> fmb.inputs.inputnode.in_file = 'diffusion.nii'
    >>> fmb.inputs.inputnode.in_ref = list(range(0, 30, 6))
    >>> fmb.inputs.inputnode.in_mask = 'mask.nii'
    >>> fmb.inputs.inputnode.bmap_mag = 'magnitude.nii'
    >>> fmb.inputs.inputnode.bmap_pha = 'phase.nii'
    >>> fmb.inputs.inputnode.settings = 'epi_param.txt'
    >>> fmb.run() # doctest: +SKIP

    .. warning:: Only SIEMENS format fieldmaps are supported.

    .. admonition:: References

      .. [Jezzard95] Jezzard P, and Balaban RS, `Correction for geometric
        distortion in echo planar images from B0 field variations
        <https://doi.org/10.1002/mrm.1910340111>`_,
        MRM 34(1):65-73. (1995). doi: 10.1002/mrm.1910340111.

      .. [Jenkinson03] Jenkinson M., `Fast, automated, N-dimensional
        phase-unwrapping algorithm <https://doi.org/10.1002/mrm.10354>`_,
        MRM 49(1):193-197, 2003, doi: 10.1002/mrm.10354.

    """

    epi_defaults = {
        'delta_te': 2.46e-3,
        'echospacing': 0.77e-3,
        'acc_factor': 2,
        'enc_dir': u'AP'
    }

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_file', 'in_ref', 'in_mask', 'bmap_pha', 'bmap_mag', 'settings'
    ]),
                        name='inputnode')

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

    r_params = pe.Node(JSONFileGrabber(defaults=epi_defaults),
                       name='SettingsGrabber')
    eff_echo = pe.Node(niu.Function(function=_eff_t_echo,
                                    input_names=['echospacing', 'acc_factor'],
                                    output_names=['eff_echo']),
                       name='EffEcho')

    firstmag = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name='GetFirst')
    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='Bias')
    bet = pe.Node(fsl.BET(frac=0.4, mask=True), name='BrainExtraction')
    dilate = pe.Node(fsl.maths.MathsCommand(nan2zeros=True,
                                            args='-kernel sphere 5 -dilM'),
                     name='MskDilate')
    pha2rads = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_file'],
                                    function=siemens2rads),
                       name='PreparePhase')
    prelude = pe.Node(fsl.PRELUDE(process3d=True), name='PhaseUnwrap')
    rad2rsec = pe.Node(niu.Function(input_names=['in_file', 'delta_te'],
                                    output_names=['out_file'],
                                    function=rads2radsec),
                       name='ToRadSec')

    baseline = pe.Node(niu.Function(input_names=['in_file', 'index'],
                                    output_names=['out_file'],
                                    function=time_avg),
                       name='Baseline')

    fmm2b0 = pe.Node(ants.Registration(output_warped_image=True),
                     name="FMm_to_B0")
    fmm2b0.inputs.transforms = ['Rigid'] * 2
    fmm2b0.inputs.transform_parameters = [(1.0, )] * 2
    fmm2b0.inputs.number_of_iterations = [[50], [20]]
    fmm2b0.inputs.dimension = 3
    fmm2b0.inputs.metric = ['Mattes', 'Mattes']
    fmm2b0.inputs.metric_weight = [1.0] * 2
    fmm2b0.inputs.radius_or_number_of_bins = [64, 64]
    fmm2b0.inputs.sampling_strategy = ['Regular', 'Random']
    fmm2b0.inputs.sampling_percentage = [None, 0.2]
    fmm2b0.inputs.convergence_threshold = [1.e-5, 1.e-8]
    fmm2b0.inputs.convergence_window_size = [20, 10]
    fmm2b0.inputs.smoothing_sigmas = [[6.0], [2.0]]
    fmm2b0.inputs.sigma_units = ['vox'] * 2
    fmm2b0.inputs.shrink_factors = [[6], [1]]  # ,[1] ]
    fmm2b0.inputs.use_estimate_learning_rate_once = [True] * 2
    fmm2b0.inputs.use_histogram_matching = [True] * 2
    fmm2b0.inputs.initial_moving_transform_com = 0
    fmm2b0.inputs.collapse_output_transforms = True
    fmm2b0.inputs.winsorize_upper_quantile = 0.995

    applyxfm = pe.Node(ants.ApplyTransforms(dimension=3, interpolation=interp),
                       name='FMp_to_B0')

    pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='PreliminaryFugue')
    demean = pe.Node(niu.Function(input_names=['in_file', 'in_mask'],
                                  output_names=['out_file'],
                                  function=demean_image),
                     name='DemeanFmap')

    cleanup = cleanup_edge_pipeline()

    addvol = pe.Node(niu.Function(input_names=['in_file'],
                                  output_names=['out_file'],
                                  function=add_empty_vol),
                     name='AddEmptyVol')

    vsm = pe.Node(fsl.FUGUE(save_shift=True, **fugue_params),
                  name="ComputeVSM")

    split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
    merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')
    unwarp = pe.MapNode(fsl.FUGUE(icorr=True, forward_warping=False),
                        iterfield=['in_file'],
                        name='UnwarpDWIs')
    thres = pe.MapNode(fsl.Threshold(thresh=0.0),
                       iterfield=['in_file'],
                       name='RemoveNegative')
    vsm2dfm = vsm2warp()
    vsm2dfm.inputs.inputnode.scaling = 1.0

    wf = pe.Workflow(name=name)
    wf.connect([(inputnode, r_params, [('settings', 'in_file')]),
                (r_params, eff_echo, [('echospacing', 'echospacing'),
                                      ('acc_factor', 'acc_factor')]),
                (inputnode, pha2rads, [('bmap_pha', 'in_file')]),
                (inputnode, firstmag, [('bmap_mag', 'in_file')]),
                (inputnode, baseline, [('in_file', 'in_file'),
                                       ('in_ref', 'index')]),
                (firstmag, n4, [('roi_file', 'input_image')]),
                (n4, bet, [('output_image', 'in_file')]),
                (bet, dilate, [('mask_file', 'in_file')]),
                (pha2rads, prelude, [('out_file', 'phase_file')]),
                (n4, prelude, [('output_image', 'magnitude_file')]),
                (dilate, prelude, [('out_file', 'mask_file')]),
                (r_params, rad2rsec, [('delta_te', 'delta_te')]),
                (prelude, rad2rsec, [('unwrapped_phase_file', 'in_file')]),
                (baseline, fmm2b0, [('out_file', 'fixed_image')]),
                (n4, fmm2b0, [('output_image', 'moving_image')]),
                (inputnode, fmm2b0, [('in_mask', 'fixed_image_mask')]),
                (dilate, fmm2b0, [('out_file', 'moving_image_mask')]),
                (baseline, applyxfm, [('out_file', 'reference_image')]),
                (rad2rsec, applyxfm, [('out_file', 'input_image')]),
                (fmm2b0, applyxfm, [('forward_transforms', 'transforms'),
                                    ('forward_invert_flags',
                                     'invert_transform_flags')]),
                (applyxfm, pre_fugue, [('output_image', 'fmap_in_file')]),
                (inputnode, pre_fugue, [('in_mask', 'mask_file')]),
                (pre_fugue, demean, [('fmap_out_file', 'in_file')]),
                (inputnode, demean, [('in_mask', 'in_mask')]),
                (demean, cleanup, [('out_file', 'inputnode.in_file')]),
                (inputnode, cleanup, [('in_mask', 'inputnode.in_mask')]),
                (cleanup, addvol, [('outputnode.out_file', 'in_file')]),
                (inputnode, vsm, [('in_mask', 'mask_file')]),
                (addvol, vsm, [('out_file', 'fmap_in_file')]),
                (r_params, vsm, [('delta_te', 'asym_se_time')]),
                (eff_echo, vsm, [('eff_echo', 'dwell_time')]),
                (inputnode, split, [('in_file', 'in_file')]),
                (split, unwarp, [('out_files', 'in_file')]),
                (vsm, unwarp, [('shift_out_file', 'shift_in_file')]),
                (r_params, unwarp, [(('enc_dir', _fix_enc_dir),
                                     'unwarp_direction')]),
                (unwarp, thres, [('unwarped_file', 'in_file')]),
                (thres, merge, [('out_file', 'in_files')]),
                (r_params, vsm2dfm, [(('enc_dir',
                                       _fix_enc_dir), 'inputnode.enc_dir')]),
                (merge, vsm2dfm, [('merged_file', 'inputnode.in_ref')]),
                (vsm, vsm2dfm, [('shift_out_file', 'inputnode.in_vsm')]),
                (merge, outputnode, [('merged_file', 'out_file')]),
                (vsm, outputnode, [('shift_out_file', 'out_vsm')]),
                (vsm2dfm, outputnode, [('outputnode.out_warp', 'out_warp')])])
    return wf
# compute median of realigned timeseries for preperation for fieldmap

median1 = Node(util.Function(input_names=['in_files'],
                             output_names=['median_file'],
                             function=median),
               name='median1')

#median = Node(SpatialFilter(operation='median'),
#              name='median')

preproc.connect([(tsnr, median1, [('detrended_file', 'in_files')])])

#prelude phase unwrapping x 2

prelude1 = Node(fsl.PRELUDE(terminal_output='none'), name='prelude1')

preproc.connect([(selectfiles, prelude1, [('phase1', 'phase_file')]),
                 (brain_extract_mag1, prelude1, [('out_file', 'magnitude_file')
                                                 ])])

prelude2 = Node(fsl.PRELUDE(terminal_output='none'), name='prelude2')

preproc.connect([(selectfiles, prelude2, [('phase2', 'phase_file')]),
                 (brain_extract_mag1, prelude2, [('out_file', 'magnitude_file')
                                                 ])])

# Getting the fieldmap in rad/s ---- fusing phase images -sub -mul 1000 -div 5,10

phase_maths_sub = Node(fsl.BinaryMaths(operation='sub'),
                       name='phase_maths_sub')
def susceptibility_distortion_correction_using_phasediff_fmap(
        fugue_params=dict(smooth3d=2.0),
        register_fmap_on_b0=True,
        name='susceptibility_distortion_correction_using_phasediff_fmap'):
    """
    The fieldmap based method implements susceptibility distortion correction
    by using a mapping of the B0 field as proposed by [Jezzard95]_.
    This workflow uses the implementation of FSL
    (`FUGUE <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE>`_). Phase
    unwrapping is performed using
    `PRELUDE <http://fsl.fmrib.ox.ac.uk/fsl/fsl-4.1.9/fugue/prelude.html>`_
    [Jenkinson03]_. Preparation of the fieldmap is performed reproducing the
    script in FSL `fsl_prepare_fieldmap
    <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE/Guide#SIEMENS_data>`_.

    Args:
        fugue_params: Regularisation to apply to the fieldmap with a
            3D Gaussian smoothing (default: 2.0)
        register_fmap_on_b0: Register the fmap on the b0 or not. If the fmap
            is already well aligned and
        name:

    Inputnode
        in_file (str): DWI dataset.
        in_bval (str): Bval file.
        in_mask (str): Mask file.
        in_fmap_magnitude (str): Magnitude fieldmap. Chose the fmap with the
            best contrast.
        in_fmap_phasediff (str): Phase difference fieldmap.
        delta_echo_time (float): Difference of echo time of the
        effective_echo_spacing (float):
        phase_encoding_direction (str):

    Outputnode:
        out_file (str): Output.
        out_vsm (str): The set of DWI volumes.
        out_warp (str): The bvalues corresponding to the out_dwi.


    .. warning:: Only SIEMENS format fieldmaps are supported.

    .. admonition:: References
<
      .. [Jezzard95] Jezzard P, and Balaban RS, `Correction for geometric
        distortion in echo planar images from B0 field variations
        <http://dx.doi.org/10.1002/mrm.1910340111>`_,
        MRM 34(1):65-73. (1995). doi: 10.1002/mrm.1910340111.

      .. [Jenkinson03] Jenkinson M., `Fast, automated, N-dimensional
        phase-unwrapping algorithm <http://dx.doi.org/10.1002/mrm.10354>`_,
        MRM 49(1):193-197, 2003, doi: 10.1002/mrm.10354.
    """
    import nipype.pipeline.engine as pe
    import nipype.interfaces.utility as niu
    import nipype.interfaces.fsl as fsl
    import nipype.interfaces.ants as ants

    from clinica.utils.epi import bids_dir_to_fsl_dir
    from clinica.utils.fmap import resample_fmap_to_b0

    from nipype.workflows.dmri.fsl.utils import (rads2radsec, siemens2rads,
                                                 vsm2warp, add_empty_vol,
                                                 cleanup_edge_pipeline,
                                                 demean_image)

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_dwi', 'in_mask', 'in_fmap_phasediff', 'in_fmap_magnitude',
        'delta_echo_time', 'effective_echo_spacing', 'phase_encoding_direction'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['out_file', 'out_vsm', 'out_warp', 'out_prepared_fmap']),
                         name='outputnode')

    fsl_dir = pe.Node(niu.Function(input_names=['bids_dir'],
                                   output_names=['fsl_dir'],
                                   function=bids_dir_to_fsl_dir),
                      name='ConvertToFslDir')

    get_b0 = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name='GetB0')

    first_mag = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name='GetFirst')

    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3),
                 name='N4MagnitudeFmap')

    bet = pe.Node(fsl.BET(frac=0.4, mask=True), name='BetN4MagnitudeFmap')

    dilate = pe.Node(fsl.maths.MathsCommand(nan2zeros=True,
                                            args='-kernel sphere 5 -dilM'),
                     name='DilateBet')

    pha2rads = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_file'],
                                    function=siemens2rads),
                       name='PreparePhase')

    prelude = pe.Node(fsl.PRELUDE(process3d=True), name='PhaseUnwrap')

    rad2rsec = pe.Node(niu.Function(input_names=['in_file', 'delta_te'],
                                    output_names=['out_file'],
                                    function=rads2radsec),
                       name='ToRadSec')

    # Node when we register the fmap onto the b0
    fmm2b0 = pe.Node(ants.Registration(output_warped_image=True),
                     name="FmapMagnitudeToB0")
    fmm2b0.inputs.transforms = ['Rigid'] * 2
    fmm2b0.inputs.transform_parameters = [(1.0, )] * 2
    fmm2b0.inputs.number_of_iterations = [[50], [20]]
    fmm2b0.inputs.dimension = 3
    fmm2b0.inputs.metric = ['Mattes', 'Mattes']
    fmm2b0.inputs.metric_weight = [1.0] * 2
    fmm2b0.inputs.radius_or_number_of_bins = [64, 64]
    fmm2b0.inputs.sampling_strategy = ['Regular', 'Random']
    fmm2b0.inputs.sampling_percentage = [None, 0.2]
    fmm2b0.inputs.convergence_threshold = [1.e-5, 1.e-8]
    fmm2b0.inputs.convergence_window_size = [20, 10]
    fmm2b0.inputs.smoothing_sigmas = [[6.0], [2.0]]
    fmm2b0.inputs.sigma_units = ['vox'] * 2
    fmm2b0.inputs.shrink_factors = [[6], [1]]  # ,[1] ]
    fmm2b0.inputs.use_estimate_learning_rate_once = [True] * 2
    fmm2b0.inputs.use_histogram_matching = [True] * 2
    fmm2b0.inputs.initial_moving_transform_com = 0
    fmm2b0.inputs.collapse_output_transforms = True
    fmm2b0.inputs.winsorize_upper_quantile = 0.995

    # Node when we resample the fmap onto the b0
    res_fmap = pe.Node(niu.Function(
        input_names=['in_fmap', 'in_b0', 'out_file'],
        output_names=['out_resampled_fmap'],
        function=resample_fmap_to_b0),
                       name='ResampleFmap')

    apply_xfm = pe.Node(ants.ApplyTransforms(dimension=3,
                                             interpolation='BSpline'),
                        name='FmapPhaseToB0')

    pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='PreliminaryFugue')

    demean = pe.Node(niu.Function(input_names=['in_file', 'in_mask'],
                                  output_names=['out_file'],
                                  function=demean_image),
                     name='DemeanFmap')

    cleanup = cleanup_edge_pipeline()

    add_vol = pe.Node(niu.Function(input_names=['in_file'],
                                   output_names=['out_file'],
                                   function=add_empty_vol),
                      name='AddEmptyVol')

    vsm = pe.Node(fsl.FUGUE(save_shift=True, **fugue_params),
                  name="ComputeVSM")

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

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

    unwarp = pe.MapNode(fsl.FUGUE(icorr=True, forward_warping=False),
                        iterfield=['in_file'],
                        name='UnwarpDWIs')

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

    vsm2dfm = vsm2warp()
    vsm2dfm.inputs.inputnode.scaling = 1.0

    wf = pe.Workflow(name=name)
    wf.connect([
        (inputnode, fsl_dir, [('phase_encoding_direction', 'bids_dir')
                              ]),  # noqa
        (inputnode, pha2rads, [('in_fmap_phasediff', 'in_file')]),  # noqa
        (inputnode, get_b0, [('in_dwi', 'in_file')]),  # noqa
        (inputnode, first_mag, [('in_fmap_magnitude', 'in_file')]),  # noqa
        (first_mag, n4, [('roi_file', 'input_image')]),  # noqa
        (n4, bet, [('output_image', 'in_file')]),  # noqa
        (bet, dilate, [('mask_file', 'in_file')]),  # noqa
        (pha2rads, prelude, [('out_file', 'phase_file')]),  # noqa
        (n4, prelude, [('output_image', 'magnitude_file')]),  # noqa
        (dilate, prelude, [('out_file', 'mask_file')]),  # noqa
        (prelude, rad2rsec, [('unwrapped_phase_file', 'in_file')]),  # noqa
        (inputnode, rad2rsec, [('delta_echo_time', 'delta_te')]),  # noqa
    ])
    if register_fmap_on_b0:
        wf.connect([
            (get_b0, fmm2b0, [('roi_file', 'fixed_image')]),  # noqa
            (n4, fmm2b0, [('output_image', 'moving_image')]),  # noqa
            (inputnode, fmm2b0, [('in_mask', 'fixed_image_mask')]),  # noqa
            (dilate, fmm2b0, [('out_file', 'moving_image_mask')]),  # noqa
            (get_b0, apply_xfm, [('roi_file', 'reference_image')]),  # noqa
            (rad2rsec, apply_xfm, [('out_file', 'input_image')]),  # noqa
            (
                fmm2b0,
                apply_xfm,
                [
                    ('forward_transforms', 'transforms'),  # noqa
                    ('forward_invert_flags', 'invert_transform_flags')
                ]),  # noqa
            (apply_xfm, pre_fugue, [('output_image', 'fmap_in_file')]),  # noqa
            (inputnode, pre_fugue, [('in_mask', 'mask_file')]),  # noqa
            (apply_xfm, outputnode, [('output_image', 'out_prepared_fmap')]
             )  # noqa
        ])
    else:
        wf.connect([
            (get_b0, res_fmap, [('roi_file', 'in_b0')]),  # noqa
            (rad2rsec, res_fmap, [('out_file', 'in_fmap')]),  # noqa
            (res_fmap, pre_fugue, [('out_resampled_fmap', 'fmap_in_file')
                                   ]),  # noqa
            (inputnode, pre_fugue, [('in_mask', 'mask_file')]),  # noqa
            (res_fmap, outputnode, [('out_resampled_fmap', 'out_prepared_fmap')
                                    ])  # noqa
        ])
    wf.connect([
        (pre_fugue, demean, [('fmap_out_file', 'in_file')]),  # noqa
        (inputnode, demean, [('in_mask', 'in_mask')]),  # noqa
        (demean, cleanup, [('out_file', 'inputnode.in_file')]),  # noqa
        (inputnode, cleanup, [('in_mask', 'inputnode.in_mask')]),  # noqa
        (cleanup, add_vol, [('outputnode.out_file', 'in_file')]),  # noqa
        (inputnode, vsm, [('in_mask', 'mask_file')]),  # noqa
        (add_vol, vsm, [('out_file', 'fmap_in_file')]),  # noqa
        (inputnode, vsm, [('delta_echo_time', 'asym_se_time')]),  # noqa
        (inputnode, vsm, [('effective_echo_spacing', 'dwell_time')]),  # noqa
        (inputnode, split, [('in_dwi', 'in_file')]),  # noqa
        (split, unwarp, [('out_files', 'in_file')]),  # noqa
        (vsm, unwarp, [('shift_out_file', 'shift_in_file')]),  # noqa
        (fsl_dir, unwarp, [('fsl_dir', 'unwarp_direction')]),  # noqa
        (unwarp, thres, [('unwarped_file', 'in_file')]),  # noqa
        (thres, merge, [('out_file', 'in_files')]),  # noqa
        (merge, vsm2dfm, [('merged_file', 'inputnode.in_ref')]),  # noqa
        (vsm, vsm2dfm, [('shift_out_file', 'inputnode.in_vsm')]),  # noqa
        (fsl_dir, vsm2dfm, [('fsl_dir', 'inputnode.enc_dir')]),  # noqa
        (rad2rsec, outputnode, [('out_file', 'out_native_fmap')]),  # noqa
        (merge, outputnode, [('merged_file', 'out_file')]),  # noqa
        (vsm, outputnode, [('shift_out_file', 'out_vsm')]),  # noqa
        (vsm2dfm, outputnode, [('outputnode.out_warp', 'out_warp')]),  # noqa
    ])

    return wf
예제 #6
0
def init_phdiff_wf(omp_nthreads, name='phdiff_wf'):
    """
    Distortion correction of EPI sequences using phase-difference maps.

    Estimates the fieldmap using a phase-difference image and one or more
    magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)`
    acquisitions. The `original code was taken from nipype
    <https://github.com/nipy/nipype/blob/master/nipype/workflows/dmri/fsl/artifacts.py#L514>`_.

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

        from sdcflows.workflows.phdiff import init_phdiff_wf
        wf = init_phdiff_wf(omp_nthreads=1)

    **Parameters**:

        omp_nthreads : int
            Maximum number of threads an individual process may use

    **Inputs**:

        magnitude : pathlike
            Path to the corresponding magnitude path(s).
        phasediff : pathlike
            Path to the corresponding phase-difference file.
        metadata : dict
            Metadata dictionary corresponding to the phasediff input

    **Outputs**:

        fmap_ref : pathlike
            The average magnitude image, skull-stripped
        fmap_mask : pathlike
            The brain mask applied to the fieldmap
        fmap : pathlike
            The estimated fieldmap in Hz

    """
    workflow = Workflow(name=name)
    workflow.__desc__ = """\
A deformation field to correct for susceptibility distortions was estimated
based on a field map that was co-registered to the BOLD reference,
using a custom workflow of *fMRIPrep* derived from D. Greve's `epidewarp.fsl`
[script](http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl) and
further improvements of HCP Pipelines [@hcppipelines].
"""

    inputnode = pe.Node(
        niu.IdentityInterface(fields=['magnitude', 'phasediff', 'metadata']),
        name='inputnode')

    outputnode = pe.Node(
        niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']),
        name='outputnode')

    # Merge input magnitude images
    magmrg = pe.Node(IntraModalMerge(), name='magmrg')

    # de-gradient the fields ("bias/illumination artifact")
    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True),
                 name='n4',
                 n_procs=omp_nthreads)
    bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True),
                  name='bet')

    # uses mask from bet; outputs a mask
    # dilate = pe.Node(fsl.maths.MathsCommand(
    #     nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate')

    # phase diff -> radians
    pha2rads = pe.Node(niu.Function(function=siemens2rads), name='pha2rads')

    # FSL PRELUDE will perform phase-unwrapping
    prelude = pe.Node(fsl.PRELUDE(), name='prelude')

    denoise = pe.Node(fsl.SpatialFilter(operation='median',
                                        kernel_shape='sphere',
                                        kernel_size=3),
                      name='denoise')

    demean = pe.Node(niu.Function(function=demean_image), name='demean')

    cleanup_wf = cleanup_edge_pipeline(name="cleanup_wf")

    compfmap = pe.Node(Phasediff2Fieldmap(), name='compfmap')

    # The phdiff2fmap interface is equivalent to:
    # rad2rsec (using rads2radsec from nipype.workflows.dmri.fsl.utils)
    # pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='ComputeFieldmapFUGUE')
    # rsec2hz (divide by 2pi)

    workflow.connect([
        (inputnode, compfmap, [('metadata', 'metadata')]),
        (inputnode, magmrg, [('magnitude', 'in_files')]),
        (magmrg, n4, [('out_avg', 'input_image')]),
        (n4, prelude, [('output_image', 'magnitude_file')]),
        (n4, bet, [('output_image', 'in_file')]),
        (bet, prelude, [('mask_file', 'mask_file')]),
        (inputnode, pha2rads, [('phasediff', 'in_file')]),
        (pha2rads, prelude, [('out', 'phase_file')]),
        (prelude, denoise, [('unwrapped_phase_file', 'in_file')]),
        (denoise, demean, [('out_file', 'in_file')]),
        (demean, cleanup_wf, [('out', 'inputnode.in_file')]),
        (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]),
        (cleanup_wf, compfmap, [('outputnode.out_file', 'in_file')]),
        (compfmap, outputnode, [('out_file', 'fmap')]),
        (bet, outputnode, [('mask_file', 'fmap_mask'),
                           ('out_file', 'fmap_ref')]),
    ])

    return workflow
예제 #7
0
파일: fieldmap.py 프로젝트: bpinsard/misc
def make_t1_fieldmap(name='make_t1_fieldmap'):

    inputnode = pe.Node(utility.IdentityInterface(fields=[
        'complex_image', 'magnitude_image', 't1_mask', 't1_mag', 'delta_TE'
    ]),
                        run_without_submitting=True,
                        name='inputspec')
    outputnode = pe.Node(
        utility.IdentityInterface(fields=['fieldmap', 'fieldmap_mask']),
        run_without_submitting=True,
        name='outputspec')

    n_fieldmap_to_t1 = pe.Node(fsl.FLIRT(cost='mutualinfo',
                                         dof=6,
                                         no_search=True,
                                         uses_qform=True),
                               name='fieldmap_to_t1')

    n_flirt_complex = pe.Node(utility.Function(
        input_names=['mat_file', 'cplx_file', 'ref_file'],
        output_names=['out_file'],
        function=flirt_complex),
                              name='flirt_complex')

    n_resample_complex = pe.Node(afni.Resample(resample_mode='Cu',
                                               out_file='%s_int1sp.nii.gz'),
                                 name='resample_complex')

    n_phase_mag = pe.Node(utility.Function(
        input_names=['complex_in_file', 'mask_file'],
        output_names=['magnitude_out_file', 'phase_out_file'],
        function=complex_to_mag_phase),
                          name='phase_mag')

    n_unwrap_phases = pe.Node(fsl.PRELUDE(process3d=True),
                              name='unwrap_phases')

    n_make_fieldmap = pe.Node(
        fsl.FUGUE(smooth3d=3),
        iterfield=['fmap_out_file', 'mask_file', 'fmap_in_file'],
        name='make_fieldmap')

    w = pe.Workflow(name=name)

    w.connect([
        #       (inputnode, n_resample_complex,[('complex_image','in_file'),
        #                                       ('t1_mask','master')]),
        (inputnode, n_fieldmap_to_t1, [('magnitude_image', 'in_file'),
                                       ('t1_mag', 'reference')]),
        (n_fieldmap_to_t1, n_flirt_complex, [
            ('out_matrix_file', 'mat_file'),
        ]),
        (inputnode, n_flirt_complex, [('complex_image', 'cplx_file'),
                                      ('t1_mag', 'ref_file')]),
        (n_flirt_complex, n_phase_mag, [('out_file', 'complex_in_file')]),
        (inputnode, n_phase_mag, [('t1_mask', 'mask_file')]),
        (n_phase_mag, n_unwrap_phases, [('phase_out_file', 'phase_file')]),
        (n_phase_mag, n_unwrap_phases, [('magnitude_out_file',
                                         'magnitude_file')]),
        (inputnode, n_unwrap_phases, [('t1_mask', 'mask_file')]),
        (n_unwrap_phases, n_make_fieldmap, [('unwrapped_phase_file',
                                             'phasemap_file')]),
        (inputnode, n_make_fieldmap,
         [('delta_TE', 'asym_se_time'), ('t1_mask', 'mask_file'),
          (('complex_image', fname_presuffix_basename, '', '_fieldmap'),
           'fmap_out_file')]),
    ])

    return w
예제 #8
0
def vsm_fmb(name='VSM_FMB', phase_unwrap=True, fmb_params={}):
    """
    Workflow that uses `FUGUE <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE>`_
    to compute the voxel-shift map (VSM) from the corresponding B-fieldmap in
    EPI data.
    """
    wf = pe.Workflow(name=name)

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_bmap', 'in_mask', 'echospacing', 'delta_te', 'acc_factor',
        'enc_dir'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['vsm', 'dfm', 'dfm_inv', 'jac', 'jac_inv']),
                         name='outputnode')

    selmag = pe.Node(niu.Select(index=0), name='SelectMag')
    selpha = pe.Node(niu.Select(index=1), name='SelectPha')

    magmsk = pe.Node(fs.ApplyMask(), name='mask_mag')
    eff_es = pe.Node(niu.Function(input_names=['echospacing', 'acc_factor'],
                                  function=_eff_es_seg,
                                  output_names=['echospacing']),
                     name='GetEffEcho')
    phcache = pe.Node(niu.IdentityInterface(fields=['pha_unwrapped']),
                      name='PhCache')

    rad2rsec = pe.Node(niu.Function(input_names=['in_file', 'delta_te'],
                                    output_names=['out_file'],
                                    function=nwu.rads2radsec),
                       name='ToRadSec')
    pre_fugue = pe.Node(fsl.FUGUE(save_unmasked_fmap=True),
                        name='PreliminaryFugue')
    demean = pe.Node(niu.Function(function=nwu.demean_image,
                                  input_names=['in_file', 'in_mask'],
                                  output_names=['out_file']),
                     name='DemeanFmap')
    cleanup = nwu.cleanup_edge_pipeline()
    addvol = pe.Node(niu.Function(function=nwu.add_empty_vol,
                                  input_names=['in_file'],
                                  output_names=['out_file']),
                     name='AddEmptyVol')
    vsm = pe.Node(fsl.FUGUE(save_unmasked_shift=True, **fmb_params),
                  name="Compute_VSM")

    dfm = process_vsm()
    dfm.inputs.inputnode.scaling = 1.0

    wf.connect([(inputnode, selmag, [('in_bmap', 'inlist')]),
                (inputnode, selpha, [('in_bmap', 'inlist')]),
                (inputnode, magmsk, [('in_mask', 'mask_file')]),
                (inputnode, eff_es, [('echospacing', 'echospacing'),
                                     ('acc_factor', 'acc_factor')]),
                (selmag, magmsk, [('out', 'in_file')]),
                (phcache, rad2rsec, [('pha_unwrapped', 'in_file')]),
                (inputnode, rad2rsec, [('delta_te', 'delta_te')]),
                (rad2rsec, pre_fugue, [('out_file', 'fmap_in_file')]),
                (inputnode, pre_fugue, [('in_mask', 'mask_file')]),
                (pre_fugue, demean, [('fmap_out_file', 'in_file')]),
                (inputnode, demean, [('in_mask', 'in_mask')]),
                (demean, cleanup, [('out_file', 'inputnode.in_file')]),
                (inputnode, cleanup, [('in_mask', 'inputnode.in_mask')]),
                (cleanup, addvol, [('outputnode.out_file', 'in_file')]),
                (addvol, vsm, [('out_file', 'fmap_in_file')]),
                (eff_es, vsm, [('echospacing', 'dwell_time')]),
                (inputnode, vsm, [('in_mask', 'mask_file'),
                                  ('delta_te', 'asym_se_time')]),
                (vsm, outputnode, [('shift_out_file', 'vsm')]),
                (vsm, dfm, [('shift_out_file', 'inputnode.vsm')]),
                (inputnode, dfm, [('in_mask', 'inputnode.reference'),
                                  ('enc_dir', 'inputnode.enc_dir')]),
                (dfm, outputnode, [('outputnode.dfm', 'dfm'),
                                   ('outputnode.jacobian', 'jac'),
                                   ('outputnode.inv_dfm', 'dfm_inv'),
                                   ('outputnode.inv_jacobian', 'jac_inv')])])

    if phase_unwrap:
        prelude = pe.Node(fsl.PRELUDE(process3d=True), name='PhaseUnwrap')
        wf.connect([(selmag, prelude, [('out', 'magnitude_file')]),
                    (selpha, prelude, [('out', 'phase_file')]),
                    (magmsk, prelude, [('out_file', 'mask_file')]),
                    (prelude, phcache, [('unwrapped_phase_file',
                                         'pha_unwrapped')])])
    else:
        wf.connect(selpha, 'out', phcache, 'pha_unwrapped')
    return wf
예제 #9
0
def init_phdiff_wf(omp_nthreads, name='phdiff_wf'):
    """
    Estimates the fieldmap using a phase-difference image and one or more
    magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)`
    acquisitions. The `original code was taken from nipype
    <https://github.com/nipy/nipype/blob/master/nipype/workflows/dmri/fsl/artifacts.py#L514>`_.

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

        from fmriprep.workflows.fieldmap.phdiff import init_phdiff_wf
        wf = init_phdiff_wf(omp_nthreads=1)


    Outputs::

      outputnode.fmap_ref - The average magnitude image, skull-stripped
      outputnode.fmap_mask - The brain mask applied to the fieldmap
      outputnode.fmap - The estimated fieldmap in Hz


    """

    inputnode = pe.Node(
        niu.IdentityInterface(fields=['magnitude', 'phasediff']),
        name='inputnode')

    outputnode = pe.Node(
        niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']),
        name='outputnode')

    def _pick1st(inlist):
        return inlist[0]

    # Read phasediff echo times
    meta = pe.Node(ReadSidecarJSON(),
                   name='meta',
                   mem_gb=0.01,
                   run_without_submitting=True)

    # Merge input magnitude images
    magmrg = pe.Node(IntraModalMerge(), name='magmrg')

    # de-gradient the fields ("bias/illumination artifact")
    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True),
                 name='n4',
                 n_procs=omp_nthreads)
    bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True),
                  name='bet')
    ds_fmap_mask = pe.Node(DerivativesDataSink(suffix='fmap_mask'),
                           name='ds_report_fmap_mask',
                           mem_gb=0.01,
                           run_without_submitting=True)
    # uses mask from bet; outputs a mask
    # dilate = pe.Node(fsl.maths.MathsCommand(
    #     nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate')

    # phase diff -> radians
    pha2rads = pe.Node(niu.Function(function=siemens2rads), name='pha2rads')

    # FSL PRELUDE will perform phase-unwrapping
    prelude = pe.Node(fsl.PRELUDE(), name='prelude')

    denoise = pe.Node(fsl.SpatialFilter(operation='median',
                                        kernel_shape='sphere',
                                        kernel_size=3),
                      name='denoise')

    demean = pe.Node(niu.Function(function=demean_image), name='demean')

    cleanup_wf = cleanup_edge_pipeline(name="cleanup_wf")

    compfmap = pe.Node(Phasediff2Fieldmap(), name='compfmap')

    # The phdiff2fmap interface is equivalent to:
    # rad2rsec (using rads2radsec from nipype.workflows.dmri.fsl.utils)
    # pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='ComputeFieldmapFUGUE')
    # rsec2hz (divide by 2pi)

    workflow = pe.Workflow(name=name)
    workflow.connect([
        (inputnode, meta, [('phasediff', 'in_file')]),
        (inputnode, magmrg, [('magnitude', 'in_files')]),
        (magmrg, n4, [('out_avg', 'input_image')]),
        (n4, prelude, [('output_image', 'magnitude_file')]),
        (n4, bet, [('output_image', 'in_file')]),
        (bet, prelude, [('mask_file', 'mask_file')]),
        (inputnode, pha2rads, [('phasediff', 'in_file')]),
        (pha2rads, prelude, [('out', 'phase_file')]),
        (meta, compfmap, [('out_dict', 'metadata')]),
        (prelude, denoise, [('unwrapped_phase_file', 'in_file')]),
        (denoise, demean, [('out_file', 'in_file')]),
        (demean, cleanup_wf, [('out', 'inputnode.in_file')]),
        (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]),
        (cleanup_wf, compfmap, [('outputnode.out_file', 'in_file')]),
        (compfmap, outputnode, [('out_file', 'fmap')]),
        (bet, outputnode, [('mask_file', 'fmap_mask'),
                           ('out_file', 'fmap_ref')]),
        (inputnode, ds_fmap_mask, [('phasediff', 'source_file')]),
        (bet, ds_fmap_mask, [('out_report', 'in_file')]),
    ])

    return workflow
예제 #10
0
파일: fieldmap.py 프로젝트: bpinsard/misc
def make_fmap_wkfl_old(name='make_fieldmap'):

    inputnode = pe.Node(utility.IdentityInterface(fields=[
        'phase_difference', 'magnitude', 't1_mask', 't1_mag', 'delta_TE'
    ]),
                        name='inputspec')
    outputnode = pe.Node(utility.IdentityInterface(fields=[
        'fieldmap', 'fieldmap_reg', 'fieldmap_magnitude', 'fieldmap_mask'
    ]),
                         name='outputspec')

    n_fieldmap2t1_warp = pe.Node(
        fsl.FLIRT(
            out_matrix_file='fieldmap2t1.mat',
            cost='normmi',
            dof=6,
            searchr_x=[-5, 5],  # restrict search as they are acquired 
            searchr_y=[-5, 5],  # in the same sequence
            searchr_z=[-5, 5],
            cost_func='normmi'),
        name='fieldmap2t1_warp')
    n_invert_fieldmap2t1_warp = pe.Node(fsl.ConvertXFM(invert_xfm=True),
                                        name='invert_fieldmap2t1_warp')
    n_warp_t1_mask = pe.Node(fsl.ApplyXfm(apply_xfm=True,
                                          interp='nearestneighbour'),
                             name='warp_t1_mask')

    n_mask_mag = pe.Node(interface=fsl.ImageMaths(op_string='-mul',
                                                  suffix='_brain',
                                                  output_type='NIFTI'),
                         name='mask_mag')

    n_unwrap_phasediff = pe.Node(fsl.PRELUDE(process3d=True),
                                 name='unwrap_phasediff')

    n_make_fieldmap = pe.Node(fsl.FUGUE(fmap_out_file='fieldmap.nii.gz',
                                        smooth3d=2),
                              name='make_fieldmap')

    w = pe.Workflow(name=name)
    w.connect([
        (inputnode, n_fieldmap2t1_warp, [('t1_mag', 'reference'),
                                         ('magnitude', 'in_file')]),
        (n_fieldmap2t1_warp, n_invert_fieldmap2t1_warp, [('out_matrix_file',
                                                          'in_file')]),
        (n_invert_fieldmap2t1_warp, n_warp_t1_mask, [('out_file',
                                                      'in_matrix_file')]),
        (inputnode, n_warp_t1_mask, [('t1_mask', 'in_file')]),
        (inputnode, n_warp_t1_mask, [('magnitude', 'reference')]),
        (inputnode, n_mask_mag, [('magnitude', 'in_file')]),
        (n_warp_t1_mask, n_mask_mag, [('out_file', 'in_file2')]),
        (inputnode, n_unwrap_phasediff, [('phase_difference', 'phase_file')]),
        (inputnode, n_unwrap_phasediff, [('magnitude', 'magnitude_file')]),
        (n_warp_t1_mask, n_unwrap_phasediff, [('out_file', 'mask_file')]),
        (inputnode, n_make_fieldmap,
         [(('phase_difference', fname_presuffix_basename, 'fieldmap_', '',
            './'), 'fmap_out_file')]),
        (n_warp_t1_mask, n_make_fieldmap, [('out_file', 'mask_file')]),
        (n_unwrap_phasediff, n_make_fieldmap, [('unwrapped_phase_file',
                                                'phasemap_file')]),
        (inputnode, n_make_fieldmap, [('delta_TE', 'asym_se_time')]),
        (n_warp_t1_mask, outputnode, [('out_file', 'fieldmap_mask')]),
        (n_mask_mag, outputnode, [('out_file', 'fieldmap_magnitude')]),
        (n_make_fieldmap, outputnode, [('fmap_out_file', 'fieldmap')]),
        (n_make_fieldmap, outputnode, [('fmap_out_file', 'fieldmap_reg')]),
    ])

    return w
예제 #11
0
def prepare_phasediff_fmap(name="prepare_phasediff_fmap"):
    """This workflow adapts the fsl_prepare_fieldmap script from FSL for the FSL eddy command.

    Please note that the step 3 converts the fieldmap into Hz instead of rad/s
    in the initial script because FSL eddy --field expects the fieldmap to be in Hz.

    Input node:
        fmap_mask (str): Binary mask of the fieldmap.
        fmap_phasediff (str): Phase difference fieldmap.
        fmap_magnitude (str): Brain extracted magnitude fieldmap. Chose the fieldmap with the best contrast.
        delta_echo_time (float): DeltaEchoTime from BIDS specifications.

    Output node:
        calibrated_fmap (str): Calibrated fieldmap for eddy --field command.

    Warnings:
        This workflow can not be used for PRELUDE. You would need to change the step 3 (conversion into rad/s instead of Hz).
    """
    import nipype.interfaces.fsl as fsl
    import nipype.interfaces.utility as nutil
    import nipype.pipeline.engine as npe
    from niflow.nipype1.workflows.dmri.fsl.utils import (
        cleanup_edge_pipeline,
        demean_image,
        siemens2rads,
    )

    from .dwi_preprocessing_using_phasediff_fmap_utils import rads2hz

    input_node = npe.Node(
        nutil.IdentityInterface(fields=[
            "fmap_mask", "fmap_phasediff", "fmap_magnitude", "delta_echo_time"
        ]),
        name="input_node",
    )

    output_node = npe.Node(nutil.IdentityInterface(fields=["calibrated_fmap"]),
                           name="output_node")

    # Step 1 - Convert the fmap into radians
    pha2rads = npe.Node(
        nutil.Function(input_names=["in_file"],
                       output_names=["out_file"],
                       function=siemens2rads),
        name="1-ConvertFMapToRads",
    )

    # Step 2 - Unwrap the fmap with PRELUDE
    prelude = npe.Node(fsl.PRELUDE(process3d=True), name="2-PhaseUnwrap")

    # Step 3 - Convert the fmap to Hz
    rads2hz = npe.Node(
        nutil.Function(
            input_names=["in_file", "delta_te"],
            output_names=["out_file"],
            function=rads2hz,
        ),
        name="3-ConvertFMapToHz",
    )

    # Step 4 - Call FUGUE to extrapolate from mask (fill holes, etc)
    pre_fugue = npe.Node(fsl.FUGUE(save_fmap=True),
                         name="4-FugueExtrapolationFromMask")

    # Step 5 - Demean fmap to avoid gross shifting
    demean = npe.Node(
        nutil.Function(
            input_names=["in_file", "in_mask"],
            output_names=["out_file"],
            function=demean_image,
        ),
        name="5-DemeanFMap",
    )

    # Step 6 - Clean up edge voxels
    cleanup = cleanup_edge_pipeline(name="6-CleanUpEdgeVoxels")

    wf = npe.Workflow(name=name)
    # fmt: off
    wf.connect([
        # Step 1 - Convert the fmap into radians
        (input_node, pha2rads, [("fmap_phasediff", "in_file")]),
        # Step 2 - Unwrap the fmap with PRELUDE
        (pha2rads, prelude, [("out_file", "phase_file")]),
        (input_node, prelude, [("fmap_magnitude", "magnitude_file")]),
        (input_node, prelude, [("fmap_mask", "mask_file")]),
        # Step 3 - Convert the fmap to Hz
        (prelude, rads2hz, [("unwrapped_phase_file", "in_file")]),
        (input_node, rads2hz, [("delta_echo_time", "delta_te")]),
        # Step 4 - Call FUGUE to extrapolate from mask (fill holes, etc)
        (rads2hz, pre_fugue, [("out_file", "fmap_in_file")]),
        (input_node, pre_fugue, [("fmap_mask", "mask_file")]),
        # Step 5 - Demean fmap to avoid gross shifting
        (pre_fugue, demean, [("fmap_out_file", "in_file")]),
        (input_node, demean, [("fmap_mask", "in_mask")]),
        # Step 6 - Clean up edge voxels
        (demean, cleanup, [("out_file", "inputnode.in_file")]),
        (input_node, cleanup, [("fmap_mask", "inputnode.in_mask")]),
        # Output node
        (cleanup, output_node, [("outputnode.out_file", "calibrated_fmap")]),
    ])
    # fmt: on

    return wf
def phase_diff_and_magnitudes(name='phase_diff_and_magnitudes'):
    """
    Estimates the fieldmap using a phase-difference image and one or more
    magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)`
    acquisitions. The `original code was taken from nipype
    <https://github.com/nipy/nipype/blob/master/nipype/workflows/dmri/fsl/artifacts.py#L514>`_.

    Outputs::

      outputnode.fmap_ref - The average magnitude image, skull-stripped
      outputnode.fmap_mask - The brain mask applied to the fieldmap
      outputnode.fmap - The estimated fieldmap in Hz


    """
    inputnode = pe.Node(niu.IdentityInterface(fields=['input_images']),
                        name='inputnode')

    outputnode = pe.Node(
        niu.IdentityInterface(fields=['fmap_ref', 'fmap_mask', 'fmap']),
        name='outputnode')

    sortfmaps = pe.Node(niu.Function(function=_sort_fmaps,
                                     input_names=['input_images'],
                                     output_names=['magnitude', 'phasediff']),
                        name='SortFmaps')

    def _pick1st(inlist):
        return inlist[0]

    # Read phasediff echo times
    meta = pe.Node(ReadSidecarJSON(fields=['EchoTime1', 'EchoTime2']),
                   name='metadata')
    dte = pe.Node(niu.Function(input_names=['in_values'],
                               output_names=['delta_te'],
                               function=_delta_te),
                  name='ComputeDeltaTE')

    # Merge input magnitude images
    magmrg = pe.Node(IntraModalMerge(), name='MagnitudeFuse')

    # de-gradient the fields ("bias/illumination artifact")
    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='MagnitudeBias')
    bet = pe.Node(fsl.BET(frac=0.6, mask=True), name='MagnitudeBET')
    # uses mask from bet; outputs a mask
    # dilate = pe.Node(fsl.maths.MathsCommand(
    #     nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate')

    # phase diff -> radians
    pha2rads = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_file'],
                                    function=siemens2rads),
                       name='PreparePhase')

    # FSL PRELUDE will perform phase-unwrapping
    prelude = pe.Node(fsl.PRELUDE(process3d=True), name='PhaseUnwrap')

    denoise = pe.Node(fsl.SpatialFilter(operation='median',
                                        kernel_shape='sphere',
                                        kernel_size=3),
                      name='PhaseDenoise')

    demean = pe.Node(niu.Function(input_names=['in_file', 'in_mask'],
                                  output_names=['out_file'],
                                  function=demean_image),
                     name='DemeanFmap')

    cleanup = cleanup_edge_pipeline()

    compfmap = pe.Node(niu.Function(input_names=['in_file', 'delta_te'],
                                    output_names=['out_file'],
                                    function=phdiff2fmap),
                       name='ComputeFieldmap')

    # The phdiff2fmap interface is equivalent to:
    # rad2rsec (using rads2radsec from nipype.workflows.dmri.fsl.utils)
    # pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='ComputeFieldmapFUGUE')
    # rsec2hz (divide by 2pi)

    workflow = pe.Workflow(name=name)
    workflow.connect([
        (inputnode, sortfmaps, [('input_images', 'input_images')]),
        (sortfmaps, meta, [(('phasediff', _pick1st), 'in_file')]),
        (sortfmaps, magmrg, [('magnitude', 'in_files')]),
        (magmrg, n4, [('out_avg', 'input_image')]),
        (n4, prelude, [('output_image', 'magnitude_file')]),
        (n4, bet, [('output_image', 'in_file')]),
        (bet, prelude, [('mask_file', 'mask_file')]),
        (sortfmaps, pha2rads, [(('phasediff', _pick1st), 'in_file')]),
        (pha2rads, prelude, [('out_file', 'phase_file')]),
        (meta, dte, [('out_dict', 'in_values')]),
        (dte, compfmap, [('delta_te', 'delta_te')]),
        (prelude, denoise, [('unwrapped_phase_file', 'in_file')]),
        (denoise, demean, [('out_file', 'in_file')]),
        (demean, cleanup, [('out_file', 'inputnode.in_file')]),
        (bet, cleanup, [('mask_file', 'inputnode.in_mask')]),
        (cleanup, compfmap, [('outputnode.out_file', 'in_file')]),
        (compfmap, outputnode, [('out_file', 'fmap')]),
        (bet, outputnode, [('mask_file', 'fmap_mask'),
                           ('out_file', 'fmap_ref')])
    ])

    return workflow
예제 #13
0
                                 moving=mag_brain,
                                 output_warped=magbrain_warped,
                                 transform_prefix=outdir + '/trans_')
applytransform(in_file=phaseon,
               reference=ref,
               out_file=phase_warped,
               transformfile=outdir + '/trans_Composite.h5',
               interpolation='LanczosWindowedSinc')

au2rads(phase_warped, outdir)
phasediff = glob.glob(outdir + '/*rads.nii.gz')
maskdata(magbrain_warped, mag_mask)

#unwarp withe predule
unwrapped = outdir + '/unwrapped.nii.gz'
prefsl = fsl.PRELUDE()
prefsl.inputs.magnitude_file = magbrain_warped
prefsl.inputs.phase_file = phasediff[0]
prefsl.inputs.mask_file = mag_mask
prefsl.inputs.unwrapped_phase_file = unwrapped
prefsl.run()
#denoise demean recenter the fieldmap and
#recentre
recentered = _recenter(unwrapped, newpath=outdir + '/')
# denoise with fsl spatial filter
denoised = outdir + '/unwrapped_denoise.nii.gz'
denoise = fsl.SpatialFilter()
denoise.inputs.in_file = recentered
denoise.inputs.kernel_shape = 'sphere'
denoise.inputs.kernel_size = 3
denoise.inputs.operation = 'median'
예제 #14
0
파일: phdiff.py 프로젝트: badamifs/qsiprep
def init_phdiff_wf(omp_nthreads, phasetype='phasediff', name='phdiff_wf'):
    """
    Estimates the fieldmap using a phase-difference image and one or more
    magnitude images corresponding to two or more :abbr:`GRE (Gradient Echo sequence)`
    acquisitions. The `original code was taken from nipype
    <https://github.com/nipy/nipype/blob/master/nipype/workflows/dmri/fsl/artifacts.py#L514>`_.

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

        from qsiprep.workflows.fieldmap.phdiff import init_phdiff_wf
        wf = init_phdiff_wf(omp_nthreads=1)


    Outputs::

      outputnode.fmap_ref - The average magnitude image, skull-stripped
      outputnode.fmap_mask - The brain mask applied to the fieldmap
      outputnode.fmap - The estimated fieldmap in Hz


    """

    workflow = Workflow(name=name)
    workflow.__desc__ = """\
A deformation field to correct for susceptibility distortions was estimated
based on a field map that was co-registered to the BOLD reference,
using a custom workflow of *fMRIPrep* derived from D. Greve's `epidewarp.fsl`
[script](http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl) and
further improvements of HCP Pipelines [@hcppipelines].
"""

    inputnode = pe.Node(
        niu.IdentityInterface(fields=['magnitude', 'phasediff']),
        name='inputnode')

    outputnode = pe.Node(
        niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']),
        name='outputnode')

    # Merge input magnitude images
    magmrg = pe.Node(IntraModalMerge(), name='magmrg')

    # de-gradient the fields ("bias/illumination artifact")
    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True),
                 name='n4',
                 n_procs=omp_nthreads)
    bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True),
                  name='bet')
    ds_report_fmap_mask = pe.Node(DerivativesDataSink(desc='brain',
                                                      suffix='mask'),
                                  name='ds_report_fmap_mask',
                                  mem_gb=0.01,
                                  run_without_submitting=True)
    # uses mask from bet; outputs a mask
    # dilate = pe.Node(fsl.maths.MathsCommand(
    #     nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate')

    # FSL PRELUDE will perform phase-unwrapping
    prelude = pe.Node(fsl.PRELUDE(), name='prelude')

    denoise = pe.Node(fsl.SpatialFilter(operation='median',
                                        kernel_shape='sphere',
                                        kernel_size=5),
                      name='denoise')

    demean = pe.Node(niu.Function(function=demean_image), name='demean')

    cleanup_wf = cleanup_edge_pipeline(name="cleanup_wf")

    compfmap = pe.Node(Phasediff2Fieldmap(), name='compfmap')

    # The phdiff2fmap interface is equivalent to:
    # rad2rsec (using rads2radsec from nipype.workflows.dmri.fsl.utils)
    # pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='ComputeFieldmapFUGUE')
    # rsec2hz (divide by 2pi)

    if phasetype == "phasediff":
        # Read phasediff echo times
        meta = pe.Node(ReadSidecarJSON(), name='meta', mem_gb=0.01)

        # phase diff -> radians
        pha2rads = pe.Node(niu.Function(function=siemens2rads),
                           name='pha2rads')
        # Read phasediff echo times
        meta = pe.Node(ReadSidecarJSON(),
                       name='meta',
                       mem_gb=0.01,
                       run_without_submitting=True)
        workflow.connect([
            (meta, compfmap, [('out_dict', 'metadata')]),
            (inputnode, pha2rads, [('phasediff', 'in_file')]),
            (pha2rads, prelude, [('out', 'phase_file')]),
            (inputnode, ds_report_fmap_mask, [('phasediff', 'source_file')]),
        ])

    elif phasetype == "phase":
        workflow.__desc__ += """\
The phase difference used for unwarping was calculated using two separate phase measurements
 [@pncprocessing].
    """
        # Special case for phase1, phase2 images
        meta = pe.MapNode(ReadSidecarJSON(),
                          name='meta',
                          mem_gb=0.01,
                          run_without_submitting=True,
                          iterfield=['in_file'])
        phases2fmap = pe.Node(Phases2Fieldmap(), name='phases2fmap')
        workflow.connect([
            (meta, phases2fmap, [('out_dict', 'metadatas')]),
            (inputnode, phases2fmap, [('phasediff', 'phase_files')]),
            (phases2fmap, prelude, [('out_file', 'phase_file')]),
            (phases2fmap, compfmap, [('phasediff_metadata', 'metadata')]),
            (phases2fmap, ds_report_fmap_mask, [('out_file', 'source_file')])
        ])

    workflow.connect([
        (inputnode, meta, [('phasediff', 'in_file')]),
        (inputnode, magmrg, [('magnitude', 'in_files')]),
        (magmrg, n4, [('out_avg', 'input_image')]),
        (n4, prelude, [('output_image', 'magnitude_file')]),
        (n4, bet, [('output_image', 'in_file')]),
        (bet, prelude, [('mask_file', 'mask_file')]),
        (prelude, denoise, [('unwrapped_phase_file', 'in_file')]),
        (denoise, demean, [('out_file', 'in_file')]),
        (demean, cleanup_wf, [('out', 'inputnode.in_file')]),
        (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]),
        (cleanup_wf, compfmap, [('outputnode.out_file', 'in_file')]),
        (compfmap, outputnode, [('out_file', 'fmap')]),
        (bet, outputnode, [('mask_file', 'fmap_mask'),
                           ('out_file', 'fmap_ref')]),
        (bet, ds_report_fmap_mask, [('out_report', 'in_file')]),
    ])

    return workflow
예제 #15
0
파일: fieldmap.py 프로젝트: bpinsard/misc
def make_fs_fieldmap(name='make_fs_fieldmap'):

    inputnode = pe.Node(utility.IdentityInterface(fields=[
        'complex_image', 'magnitude_image', 'subject_id',
        'freesurfer_subject_dir', 't1_mask', 'delta_TE'
    ]),
                        run_without_submitting=True,
                        name='inputspec')
    outputnode = pe.Node(
        utility.IdentityInterface(fields=['fieldmap', 'fieldmap_mask']),
        run_without_submitting=True,
        name='outputspec')

    n_fieldmap_to_t1_bbr = pe.Node(freesurfer.BBRegister(init='header',
                                                         reg_frame=0,
                                                         out_fsl_file=True,
                                                         registered_file=True,
                                                         contrast_type='t1'),
                                   name='fieldmap_to_t1_bbr')
    """
    n_fieldmap_to_t1 = pe.Node(
        fsl.FLIRT(cost='mutualinfo',
                  dof=6,
                  no_search=True,
                  uses_qform=True),
        name='fieldmap_to_t1')
        """
    n_reg_to_mni = pe.Node(freesurfer.preprocess.Tkregister(
        no_edit=True, xfm_out='%s_xfm.mat'),
                           run_without_submitting=True,
                           name='reg_to_mni')

    n_resamp_complex = pe.Node(utility.Function(
        input_names=['mat_file', 'cplx_file', 'ref_file'],
        output_names=['out_file'],
        function=fs_resamp_complex),
                               name='resamp_complex')

    n_phase_mag = pe.Node(utility.Function(
        input_names=['complex_in_file', 'mask_file'],
        output_names=['magnitude_out_file', 'phase_out_file'],
        function=complex_to_mag_phase),
                          name='phase_mag')

    n_unwrap_phases = pe.Node(fsl.PRELUDE(process3d=True),
                              name='unwrap_phases')

    n_make_fieldmap = pe.Node(
        fsl.FUGUE(smooth3d=3, unwarp_direction='z'),
        iterfield=['fmap_out_file', 'mask_file', 'fmap_in_file'],
        name='make_fieldmap')

    w = pe.Workflow(name=name)

    w.connect([
        #       (inputnode, n_fieldmap_to_t1, [('magnitude_image','in_file'),
        #                                      ('t1_mag','reference')]),
        #(n_fieldmap_to_t1, n_flirt_complex, [('out_matrix_file','mat_file'),]),
        (inputnode, n_fieldmap_to_t1_bbr, [('magnitude_image', 'source_file'),
                                           ('freesurfer_subject_dir',
                                            'subjects_dir'),
                                           ('subject_id', 'subject_id')]),
        (n_fieldmap_to_t1_bbr, n_reg_to_mni, [('out_reg_file', 'reg_file')]),
        (inputnode, n_reg_to_mni, [
            ('magnitude_image', 'mov'),
            ('freesurfer_subject_dir', 'subjects_dir'),
        ]),
        (n_reg_to_mni, n_resamp_complex, [
            ('xfm_out', 'mat_file'),
        ]),
        (inputnode, n_resamp_complex, [('complex_image', 'cplx_file'),
                                       ('t1_mask', 'ref_file')]),
        (n_resamp_complex, n_phase_mag, [('out_file', 'complex_in_file')]),
        (inputnode, n_phase_mag, [('t1_mask', 'mask_file')]),
        (n_phase_mag, n_unwrap_phases, [('phase_out_file', 'phase_file')]),
        (n_phase_mag, n_unwrap_phases, [('magnitude_out_file',
                                         'magnitude_file')]),
        (inputnode, n_unwrap_phases, [('t1_mask', 'mask_file')]),
        (n_unwrap_phases, n_make_fieldmap, [('unwrapped_phase_file',
                                             'phasemap_file')]),
        (inputnode, n_make_fieldmap,
         [('delta_TE', 'asym_se_time'), ('t1_mask', 'mask_file'),
          (('complex_image', fname_presuffix_basename, '', '_fieldmap'),
           'fmap_out_file')]),
    ])

    return w
예제 #16
0
def create_epidewarp_pipeline(name='epidewarp', fieldmap_registration=False):
    """
    Replaces the epidewarp.fsl script (http://www.nmr.mgh.harvard.edu/~greve/fbirn/b0/epidewarp.fsl)
    for susceptibility distortion correction of dMRI & fMRI acquired with EPI sequences and the fieldmap
    information (Jezzard et al., 1995) using FSL's FUGUE. The registration to the (warped) fieldmap
    (strictly following the original script) is available using fieldmap_registration=True.


    .. warning:: This workflow makes use of ``epidewarp.fsl`` a script of FSL deprecated long
      time ago. The use of this workflow is not recommended, use
      :func:`nipype.workflows.dmri.preprocess.epi.sdc_fmb` instead.


    Example
    -------

    >>> nipype_epicorrect = create_epidewarp_pipeline('nipype_epidewarp', fieldmap_registration=False)
    >>> nipype_epicorrect.inputs.inputnode.in_file = 'diffusion.nii'
    >>> nipype_epicorrect.inputs.inputnode.fieldmap_mag = 'magnitude.nii'
    >>> nipype_epicorrect.inputs.inputnode.fieldmap_pha = 'phase.nii'
    >>> nipype_epicorrect.inputs.inputnode.te_diff = 2.46
    >>> nipype_epicorrect.inputs.inputnode.epi_echospacing = 0.77
    >>> nipype_epicorrect.inputs.inputnode.epi_rev_encoding = False
    >>> nipype_epicorrect.inputs.inputnode.ref_num = 0
    >>> nipype_epicorrect.inputs.inputnode.pi_accel_factor = 1.0
    >>> nipype_epicorrect.run() # doctest: +SKIP

    Inputs::

        inputnode.in_file - The volume acquired with EPI sequence
        inputnode.fieldmap_mag - The magnitude of the fieldmap
        inputnode.fieldmap_pha - The phase difference of the fieldmap
        inputnode.te_diff - Time difference between TE in ms.
        inputnode.epi_echospacing - The echo spacing (aka dwell time) in the EPI sequence
        inputnode.epi_ph_encoding_dir - The phase encoding direction in EPI acquisition (default y)
        inputnode.epi_rev_encoding - True if it is acquired with reverse encoding
        inputnode.pi_accel_factor - Acceleration factor used for EPI parallel imaging (GRAPPA)
        inputnode.vsm_sigma - Sigma value of the gaussian smoothing filter applied to the vsm (voxel shift map)
        inputnode.ref_num - The reference volume (B=0 in dMRI or a central frame in fMRI)


    Outputs::

        outputnode.epi_corrected


    Optional arguments::

        fieldmap_registration - True if registration to fieldmap should be done (default False)

    """

    warnings.warn(('This workflow reproduces a deprecated FSL script.'),
                  DeprecationWarning)

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_file', 'fieldmap_mag', 'fieldmap_pha', 'te_diff',
        'epi_echospacing', 'epi_ph_encoding_dir', 'epi_rev_encoding',
        'pi_accel_factor', 'vsm_sigma', 'ref_num', 'unwarp_direction'
    ]),
                        name='inputnode')

    pipeline = pe.Workflow(name=name)

    # Keep first frame from magnitude
    select_mag = pe.Node(fsl.utils.ExtractROI(t_size=1, t_min=0),
                         name='select_magnitude')

    # mask_brain
    mask_mag = pe.Node(fsl.BET(mask=True), name='mask_magnitude')
    mask_mag_dil = pe.Node(niu.Function(input_names=['in_file'],
                                        output_names=['out_file'],
                                        function=_dilate_mask),
                           name='mask_dilate')

    # Compute dwell time
    dwell_time = pe.Node(niu.Function(
        input_names=['dwell_time', 'pi_factor', 'is_reverse_encoding'],
        output_names=['dwell_time'],
        function=_compute_dwelltime),
                         name='dwell_time')

    # Normalize phase diff to be [-pi, pi)
    norm_pha = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_file'],
                                    function=_prepare_phasediff),
                       name='normalize_phasediff')
    # Execute FSL PRELUDE: prelude -p %s -a %s -o %s -f -v -m %s
    prelude = pe.Node(fsl.PRELUDE(process3d=True), name='phase_unwrap')
    fill_phase = pe.Node(niu.Function(input_names=['in_file'],
                                      output_names=['out_file'],
                                      function=_fill_phase),
                         name='fill_phasediff')

    # to assure that vsm is same dimension as mag. The input only affects the output dimension.
    # The content of the input has no effect on the vsm. The de-warped mag volume is
    # meaningless and will be thrown away
    # fugue -i %s -u %s -p %s --dwell=%s --asym=%s --mask=%s --saveshift=%s %
    # ( mag_name, magdw_name, ph_name, esp, tediff, mask_name, vsmmag_name)
    vsm = pe.Node(fsl.FUGUE(save_shift=True), name='generate_vsm')
    vsm_mean = pe.Node(niu.Function(
        input_names=['in_file', 'mask_file', 'in_unwarped'],
        output_names=['out_file'],
        function=_vsm_remove_mean),
                       name='vsm_mean_shift')

    # fugue_epi
    dwi_split = pe.Node(niu.Function(input_names=['in_file'],
                                     output_names=['out_files'],
                                     function=_split_dwi),
                        name='dwi_split')
    # 'fugue -i %s -u %s --loadshift=%s --mask=%s' % ( vol_name, out_vol_name, vsm_name, mask_name )
    dwi_applyxfm = pe.MapNode(fsl.FUGUE(icorr=True, save_shift=False),
                              iterfield=['in_file'],
                              name='dwi_fugue')
    # Merge back all volumes
    dwi_merge = pe.Node(fsl.utils.Merge(dimension='t'), name='dwi_merge')

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

    pipeline.connect([
        (inputnode, dwell_time, [('epi_echospacing', 'dwell_time'),
                                 ('pi_accel_factor', 'pi_factor'),
                                 ('epi_rev_encoding', 'is_reverse_encoding')]),
        (inputnode, select_mag, [('fieldmap_mag', 'in_file')]),
        (inputnode, norm_pha, [('fieldmap_pha', 'in_file')]),
        (select_mag, mask_mag, [('roi_file', 'in_file')]),
        (mask_mag, mask_mag_dil, [('mask_file', 'in_file')]),
        (select_mag, prelude, [('roi_file', 'magnitude_file')]),
        (norm_pha, prelude, [('out_file', 'phase_file')]),
        (mask_mag_dil, prelude, [('out_file', 'mask_file')]),
        (prelude, fill_phase, [('unwrapped_phase_file', 'in_file')]),
        (inputnode, vsm, [('fieldmap_mag', 'in_file')]),
        (fill_phase, vsm, [('out_file', 'phasemap_in_file')]),
        (inputnode, vsm, [(('te_diff', _ms2sec), 'asym_se_time'),
                          ('vsm_sigma', 'smooth2d')]),
        (dwell_time, vsm, [(('dwell_time', _ms2sec), 'dwell_time')]),
        (mask_mag_dil, vsm, [('out_file', 'mask_file')]),
        (mask_mag_dil, vsm_mean, [('out_file', 'mask_file')]),
        (vsm, vsm_mean, [('unwarped_file', 'in_unwarped'),
                         ('shift_out_file', 'in_file')]),
        (inputnode, dwi_split, [('in_file', 'in_file')]),
        (dwi_split, dwi_applyxfm, [('out_files', 'in_file')]),
        (dwi_applyxfm, dwi_merge, [('unwarped_file', 'in_files')]),
        (dwi_merge, outputnode, [('merged_file', 'epi_corrected')])
    ])

    if fieldmap_registration:
        """ Register magfw to example epi. There are some parameters here that may need to be tweaked. Should probably strip the mag
            Pre-condition: forward warp the mag in order to reg with func. What does mask do here?
        """
        # Select reference volume from EPI (B0 in dMRI and a middle frame in
        # fMRI)
        select_epi = pe.Node(fsl.utils.ExtractROI(t_size=1), name='select_epi')

        # fugue -i %s -w %s --loadshift=%s --mask=%s % ( mag_name, magfw_name,
        # vsmmag_name, mask_name ), log ) # Forward Map
        vsm_fwd = pe.Node(fsl.FUGUE(forward_warping=True), name='vsm_fwd')
        vsm_reg = pe.Node(fsl.FLIRT(bins=256,
                                    cost='corratio',
                                    dof=6,
                                    interp='spline',
                                    searchr_x=[-10, 10],
                                    searchr_y=[-10, 10],
                                    searchr_z=[-10, 10]),
                          name='vsm_registration')
        # 'flirt -in %s -ref %s -out %s -init %s -applyxfm' % ( vsmmag_name, ref_epi, vsmmag_name, magfw_mat_out )
        vsm_applyxfm = pe.Node(fsl.ApplyXfm(interp='spline'),
                               name='vsm_apply_xfm')
        # 'flirt -in %s -ref %s -out %s -init %s -applyxfm' % ( mask_name, ref_epi, mask_name, magfw_mat_out )
        msk_applyxfm = pe.Node(fsl.ApplyXfm(interp='nearestneighbour'),
                               name='msk_apply_xfm')

        pipeline.connect([
            (inputnode, select_epi, [('in_file', 'in_file'),
                                     ('ref_num', 't_min')]),
            (select_epi, vsm_reg, [('roi_file', 'reference')]),
            (vsm, vsm_fwd, [('shift_out_file', 'shift_in_file')]),
            (mask_mag_dil, vsm_fwd, [('out_file', 'mask_file')]),
            (inputnode, vsm_fwd, [('fieldmap_mag', 'in_file')]),
            (vsm_fwd, vsm_reg, [('warped_file', 'in_file')]),
            (vsm_reg, msk_applyxfm, [('out_matrix_file', 'in_matrix_file')]),
            (select_epi, msk_applyxfm, [('roi_file', 'reference')]),
            (mask_mag_dil, msk_applyxfm, [('out_file', 'in_file')]),
            (vsm_reg, vsm_applyxfm, [('out_matrix_file', 'in_matrix_file')]),
            (select_epi, vsm_applyxfm, [('roi_file', 'reference')]),
            (vsm_mean, vsm_applyxfm, [('out_file', 'in_file')]),
            (msk_applyxfm, dwi_applyxfm, [('out_file', 'mask_file')]),
            (vsm_applyxfm, dwi_applyxfm, [('out_file', 'shift_in_file')])
        ])
    else:
        pipeline.connect([
            (mask_mag_dil, dwi_applyxfm, [('out_file', 'mask_file')]),
            (vsm_mean, dwi_applyxfm, [('out_file', 'shift_in_file')])
        ])

    return pipeline
예제 #17
0
def sdc_fmb(name='fmb_correction',
            fugue_params=dict(smooth3d=2.0),
            bmap_params=dict(delta_te=2.46e-3),
            epi_params=dict(echospacing=0.77e-3,
                            acc_factor=3,
                            enc_dir='y-')):
    """
    SDC stands for susceptibility distortion correction. FMB stands for
    fieldmap-based.

    The fieldmap based method (FMB) implements SDC by using a mapping of the
    B0 field as proposed by [Jezzard95]_. This workflow uses the implementation
    of FSL (`FUGUE <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE>`_). Phase
    unwrapping is performed using `PRELUDE
    <http://fsl.fmrib.ox.ac.uk/fsl/fsl-4.1.9/fugue/prelude.html>`_
    [Jenkinson03]_. Preparation of the fieldmap is performed reproducing the
    script in FSL `fsl_prepare_fieldmap
    <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE/Guide#SIEMENS_data>`_.

    Example
    -------

    >>> from nipype.workflows.dmri.fsl.artifacts import sdc_fmb
    >>> fmb = sdc_fmb()
    >>> fmb.inputs.inputnode.in_file = 'diffusion.nii'
    >>> fmb.inputs.inputnode.in_bval = 'diffusion.bval'
    >>> fmb.inputs.inputnode.in_mask = 'mask.nii'
    >>> fmb.inputs.inputnode.bmap_mag = 'magnitude.nii'
    >>> fmb.inputs.inputnode.bmap_pha = 'phase.nii'
    >>> fmb.run() # doctest: +SKIP

    .. warning:: Only SIEMENS format fieldmaps are supported.

    .. admonition:: References

      .. [Jezzard95] Jezzard P, and Balaban RS, `Correction for geometric
        distortion in echo planar images from B0 field variations
        <http://dx.doi.org/10.1002/mrm.1910340111>`_,
        MRM 34(1):65-73. (1995). doi: 10.1002/mrm.1910340111.

      .. [Jenkinson03] Jenkinson M., `Fast, automated, N-dimensional
        phase-unwrapping algorithm <http://dx.doi.org/10.1002/mrm.10354>`_,
        MRM 49(1):193-197, 2003, doi: 10.1002/mrm.10354.

    """
    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bval',
                        'in_mask', 'bmap_pha', 'bmap_mag']),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_vsm',
                         'out_warp']),
                         name='outputnode')

    delta_te = epi_params['echospacing'] / (1.0 * epi_params['acc_factor'])

    firstmag = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name='GetFirst')
    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='Bias')
    bet = pe.Node(fsl.BET(frac=0.4, mask=True), name='BrainExtraction')
    dilate = pe.Node(fsl.maths.MathsCommand(nan2zeros=True,
                     args='-kernel sphere 5 -dilM'), name='MskDilate')
    pha2rads = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_file'],
                       function=siemens2rads), name='PreparePhase')
    prelude = pe.Node(fsl.PRELUDE(process3d=True), name='PhaseUnwrap')
    rad2rsec = pe.Node(niu.Function(input_names=['in_file', 'delta_te'],
                       output_names=['out_file'], function=rads2radsec), name='ToRadSec')
    rad2rsec.inputs.delta_te = bmap_params['delta_te']

    avg_b0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
                     output_names=['out_file'], function=b0_average), name='b0_avg')

    flirt = pe.Node(fsl.FLIRT(interp='spline', cost='normmi', cost_func='normmi',
                    dof=6, bins=64, save_log=True, padding_size=10,
                    searchr_x=[-4, 4], searchr_y=[-4, 4], searchr_z=[-4, 4],
                    fine_search=1, coarse_search=10),
                    name='BmapMag2B0')
    applyxfm = pe.Node(fsl.ApplyXfm(interp='spline', padding_size=10, apply_xfm=True),
                       name='BmapPha2B0')

    pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='PreliminaryFugue')
    demean = pe.Node(niu.Function(input_names=['in_file', 'in_mask'],
                     output_names=['out_file'], function=demean_image),
                     name='DemeanFmap')

    cleanup = cleanup_edge_pipeline()

    addvol = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_file'],
                     function=add_empty_vol), name='AddEmptyVol')

    vsm = pe.Node(fsl.FUGUE(save_shift=True, **fugue_params),
                  name="ComputeVSM")
    vsm.inputs.asym_se_time = bmap_params['delta_te']
    vsm.inputs.dwell_time = delta_te

    split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
    merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')
    unwarp = pe.MapNode(fsl.FUGUE(icorr=True, forward_warping=False),
                        iterfield=['in_file'], name='UnwarpDWIs')
    unwarp.inputs.unwarp_direction = epi_params['enc_dir']
    thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'],
                       name='RemoveNegative')
    vsm2dfm = vsm2warp()
    vsm2dfm.inputs.inputnode.scaling = 1.0
    vsm2dfm.inputs.inputnode.enc_dir = epi_params['enc_dir']

    wf = pe.Workflow(name=name)
    wf.connect([
        (inputnode,   pha2rads,   [('bmap_pha', 'in_file')]),
        (inputnode,   firstmag,   [('bmap_mag', 'in_file')]),
        (inputnode,   avg_b0,     [('in_file', 'in_dwi'),
                                   ('in_bval', 'in_bval')]),
        (firstmag,    n4,         [('roi_file', 'input_image')]),
        (n4,          bet,        [('output_image', 'in_file')]),
        (bet,         dilate,     [('mask_file', 'in_file')]),
        (pha2rads,    prelude,    [('out_file', 'phase_file')]),
        (n4,          prelude,    [('output_image', 'magnitude_file')]),
        (dilate,      prelude,    [('out_file', 'mask_file')]),
        (prelude,     rad2rsec,   [('unwrapped_phase_file', 'in_file')]),
        (avg_b0,      flirt,      [('out_file', 'reference')]),
        (inputnode,   flirt,      [('in_mask', 'ref_weight')]),
        (n4,          flirt,      [('output_image', 'in_file')]),
        (dilate,      flirt,      [('out_file', 'in_weight')]),
        (avg_b0,      applyxfm,   [('out_file', 'reference')]),
        (rad2rsec,    applyxfm,   [('out_file', 'in_file')]),
        (flirt,       applyxfm,   [('out_matrix_file', 'in_matrix_file')]),
        (applyxfm,    pre_fugue,  [('out_file', 'fmap_in_file')]),
        (inputnode,   pre_fugue,  [('in_mask', 'mask_file')]),
        (pre_fugue,   demean,     [('fmap_out_file', 'in_file')]),
        (inputnode,   demean,     [('in_mask', 'in_mask')]),
        (demean,      cleanup,    [('out_file', 'inputnode.in_file')]),
        (inputnode,   cleanup,    [('in_mask', 'inputnode.in_mask')]),
        (cleanup,     addvol,     [('outputnode.out_file', 'in_file')]),
        (inputnode,   vsm,        [('in_mask', 'mask_file')]),
        (addvol,      vsm,        [('out_file', 'fmap_in_file')]),
        (inputnode,   split,      [('in_file', 'in_file')]),
        (split,       unwarp,     [('out_files', 'in_file')]),
        (vsm,         unwarp,     [('shift_out_file', 'shift_in_file')]),
        (unwarp,      thres,      [('unwarped_file', 'in_file')]),
        (thres,       merge,      [('out_file', 'in_files')]),
        (merge,       vsm2dfm,    [('merged_file', 'inputnode.in_ref')]),
        (vsm,         vsm2dfm,    [('shift_out_file', 'inputnode.in_vsm')]),
        (merge,       outputnode, [('merged_file', 'out_file')]),
        (vsm,         outputnode, [('shift_out_file', 'out_vsm')]),
        (vsm2dfm,     outputnode, [('outputnode.out_warp', 'out_warp')])
    ])
    return wf