def afni_unifize(in_file,
                 write_dir=None,
                 out_file=None,
                 caching=False,
                 terminal_output='allatonce',
                 verbose=True,
                 environ=None,
                 copy_geometry=False,
                 **unifize_kwargs):
    if write_dir is None:
        write_dir = os.path.dirname(in_file)

    if environ is None:
        environ = {'AFNI_DECONFLICT': 'OVERWRITE'}

    if caching:
        memory = Memory(write_dir)
        copy_geom = memory.cache(fsl.CopyGeom)
        unifize = memory.cache(afni.Unifize)
        copy = memory.cache(afni.Copy)
        unifize.interface().set_default_terminal_output(terminal_output)
        copy.interface().set_default_terminal_output(terminal_output)
    else:
        copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run
        unifize = afni.Unifize(terminal_output=terminal_output).run
        copy = afni.Copy(terminal_output=terminal_output).run

    if out_file is None:
        out_file = fname_presuffix(in_file,
                                   suffix='_unifized',
                                   newpath=write_dir)
    if copy_geometry:
        unifized_file = fname_presuffix(in_file,
                                        suffix='_unifized_rough_geom',
                                        newpath=write_dir)
    else:
        unifized_file = out_file

    out_unifize = unifize(in_file=in_file,
                          out_file=unifized_file,
                          environ=environ,
                          quiet=not (verbose),
                          **unifize_kwargs)

    if copy_geometry:
        out_copy = copy(in_file=out_unifize.outputs.out_file,
                        out_file=out_file,
                        environ=environ)
        out_copy_geom = copy_geom(dest_file=out_copy.outputs.out_file,
                                  in_file=in_file)
    return out_file
def ants_n4(in_file,
            write_dir=None,
            caching=False,
            terminal_output='allatonce',
            environ=None,
            copy_geometry=True):
    if write_dir is None:
        write_dir = os.path.dirname(in_file)

    if environ is None:
        environ = {'AFNI_DECONFLICT': 'OVERWRITE'}

    if caching:
        memory = Memory(write_dir)
        bias_correct = memory.cache(ants.N4BiasFieldCorrection)
        copy = memory.cache(afni.Copy)
        copy_geom = memory.cache(fsl.CopyGeom)
        bias_correct.interface().set_default_terminal_output(terminal_output)
        copy.interface().set_default_terminal_output(terminal_output)
    else:
        bias_correct = ants.N4BiasFieldCorrection(
            terminal_output=terminal_output).run
        copy = afni.Copy(terminal_output=terminal_output).run
        copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run

    unbiased_file = fname_presuffix(in_file, suffix='_n4', newpath=write_dir)
    if copy_geometry:
        output_image = fname_presuffix(in_file,
                                       suffix='_n4_rough_geom',
                                       newpath=write_dir)
    else:
        output_image = unbiased_file

    out_bias_correct = bias_correct(
        input_image=in_file,
        shrink_factor=_compute_n4_max_shrink(in_file),
        output_image=output_image)

    if copy_geometry:
        out_copy = copy(in_file=out_bias_correct.outputs.output_image,
                        out_file=unbiased_file,
                        environ=environ)
        out_copy_geom = copy_geom(dest_file=out_copy.outputs.out_file,
                                  in_file=in_file)
    return unbiased_file
Beispiel #3
0
def create_preprocess_phase_wf():
    """Create's phase preprocessing workflow with the following steps:

    1) Convert data to float
    2) Determine scaling required for radians
    3) Apply radian scaling
    4) Convert to real and imaginary
    5) Apply magnitude motion correction parameters
    6) Correct geometry changes (AFNI issue)
    7) Convert back to phase
    8) Unwrap and detrend data
    9) Mask data using magnitude mask
    10) Calculate noise from data

    """
    preprocphase = pe.Workflow(name="preprocphase")
    preprocphase.config['execution']['remove_unnecessary_outputs'] = False

    # define inputs
    inputspec = pe.Node(
        ul.IdentityInterface(fields=[
            'input_phase',  # raw phase data
            'input_mag',  # raw mag data
            'motion_par',  # afni transform concatenated from magnitude data
            'mask_file',  # bet mask from magnitude data
            'rest',  # volumes of rest in block design
            'task',  # volumes of task in block design
        ]),
        name='inputspec')

    # 1) Convert data to float
    img2float = pe.MapNode(interface=fsl.ImageMaths(out_data_type='float',
                                                    op_string='',
                                                    suffix='_dtype'),
                           iterfield=['in_file'],
                           name='img2float')

    # 2) Determine radian scaling required
    findscaling = pe.MapNode(interface=ul.Function(
        input_names=['in_file'],
        output_names=['scaling_arg'],
        function=findscalingarg),
                             name='findscaling',
                             iterfield=['in_file'])

    # 3) Apply radian scaling
    convert2rad = pe.MapNode(interface=fsl.maths.MathsCommand(),
                             name='convert2rad',
                             iterfield=['in_file', 'args'])

    # 4) Convert to real and imaginary (2 step process)
    makecomplex = pe.MapNode(interface=fsl.Complex(complex_polar=True),
                             name='makecomplex',
                             iterfield=['magnitude_in_file', 'phase_in_file'])

    splitcomplex = pe.MapNode(interface=fsl.Complex(real_cartesian=True),
                              name='splitcomplex',
                              iterfield=['complex_in_file'])

    # 5) Apply magnitude motion correction parameters
    mocoreal = pe.MapNode(interface=afni.Allineate(),
                          name='mocoreal',
                          iterfield=['in_file', 'in_matrix'])
    mocoreal.inputs.outputtype = 'NIFTI_GZ'
    mocoreal.inputs.out_file = 'mocophase.nii.gz'
    mocoreal.inputs.num_threads = 2
    mocoimag = mocoreal.clone('mocoimag')

    # 6) Correct geometry changes (AFNI issue)
    cpgeommocoreal = pe.MapNode(interface=fsl.CopyGeom(),
                                name='cpgeommoco',
                                iterfield=['dest_file', 'in_file'])
    cpgeommocoimag = cpgeommocoreal.clone('cpgeommocoimag')
    cpgeommocophase = cpgeommocoreal.clone('cpgeommocophase')

    # 7) Convert back to phase (2 step process)
    makecomplexmoco = pe.MapNode(
        interface=fsl.Complex(complex_cartesian=True),
        name='makecomplexmoco',
        iterfield=['real_in_file', 'imaginary_in_file'])

    splitcomplexmoco = pe.MapNode(interface=fsl.Complex(real_polar=True),
                                  name='splitcomplexmoco',
                                  iterfield=['complex_in_file'])

    # 8) Remove first volume, unwrap and detrend phase data
    prepphase = pe.MapNode(interface=pp.PreprocessPhase(),
                           name='prepphase',
                           iterfield=['phase'])

    # 9) Mask data using magnitude mask
    maskfunc = pe.MapNode(interface=fsl.ImageMaths(suffix='_bet',
                                                   op_string='-mas'),
                          iterfield=['in_file'],
                          name='maskfunc')
    # 10) Calculate noise from data
    calcSNR = pe.MapNode(interface=pp.RestAverage(),
                         name='calcSNR',
                         iterfield=['func', 'rest', 'task'])

    # outputspec
    outputspec = pe.Node(ul.IdentityInterface(
        fields=['proc_phase', 'uw_phase', 'delta_phase', 'std_phase']),
                         name='outputspec')

    preprocphase = pe.Workflow(name='preprocphase')
    preprocphase.connect([
        (inputspec, img2float, [('input_phase', 'in_file')]),  # 1
        (inputspec, findscaling, [('input_phase', 'in_file')]),  # 2
        (findscaling, convert2rad, [('scaling_arg', 'args')]),
        (img2float, convert2rad, [('out_file', 'in_file')]),
        (convert2rad, makecomplex, [('out_file', 'phase_in_file')]),  # 3
        (inputspec, makecomplex, [('input_mag', 'magnitude_in_file')]),
        (makecomplex, splitcomplex, [('complex_out_file', 'complex_in_file')
                                     ]),  # 4
        (inputspec, mocoreal, [('motion_par', 'in_matrix')]),  # 5 real
        (splitcomplex, mocoreal, [('real_out_file', 'in_file')]),
        (mocoreal, cpgeommocoreal, [('out_file', 'dest_file')]),  #6 real
        (img2float, cpgeommocoreal, [('out_file', 'in_file')]),
        (inputspec, mocoimag, [('motion_par', 'in_matrix')]),  # 5 imag
        (splitcomplex, mocoimag, [('imaginary_out_file', 'in_file')]),
        (mocoimag, cpgeommocoimag, [('out_file', 'dest_file')]),  # 6 imag
        (img2float, cpgeommocoimag, [('out_file', 'in_file')]),
        (cpgeommocoreal, makecomplexmoco, [('out_file', 'real_in_file')]),  # 7
        (cpgeommocoimag, makecomplexmoco, [('out_file', 'imaginary_in_file')]),
        (makecomplexmoco, splitcomplexmoco, [('complex_out_file',
                                              'complex_in_file')]),
        (splitcomplexmoco, cpgeommocophase, [('phase_out_file', 'dest_file')]),
        (img2float, cpgeommocophase, [('out_file', 'in_file')]),
        (cpgeommocophase, prepphase, [('out_file', 'phase')]),  # 8
        (prepphase, maskfunc, [('detrended_phase', 'in_file')]),  # 9
        (inputspec, maskfunc, [('mask_file', 'in_file2')]),
        (maskfunc, outputspec, [('out_file', 'proc_phase')]),
        (prepphase, outputspec, [('uw_phase', 'uw_phase')]),
        (prepphase, outputspec, [('delta_phase', 'delta_phase')]),
        (
            inputspec,
            calcSNR,
            [
                ('rest', 'rest'),  # 10
                ('task', 'task')
            ]),
        (prepphase, calcSNR, [('detrended_phase', 'func')]),
        (calcSNR, outputspec, [('noise', 'std_phase')])
    ])

    return preprocphase
Beispiel #4
0
pipe.connect(bandpass_filter, 'out_file', graph, 'inputspec.subject')
pipe.connect(preproc, 'outputspec.func_brain_mask', graph,
             'inputspec.template')

########################################################################################################################
# get fisrt element of results

get_element = pe.MapNode(interface=util.Function(input_names=['list', 'index'],
                                                 output_names=['out'],
                                                 function=get_element),
                         name='get_element',
                         iterfield=['list'])
get_element.inputs.index = 0
pipe.connect(graph, 'outputspec.centrality_outputs', get_element, 'list')

copg = pe.MapNode(interface=fsl.CopyGeom(),
                  name="copy_geom",
                  iterfield=['in_file', 'dest_file'])

pipe.connect(get_element, 'out', copg, 'dest_file')
pipe.connect(preproc, 'outputspec.func_brain_mask', copg, 'in_file')

########################################################################################################################
# get_zscore
#from CPAC.utils import get_zscore

zscore_cent = cent.get_zscore('cent', wf_name='Ztrans_cent')

pipe.connect(preproc, 'outputspec.func_brain_mask', zscore_cent,
             'inputspec.mask_file')
pipe.connect(copg, 'out_file', zscore_cent, 'inputspec.input_file')
Beispiel #5
0
def coregister_fmri_session(session_data,
                            t_r,
                            write_dir,
                            brain_volume,
                            use_rats_tool=True,
                            slice_timing=True,
                            prior_rigid_body_registration=False,
                            caching=False,
                            voxel_size_x=.1,
                            voxel_size_y=.1,
                            verbose=True,
                            **environ_kwargs):
    """
    Coregistration of the subject's functional and anatomical images.
    The functional volume is aligned to the anatomical, first with a rigid body
    registration and then on a per-slice basis (only a fine correction, this is
    mostly for correction of EPI distortion).


    Parameters
    ----------
    session_data : sammba.registration.SessionData
        Single animal data, giving paths to its functional and anatomical
        image, as well as it identifier.

    t_r : float
        Repetition time for the EPI, in seconds.

    write_dir : str
        Directory to save the output and temporary images.

    brain_volume : int
        Volume of the brain in mm3 used for brain extraction.
        Typically 400 for mouse and 1800 for rat.

    use_rats_tool : bool, optional
        If True, brain mask is computed using RATS Mathematical Morphology.
        Otherwise, a histogram-based brain segmentation is used.

    prior_rigid_body_registration : bool, optional
        If True, a rigid-body registration of the anat to the func is performed
        prior to the warp. Useful if the images headers have missing/wrong
        information.

    voxel_size_x : float, optional
        Resampling resolution for the x-axis, in mm.

    voxel_size_y : float, optional
        Resampling resolution for the y-axis, in mm.

    caching : bool, optional
        Wether or not to use caching.

    verbose : bool, optional
        If True, all steps are verbose. Note that caching implies some
        verbosity in any case.

    environ_kwargs : extra arguments keywords
        Extra arguments keywords, passed to interfaces environ variable.

    Returns
    -------
    the same sequence with each animal_data updated: the following attributes
    are added
        - `output_dir_` : str
                          Path to the output directory.
        - `coreg_func_` : str
                          Path to paths to the coregistered functional image.
        - `coreg_anat_` : str
                          Path to paths to the coregistered functional image.
        - `coreg_transform_` : str
                               Path to the transform from anat to func.

    Notes
    -----
    If `use_rats_tool` is turned on, RATS tool is used for brain extraction
    and has to be cited. For more information, see
    `RATS <http://www.iibi.uiowa.edu/content/rats-overview/>`_
    """
    func_filename = session_data.func
    anat_filename = session_data.anat

    environ = {'AFNI_DECONFLICT': 'OVERWRITE'}
    for (key, value) in environ_kwargs.items():
        environ[key] = value

    if verbose:
        terminal_output = 'allatonce'
    else:
        terminal_output = 'none'

    if use_rats_tool:
        if segmentation.interfaces.Info().version() is None:
            raise ValueError('Can not locate RATS')
        else:
            ComputeMask = segmentation.MathMorphoMask
    else:
        ComputeMask = segmentation.HistogramMask

    if ants.base.Info().version is None:
        raise ValueError('Can not locate ANTS')

    if caching:
        memory = Memory(write_dir)
        tshift = memory.cache(afni.TShift)
        clip_level = memory.cache(afni.ClipLevel)
        volreg = memory.cache(afni.Volreg)
        allineate = memory.cache(afni.Allineate)
        tstat = memory.cache(afni.TStat)
        compute_mask = memory.cache(ComputeMask)
        calc = memory.cache(afni.Calc)
        allineate = memory.cache(afni.Allineate)
        allineate2 = memory.cache(afni.Allineate)
        unifize = memory.cache(afni.Unifize)
        bias_correct = memory.cache(ants.N4BiasFieldCorrection)
        catmatvec = memory.cache(afni.CatMatvec)
        warp = memory.cache(afni.Warp)
        resample = memory.cache(afni.Resample)
        slicer = memory.cache(afni.ZCutUp)
        warp_apply = memory.cache(afni.NwarpApply)
        qwarp = memory.cache(afni.Qwarp)
        merge = memory.cache(afni.Zcat)
        copy_geom = memory.cache(fsl.CopyGeom)
        overwrite = False
        for step in [
                tshift, volreg, allineate, allineate2, tstat, compute_mask,
                calc, unifize, resample, slicer, warp_apply, qwarp, merge
        ]:
            step.interface().set_default_terminal_output(terminal_output)
    else:
        tshift = afni.TShift(terminal_output=terminal_output).run
        clip_level = afni.ClipLevel().run
        volreg = afni.Volreg(terminal_output=terminal_output).run
        allineate = afni.Allineate(terminal_output=terminal_output).run
        allineate2 = afni.Allineate(terminal_output=terminal_output
                                    ).run  # TODO: remove after fixed bug
        tstat = afni.TStat(terminal_output=terminal_output).run
        compute_mask = ComputeMask().run
        calc = afni.Calc(terminal_output=terminal_output).run
        unifize = afni.Unifize(terminal_output=terminal_output).run
        bias_correct = ants.N4BiasFieldCorrection(
            terminal_output=terminal_output).run
        catmatvec = afni.CatMatvec().run
        warp = afni.Warp().run
        resample = afni.Resample(terminal_output=terminal_output).run
        slicer = afni.ZCutUp(terminal_output=terminal_output).run
        warp_apply = afni.NwarpApply(terminal_output=terminal_output).run
        qwarp = afni.Qwarp(terminal_output=terminal_output).run
        merge = afni.Zcat(terminal_output=terminal_output).run
        copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run
        overwrite = True

    session_data._check_inputs()
    output_dir = os.path.join(os.path.abspath(write_dir),
                              session_data.animal_id)
    session_data._set_output_dir_(output_dir)
    current_dir = os.getcwd()
    os.chdir(output_dir)
    output_files = []

    #######################################
    # Correct functional for slice timing #
    #######################################
    if slice_timing:
        out_tshift = tshift(in_file=func_filename,
                            outputtype='NIFTI_GZ',
                            tpattern='altplus',
                            tr=str(t_r),
                            environ=environ)
        func_filename = out_tshift.outputs.out_file
        output_files.append(func_filename)

    ################################################
    # Register functional volumes to the first one #
    ################################################
    # XXX why do you need a thresholded image ?
    out_clip_level = clip_level(in_file=func_filename)
    out_calc_threshold = calc(in_file_a=func_filename,
                              expr='ispositive(a-{0}) * a'.format(
                                  out_clip_level.outputs.clip_val),
                              outputtype='NIFTI_GZ')
    thresholded_filename = out_calc_threshold.outputs.out_file

    out_volreg = volreg(  # XXX dfile not saved
        in_file=thresholded_filename,
        outputtype='NIFTI_GZ',
        environ=environ,
        oned_file=fname_presuffix(thresholded_filename,
                                  suffix='Vr.1Dfile.1D',
                                  use_ext=False),
        oned_matrix_save=fname_presuffix(thresholded_filename,
                                         suffix='Vr.aff12.1D',
                                         use_ext=False))

    # Apply the registration to the whole head
    out_allineate = allineate(in_file=func_filename,
                              master=func_filename,
                              in_matrix=out_volreg.outputs.oned_matrix_save,
                              out_file=fname_presuffix(func_filename,
                                                       suffix='Av'),
                              environ=environ)

    # 3dAllineate removes the obliquity. This is not a good way to readd it as
    # removes motion correction info in the header if it were an AFNI file...as
    # it happens it's NIfTI which does not store that so irrelevant!
    out_copy_geom = copy_geom(dest_file=out_allineate.outputs.out_file,
                              in_file=out_volreg.outputs.out_file)

    allineated_filename = out_copy_geom.outputs.out_file

    # Create a (hopefully) nice mean image for use in the registration
    out_tstat = tstat(in_file=allineated_filename,
                      args='-mean',
                      outputtype='NIFTI_GZ',
                      environ=environ)

    # Update outputs
    output_files.extend([
        thresholded_filename, out_volreg.outputs.oned_matrix_save,
        out_volreg.outputs.out_file, out_volreg.outputs.md1d_file,
        allineated_filename, out_tstat.outputs.out_file
    ])

    ###########################################
    # Corret anat and func for intensity bias #
    ###########################################
    # Correct the functional average for intensities bias
    out_bias_correct = bias_correct(input_image=out_tstat.outputs.out_file)
    unbiased_func_filename = out_bias_correct.outputs.output_image

    # Bias correct the antomical image
    out_unifize = unifize(in_file=anat_filename,
                          outputtype='NIFTI_GZ',
                          environ=environ)
    unbiased_anat_filename = out_unifize.outputs.out_file

    # Update outputs
    output_files.extend([unbiased_func_filename, unbiased_anat_filename])

    #############################################
    # Rigid-body registration anat -> mean func #
    #############################################
    if prior_rigid_body_registration:
        # Mask the mean functional volume outside the brain.
        out_clip_level = clip_level(in_file=unbiased_func_filename)
        out_compute_mask_func = compute_mask(
            in_file=unbiased_func_filename,
            volume_threshold=brain_volume,
            intensity_threshold=int(out_clip_level.outputs.clip_val))
        out_cacl_func = calc(in_file_a=unbiased_func_filename,
                             in_file_b=out_compute_mask_func.outputs.out_file,
                             expr='a*b',
                             outputtype='NIFTI_GZ',
                             environ=environ)

        # Mask the anatomical volume outside the brain.
        out_clip_level = clip_level(in_file=unbiased_anat_filename)
        out_compute_mask_anat = compute_mask(
            in_file=unbiased_anat_filename,
            volume_threshold=brain_volume,
            intensity_threshold=int(out_clip_level.outputs.clip_val))
        out_cacl_anat = calc(in_file_a=unbiased_anat_filename,
                             in_file_b=out_compute_mask_anat.outputs.out_file,
                             expr='a*b',
                             outputtype='NIFTI_GZ',
                             environ=environ)

        # Compute the transformation from functional to anatomical brain
        # XXX: why in this sense
        out_allineate = allineate2(
            in_file=out_cacl_func.outputs.out_file,
            reference=out_cacl_anat.outputs.out_file,
            out_matrix=fname_presuffix(out_cacl_func.outputs.out_file,
                                       suffix='_shr.aff12.1D',
                                       use_ext=False),
            center_of_mass='',
            warp_type='shift_rotate',
            out_file=fname_presuffix(out_cacl_func.outputs.out_file,
                                     suffix='_shr'),
            environ=environ)
        rigid_transform_file = out_allineate.outputs.out_matrix
        output_files.extend([
            out_compute_mask_func.outputs.out_file,
            out_cacl_func.outputs.out_file,
            out_compute_mask_anat.outputs.out_file,
            out_cacl_anat.outputs.out_file, rigid_transform_file,
            out_allineate.outputs.out_file
        ])

        # apply the inverse transform to register the anatomical to the func
        catmatvec_out_file = fname_presuffix(rigid_transform_file,
                                             suffix='INV')
        out_catmatvec = catmatvec(in_file=[(rigid_transform_file, 'I')],
                                  oneline=True,
                                  out_file=catmatvec_out_file)
        output_files.append(out_catmatvec.outputs.out_file)
        out_allineate = allineate(in_file=unbiased_anat_filename,
                                  master=unbiased_func_filename,
                                  in_matrix=out_catmatvec.outputs.out_file,
                                  out_file=fname_presuffix(
                                      unbiased_anat_filename,
                                      suffix='_shr_in_func_space'),
                                  environ=environ)
        allineated_anat_filename = out_allineate.outputs.out_file
        output_files.append(allineated_anat_filename)
    else:
        allineated_anat_filename = unbiased_anat_filename

    ############################################
    # Nonlinear registration anat -> mean func #
    ############################################
    # 3dWarp doesn't put the obliquity in the header, so do it manually
    # This step generates one file per slice and per time point, so we are
    # making sure they are removed at the end
    out_warp = warp(in_file=allineated_anat_filename,
                    oblique_parent=unbiased_func_filename,
                    interp='quintic',
                    gridset=unbiased_func_filename,
                    outputtype='NIFTI_GZ',
                    verbose=True,
                    environ=environ)
    registered_anat_filename = out_warp.outputs.out_file
    registered_anat_oblique_filename = fix_obliquity(registered_anat_filename,
                                                     unbiased_func_filename,
                                                     verbose=verbose)

    # Concatenate all the anat to func tranforms
    mat_filename = fname_presuffix(registered_anat_filename,
                                   suffix='_warp.mat',
                                   use_ext=False)
    # XXX Handle this correctly according to caching
    if not os.path.isfile(mat_filename):
        np.savetxt(mat_filename, [out_warp.runtime.stdout], fmt='%s')
        output_files.append(mat_filename)

    transform_filename = fname_presuffix(registered_anat_filename,
                                         suffix='_anat_to_func.aff12.1D',
                                         use_ext=False)
    if prior_rigid_body_registration:
        _ = catmatvec(in_file=[(mat_filename, 'ONELINE'),
                               (rigid_transform_file, 'ONELINE')],
                      oneline=True,
                      out_file=transform_filename)
    else:
        _ = catmatvec(in_file=[(mat_filename, 'ONELINE')],
                      oneline=True,
                      out_file=transform_filename)

    ##################################################
    # Per-slice non-linear registration func -> anat #
    ##################################################
    # Slice anatomical image
    anat_img = nibabel.load(registered_anat_oblique_filename)
    anat_n_slices = anat_img.header.get_data_shape()[2]
    sliced_registered_anat_filenames = []
    for slice_n in range(anat_n_slices):
        out_slicer = slicer(in_file=registered_anat_oblique_filename,
                            keep='{0} {0}'.format(slice_n),
                            out_file=fname_presuffix(
                                registered_anat_oblique_filename,
                                suffix='Sl%d' % slice_n),
                            environ=environ)
        oblique_slice = fix_obliquity(out_slicer.outputs.out_file,
                                      registered_anat_oblique_filename,
                                      verbose=verbose)
        sliced_registered_anat_filenames.append(oblique_slice)

    # Slice mean functional
    sliced_bias_corrected_filenames = []
    img = nibabel.load(func_filename)
    n_slices = img.header.get_data_shape()[2]
    for slice_n in range(n_slices):
        out_slicer = slicer(in_file=unbiased_func_filename,
                            keep='{0} {0}'.format(slice_n),
                            out_file=fname_presuffix(unbiased_func_filename,
                                                     suffix='Sl%d' % slice_n),
                            environ=environ)
        oblique_slice = fix_obliquity(out_slicer.outputs.out_file,
                                      unbiased_func_filename,
                                      verbose=verbose)
        sliced_bias_corrected_filenames.append(oblique_slice)

    # Below line is to deal with slices where there is no signal (for example
    # rostral end of some anatomicals)

    # The inverse warp frequently fails, Resampling can help it work better
    # XXX why specifically .1 in voxel_size ?
    voxel_size_z = anat_img.header.get_zooms()[2]
    resampled_registered_anat_filenames = []
    for sliced_registered_anat_filename in sliced_registered_anat_filenames:
        out_resample = resample(in_file=sliced_registered_anat_filename,
                                voxel_size=(voxel_size_x, voxel_size_y,
                                            voxel_size_z),
                                outputtype='NIFTI_GZ',
                                environ=environ)
        resampled_registered_anat_filenames.append(
            out_resample.outputs.out_file)

    resampled_bias_corrected_filenames = []
    for sliced_bias_corrected_filename in sliced_bias_corrected_filenames:
        out_resample = resample(in_file=sliced_bias_corrected_filename,
                                voxel_size=(voxel_size_x, voxel_size_y,
                                            voxel_size_z),
                                outputtype='NIFTI_GZ',
                                environ=environ)
        resampled_bias_corrected_filenames.append(
            out_resample.outputs.out_file)

    # single slice non-linear functional to anatomical registration
    warped_slices = []
    warp_filenames = []
    for (resampled_bias_corrected_filename,
         resampled_registered_anat_filename) in zip(
             resampled_bias_corrected_filenames,
             resampled_registered_anat_filenames):
        warped_slice = fname_presuffix(resampled_bias_corrected_filename,
                                       suffix='_qw')
        out_qwarp = qwarp(
            in_file=resampled_bias_corrected_filename,
            base_file=resampled_registered_anat_filename,
            iwarp=True,  # XXX: is this necessary
            noneg=True,
            blur=[0],
            nmi=True,
            noXdis=True,
            allineate=True,
            allineate_opts='-parfix 1 0 -parfix 2 0 -parfix 3 0 '
            '-parfix 4 0 -parfix 5 0 -parfix 6 0 '
            '-parfix 7 0 -parfix 9 0 '
            '-parfix 10 0 -parfix 12 0',
            out_file=warped_slice,
            environ=environ)
        warped_slices.append(out_qwarp.outputs.warped_source)
        warp_filenames.append(out_qwarp.outputs.source_warp)
        output_files.append(out_qwarp.outputs.base_warp)
        # There are files geenrated by the allineate option
        output_files.extend([
            fname_presuffix(out_qwarp.outputs.warped_source, suffix='_Allin'),
            fname_presuffix(out_qwarp.outputs.warped_source,
                            suffix='_Allin.nii',
                            use_ext=False),
            fname_presuffix(out_qwarp.outputs.warped_source,
                            suffix='_Allin.aff12.1D',
                            use_ext=False)
        ])

    # Resample the mean volume back to the initial resolution,
    voxel_size = nibabel.load(unbiased_func_filename).header.get_zooms()
    resampled_warped_slices = []
    for warped_slice in warped_slices:
        out_resample = resample(in_file=warped_slice,
                                voxel_size=voxel_size,
                                outputtype='NIFTI_GZ',
                                environ=environ)
        resampled_warped_slices.append(out_resample.outputs.out_file)

    # fix the obliquity
    resampled_warped_slices_oblique = []
    for (sliced_registered_anat_filename,
         resampled_warped_slice) in zip(sliced_registered_anat_filenames,
                                        resampled_warped_slices):
        oblique_slice = fix_obliquity(resampled_warped_slice,
                                      sliced_registered_anat_filename,
                                      verbose=verbose)
        resampled_warped_slices_oblique.append(oblique_slice)

    # slice functional
    sliced_func_filenames = []
    for slice_n in range(n_slices):
        out_slicer = slicer(in_file=allineated_filename,
                            keep='{0} {0}'.format(slice_n),
                            out_file=fname_presuffix(allineated_filename,
                                                     suffix='Sl%d' % slice_n),
                            environ=environ)
        oblique_slice = fix_obliquity(out_slicer.outputs.out_file,
                                      allineated_filename,
                                      verbose=verbose)
        sliced_func_filenames.append(oblique_slice)

    # Apply the precomputed warp slice by slice
    warped_func_slices = []
    for (sliced_func_filename, warp_filename) in zip(sliced_func_filenames,
                                                     warp_filenames):
        out_warp_apply = warp_apply(in_file=sliced_func_filename,
                                    master=sliced_func_filename,
                                    warp=warp_filename,
                                    out_file=fname_presuffix(
                                        sliced_func_filename, suffix='_qw'),
                                    environ=environ)
        warped_func_slices.append(out_warp_apply.outputs.out_file)

    # Finally, merge all slices !
    out_merge_func = merge(in_files=warped_func_slices,
                           outputtype='NIFTI_GZ',
                           environ=environ)

    # Fix the obliquity
    merged_oblique = fix_obliquity(out_merge_func.outputs.out_file,
                                   allineated_filename,
                                   verbose=verbose)

    # Update the fmri data
    setattr(session_data, "coreg_func_", merged_oblique)
    setattr(session_data, "coreg_anat_", registered_anat_oblique_filename)
    setattr(session_data, "coreg_transform_", transform_filename)
    os.chdir(current_dir)

    # Collect the outputs
    output_files.extend(sliced_registered_anat_filenames +
                        sliced_bias_corrected_filenames +
                        resampled_registered_anat_filenames +
                        resampled_bias_corrected_filenames + warped_slices +
                        warp_filenames + resampled_warped_slices_oblique +
                        sliced_func_filenames + warped_func_slices)
    if not caching:
        for out_file in output_files:
            if os.path.isfile(out_file):
                os.remove(out_file)
Beispiel #6
0
def _realign(func_filename,
             write_dir,
             caching=False,
             terminal_output='allatonce',
             environ=None):
    if environ is None:
        environ = {'AFNI_DECONFLICT': 'OVERWRITE'}

    if caching:
        memory = Memory(write_dir)
        clip_level = memory.cache(afni.ClipLevel)
        threshold = memory.cache(fsl.Threshold)
        volreg = memory.cache(afni.Volreg)
        allineate = memory.cache(afni.Allineate)
        copy = memory.cache(afni.Copy)
        copy_geom = memory.cache(fsl.CopyGeom)
        tstat = memory.cache(afni.TStat)
        for step in [threshold, volreg, allineate, tstat, copy, copy_geom]:
            step.interface().set_default_terminal_output(terminal_output)
    else:
        clip_level = afni.ClipLevel().run
        threshold = fsl.Threshold(terminal_output=terminal_output).run
        volreg = afni.Volreg(terminal_output=terminal_output).run
        allineate = afni.Allineate(terminal_output=terminal_output).run
        copy = afni.Copy(terminal_output=terminal_output).run
        copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run
        tstat = afni.TStat(terminal_output=terminal_output).run

    out_clip_level = clip_level(in_file=func_filename)

    out_threshold = threshold(in_file=func_filename,
                              thresh=out_clip_level.outputs.clip_val,
                              out_file=fname_presuffix(func_filename,
                                                       suffix='_thresholded',
                                                       newpath=write_dir))
    thresholded_filename = out_threshold.outputs.out_file

    out_volreg = volreg(  # XXX dfile not saved
        in_file=thresholded_filename,
        out_file=fname_presuffix(thresholded_filename,
                                 suffix='_volreg',
                                 newpath=write_dir),
        environ=environ,
        oned_file=fname_presuffix(thresholded_filename,
                                  suffix='_volreg.1Dfile.1D',
                                  use_ext=False,
                                  newpath=write_dir),
        oned_matrix_save=fname_presuffix(thresholded_filename,
                                         suffix='_volreg.aff12.1D',
                                         use_ext=False,
                                         newpath=write_dir))

    # Apply the registration to the whole head
    out_allineate = allineate(in_file=func_filename,
                              master=func_filename,
                              in_matrix=out_volreg.outputs.oned_matrix_save,
                              out_file=fname_presuffix(func_filename,
                                                       suffix='_volreg',
                                                       newpath=write_dir),
                              environ=environ)

    # 3dAllineate removes the obliquity. This is not a good way to readd it as
    # removes motion correction info in the header if it were an AFNI file...as
    # it happens it's NIfTI which does not store that so irrelevant!
    out_copy = copy(in_file=out_allineate.outputs.out_file,
                    out_file=fname_presuffix(out_allineate.outputs.out_file,
                                             suffix='_oblique',
                                             newpath=write_dir),
                    environ=environ)
    out_copy_geom = copy_geom(dest_file=out_copy.outputs.out_file,
                              in_file=out_volreg.outputs.out_file)

    oblique_allineated_filename = out_copy_geom.outputs.out_file

    # Create a (hopefully) nice mean image for use in the registration
    out_tstat = tstat(in_file=oblique_allineated_filename,
                      args='-mean',
                      out_file=fname_presuffix(oblique_allineated_filename,
                                               suffix='_tstat',
                                               newpath=write_dir),
                      environ=environ)

    # Remove intermediate outputs
    if not caching:
        for output_file in [
                thresholded_filename, out_volreg.outputs.oned_matrix_save,
                out_volreg.outputs.out_file, out_volreg.outputs.md1d_file,
                out_allineate.outputs.out_file
        ]:
            os.remove(output_file)
    return (oblique_allineated_filename, out_tstat.outputs.out_file,
            out_volreg.outputs.oned_file)
Beispiel #7
0
    def preprocess_channels_pipeline(self, **name_maps):
        pipeline = self.new_pipeline(
            'preprocess_channels',
            name_maps=name_maps,
            desc=("Convert channel signals in complex coords to polar coords "
                  "and combine"))

        if (self.provided('header_image') or
                self.branch('reorient_to_std') or
                self.parameter('force_channel_flip') is not None):
            # Read channel files reorient them into standard space and then
            # write back to directory
            list_channels = pipeline.add(
                'list_channels',
                ListDir(),
                inputs={
                    'directory': ('channels', multi_nifti_gz_format)})

            if self.parameter('force_channel_flip') is not None:
                force_flip = pipeline.add(
                    'flip_dims',
                    fsl.SwapDimensions(
                        new_dims=tuple(self.parameter('force_channel_flip'))),
                    inputs={
                        'in_file': (list_channels, 'files')},
                    iterfield=['in_file'])
                geom_dest_file = (force_flip, 'out_file')
            else:
                geom_dest_file = (list_channels, 'files')

            if self.provided('header_image'):
                # If header image is provided stomp its geometry over the
                # acquired channels
                copy_geom = pipeline.add(
                    'qsm_copy_geometry',
                    fsl.CopyGeom(
                        output_type='NIFTI_GZ'),
                    inputs={
                        'in_file': ('header_image', nifti_gz_format),
                        'dest_file': geom_dest_file},
                    iterfield=(['dest_file']),
                    requirements=[fsl_req.v('5.0.8')])
                reorient_in_file = (copy_geom, 'out_file')
            else:
                reorient_in_file = geom_dest_file

            if self.branch('reorient_to_std'):
                reorient = pipeline.add(
                    'reorient_channel',
                    fsl.Reorient2Std(
                        output_type='NIFTI_GZ'),
                    inputs={
                        'in_file': reorient_in_file},
                    iterfield=['in_file'],
                    requirements=[fsl_req.v('5.0.8')])
                copy_to_dir_in_files = (reorient, 'out_file')
            else:
                copy_to_dir_in_files = reorient_in_file

            copy_to_dir = pipeline.add(
                'copy_to_dir',
                CopyToDir(),
                inputs={
                    'in_files': copy_to_dir_in_files,
                    'file_names': (list_channels, 'files')})
            to_polar_in_dir = (copy_to_dir, 'out_dir')
        else:
            to_polar_in_dir = ('channels', multi_nifti_gz_format)

        pipeline.add(
            'to_polar',
            ToPolarCoords(
                in_fname_re=self.parameter('channel_fname_regex'),
                real_label=self.parameter('channel_real_label'),
                imaginary_label=self.parameter('channel_imag_label')),
            inputs={
                'in_dir': to_polar_in_dir},
            outputs={
                'mag_channels': ('magnitudes_dir', multi_nifti_gz_format),
                'phase_channels': ('phases_dir', multi_nifti_gz_format)})

        return pipeline
Beispiel #8
0
def compute_morpho_brain_mask(head_file,
                              brain_volume,
                              write_dir=None,
                              unifize=True,
                              caching=False,
                              verbose=True,
                              terminal_output='allatonce',
                              **unifize_kwargs):
    """
    Parameters
    ----------
    brain_volume : int
        Volume of the brain in mm3 used for brain extraction.
        Typically 400 for mouse and 1800 for rat.

    unifize : bool, optional
        If True, brain mask is computed using RATS Mathematical Morphology.
        Otherwise, a histogram-based brain segmentation is used.

    caching : bool, optional
        Wether or not to use caching.

    unifize_kwargs : dict, optional
        Is passed to nipype.interfaces.afni.Unifize.

    Returns
    -------
    path to brain extracted image.

    Notes
    -----
    RATS tool is used for brain extraction and has to be cited. For more
    information, see
    `RATS <http://www.iibi.uiowa.edu/content/rats-overview/>`_
    """
    if write_dir is None:
        write_dir = os.path.dirname(head_file)

    if interfaces.Info().version() is None:
        raise ValueError('Can not locate Rats')

    environ = {'AFNI_DECONFLICT': 'OVERWRITE'}

    if caching:
        memory = Memory(write_dir)
        clip_level = memory.cache(afni.ClipLevel)
        compute_mask = memory.cache(interfaces.MathMorphoMask)
        compute_mask.interface().set_default_terminal_output(terminal_output)
        copy = memory.cache(afni.Copy)
        copy.interface().set_default_terminal_output(terminal_output)
        copy_geom = memory.cache(fsl.CopyGeom)
    else:
        clip_level = afni.ClipLevel().run
        compute_mask = interfaces.MathMorphoMask(
            terminal_output=terminal_output).run
        copy = afni.Copy(terminal_output=terminal_output).run
        copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run

    if unifize:
        unifization_options = [
            '{}_{}'.format(k, v) for (k, v) in unifize_kwargs.items()
        ]
        suffix = 'unifized_' + '_'.join(unifization_options)

        file_to_mask = afni_unifize(head_file,
                                    write_dir,
                                    out_file=fname_presuffix(
                                        head_file,
                                        suffix=suffix,
                                        newpath=write_dir),
                                    caching=caching,
                                    terminal_output=terminal_output,
                                    verbose=verbose,
                                    environ=environ,
                                    **unifize_kwargs)
    else:
        file_to_mask = head_file

    out_clip_level = clip_level(in_file=file_to_mask)
    out_compute_mask = compute_mask(
        in_file=file_to_mask,
        out_file=fname_presuffix(file_to_mask,
                                 suffix='_rats_brain_mask',
                                 newpath=write_dir),
        volume_threshold=brain_volume,
        intensity_threshold=int(out_clip_level.outputs.clip_val))

    # RATS sometimes slightly modifies the affine
    same_geom = _check_same_geometry(out_compute_mask.outputs.out_file,
                                     head_file)
    if not same_geom:
        mask_file = fname_presuffix(out_compute_mask.outputs.out_file,
                                    suffix='_rough_geom',
                                    newpath=write_dir)
        out_copy = copy(in_file=out_compute_mask.outputs.out_file,
                        out_file=mask_file,
                        environ=environ)
        _ = copy_geom(dest_file=out_copy.outputs.out_file, in_file=head_file)
    else:
        mask_file = out_compute_mask.outputs.out_file

    # Remove intermediate output
    if not caching and unifize:
        os.remove(file_to_mask)
        if not same_geom:
            os.remove(out_compute_mask.outputs.out_file)

    return mask_file
Beispiel #9
0
def create_preprocess_mag_wf():
    preprocmag = pe.Workflow(name="preprocmag")
    preprocmag.config['execution']['remove_unnecessary_outputs'] = False

    # define inputs
    inputspec = pe.Node(ul.IdentityInterface(fields=['input_mag', # raw phase data
                                                     'frac', # BET franction (-f parameter)
                                                     'rest', # volumes of rest in block design
                                                     'task', # volumes of task in block design
                                                     ]),
                        name='inputspec')

    # convert image to float
    img2float = pe.MapNode(interface=fsl.ImageMaths(out_data_type='float', op_string='', suffix='_dtype'),
                           iterfield=['in_file'],
                           name='img2float')

    # motion correct each run
    volreg = pe.MapNode(interface=afni.Volreg(), name='volreg', iterfield='in_file')
    volreg.inputs.outputtype = 'NIFTI_GZ'

    # calculate relative motions
    calcrel = pe.MapNode(ul.Function(['in_file'], ['out_file'], calcrelmotion),
        name='calcrel', iterfield=['in_file'])

    #generate motion plots
    plotmc = pe.MapNode(interface=fsl.PlotMotionParams(), name='plotmc', iterfield='in_file')
    plotmc.inputs.in_source = 'fsl'
    plotmc.iterables = ("plot_type", ['rotations', 'translations', 'displacement'])

    # register each run to first volume of first run
    # A) extract the first volume of the first run
    extract_ref = pe.MapNode(interface=fsl.ExtractROI(t_size=1, t_min=0), name='extract_ref', iterfield=['in_file'])

    # B) registration
    align2first = pe.MapNode(interface=afni.Allineate(), name='align2first', iterfield=['in_file'])
    align2first.inputs.num_threads = 2
    align2first.inputs.out_matrix = 'align2first'

    # merge xfm from moco and first run alignment
    merge_xfm = pe.MapNode(interface=ul.Merge(2), name='merge_xfm', iterfield=['in1', 'in2'])

    # concatenate moco and alignment to run 1
    cat_xfm = pe.MapNode(interface=afni.CatMatvec(oneline=True), name='cat_xfm', iterfield=['in_file'])
    cat_xfm.inputs.out_file = 'concated_xfm.aff12.1D'

    # apply first volume registration and motion correction in a single step
    applyalign = pe.MapNode(interface=afni.Allineate(), name='applyalign', iterfield=['in_file', 'in_matrix'])
    applyalign.inputs.num_threads = 2
    applyalign.inputs.final_interpolation = 'nearestneighbour'
    applyalign.inputs.outputtype = 'NIFTI_GZ'

    # afni messes with the header (unobliques the data) this puts it back
    cpgeommoco = pe.MapNode(interface=fsl.CopyGeom(), name='cpgeommoco', iterfield=['dest_file', 'in_file'])

    # linear detrending prior to SNR calculation
    detrend = pe.MapNode(interface=pp.DetrendMag(), name='detrend', iterfield=['mag'])

    # get the mean functional of run 1 for brain extraction
    meanfunc = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                suffix='_mean'),
                       name='meanfunc', iterfield=['in_file'])

    # calculate the phase noise (takes in volume of activation, if none provided them assumes resting state)
    calcSNR = pe.MapNode(interface=pp.RestAverage(), name='calcSNR', iterfield=['func', 'rest', 'task'])

    # extract brain with fsl and save the mask
    extractor = pe.Node(interface=fsl.BET(), name="extractor")
    extractor.inputs.mask = True

    # apply the mask to all runs
    maskfunc = pe.MapNode(interface=fsl.ImageMaths(suffix='_bet',
                                                   op_string='-mas'),
                          iterfield=['in_file'],
                          name='maskfunc')

    # outputspec
    outputspec = pe.Node(ul.IdentityInterface(fields=['proc_mag','motion_par',
                                                      'motion_data', 'maxdisp_data' ,
                                                      'motion_plot', 'run_txfm',
                                                      'mask_file','mean_file','snr']),
                        name='outputspec')

    preprocmag = pe.Workflow(name='preprocmag')
    preprocmag.connect([(inputspec, img2float, [('input_mag', 'in_file')]),
                        (img2float, volreg, [('out_file', 'in_file')]),
                        (volreg, extract_ref, [('out_file', 'in_file')]),
                        (extract_ref, align2first, [('roi_file', 'in_file')]),
                        (extract_ref, align2first, [(('roi_file', pickfirst), 'reference')]),
                        (extract_ref, applyalign, [(('roi_file', pickfirst), 'reference')]),
                        (volreg, merge_xfm, [('oned_matrix_save', 'in2')]),
                        (align2first, merge_xfm, [('out_matrix', 'in1')]),
                        (merge_xfm, cat_xfm, [(('out', wraptuple), 'in_file')]),
                        (volreg,applyalign, [('out_file', 'in_file')]),
                        (volreg, calcrel, [('md1d_file', 'in_file')]),
                        (volreg, plotmc, [('oned_file', 'in_file')]),
                        (cat_xfm, applyalign, [('out_file', 'in_matrix')]),
                        (img2float, cpgeommoco, [('out_file', 'in_file')]),
                        (applyalign, cpgeommoco, [('out_file', 'dest_file')]),
                        (cpgeommoco, detrend, [('out_file', 'mag')]),
                        (detrend, meanfunc, [('detrended_mag', 'in_file')]),
                        (inputspec, calcSNR, [('rest', 'rest'),
                                              ('task', 'task')]),
                        (detrend, calcSNR, [('detrended_mag', 'func')]),
                        (inputspec, extractor, [('frac', 'frac')]),
                        (meanfunc, extractor, [(('out_file', pickfirst), 'in_file')]),
                        (cpgeommoco, maskfunc, [('out_file', 'in_file')]),
                        (extractor, maskfunc, [('mask_file', 'in_file2')]),
                        (maskfunc, outputspec, [('out_file', 'proc_mag')]),
                        (volreg, outputspec, [('oned_matrix_save', 'motion_par')]),
                        (volreg, outputspec, [('oned_file', 'motion_data')]),
                        (volreg, outputspec, [('md1d_file', 'maxdisp_data')]),
                        (plotmc, outputspec, [('out_file', 'motion_plot')]),
                        (cat_xfm, outputspec, [('out_file', 'run_txfm')]),
                        (extractor, outputspec, [('mask_file', 'mask_file')]),
                        (extractor, outputspec, [('out_file', 'mean_file')]),
                        (calcSNR, outputspec, [('tsnr', 'snr')]),
                        ])

    return preprocmag