Esempio n. 1
0
 def _list_outputs(self):
     outputs = self.output_spec().get()
     if isdefined(self.inputs.out_file):
         outputs['out_file'] = os.path.abspath(self.inputs.out_file)
     else:
         outputs['out_file'] = os.path.abspath(
             fname_presuffix(os.path.basename(self.inputs.in_file),
                             suffix='_histo_mask'))
     return outputs
Esempio n. 2
0
def _reset_affines(in_file,
                   out_file,
                   overwrite=False,
                   axes_to_permute=None,
                   axes_to_flip=None,
                   xyzscale=None,
                   center_mass=None,
                   verbose=1):
    """Sets the qform equal to the sform in the header, with optionally
       rescaling, setting the image center to 0, permuting or/and flipping axes
    """
    if not os.path.isfile(out_file) or overwrite:
        shutil.copy(in_file, out_file)
    else:
        return

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

    in_file = out_file
    if xyzscale is not None:
        refit = afni.Refit()
        refit.inputs.in_file = in_file
        refit.inputs.xyzscale = xyzscale
        refit.set_default_terminal_output(terminal_output)
        result = refit.run()
        in_file = result.outputs.out_file

    if center_mass is not None:
        set_center_mass = afni.CenterMass()
        set_center_mass.inputs.in_file = in_file
        set_center_mass.inputs.cm_file = fname_presuffix(out_file,
                                                         suffix='.txt',
                                                         use_ext=False)
        set_center_mass.inputs.set_cm = center_mass
        #        set_center_mass.set_default_terminal_output(terminal_output) # XXX BUG
        result = set_center_mass.run()
        in_file = result.outputs.out_file

    img = nibabel.load(in_file)
    header = img.header.copy()
    sform, code = header.get_sform(coded=True)

    if axes_to_flip:
        for axis in axes_to_flip:
            sform[axis] *= -1

    if axes_to_permute:
        for (axis1, axis2) in axes_to_permute:
            sform[[axis1, axis2]] = sform[[axis2, axis1]]

    header.set_sform(sform)
    header.set_qform(sform, int(code))
    nibabel.Nifti1Image(img.get_data(), sform, header).to_filename(out_file)
Esempio n. 3
0
def compute_mask_contour(mask_file, write_dir=None, out_file=None):
    mask_img = check_niimg(mask_file)
    vertices, _ = measure.marching_cubes(mask_img.get_data(),
                                         0)  #marching_cubes_lewiner
    vertices_minus = np.floor(vertices).astype(int)
    vertices_plus = np.ceil(vertices).astype(int)
    contour_data = np.zeros(mask_img.shape)
    contour_data[vertices_minus.T[0], vertices_minus.T[1],
                 vertices_minus.T[2]] = 1
    contour_data[vertices_plus.T[0], vertices_plus.T[1],
                 vertices_plus.T[2]] = 1
    contour_img = image.new_img_like(mask_img, contour_data)
    if write_dir is None:
        write_dir = os.getcwd()

    if out_file is None:
        out_file = fname_presuffix(mask_file,
                                   suffix='_countour',
                                   newpath=write_dir)
    contour_img.to_filename(out_file)
    return out_file
Esempio n. 4
0
def _slice_time(func_file,
                t_r,
                write_dir,
                caching=False,
                terminal_output='allatonce',
                environ=None):
    if environ is None:
        environ = {'AFNI_DECONFLICT': 'OVERWRITE'}

    if caching:
        memory = Memory(write_dir)
        tshift = memory.cache(afni.TShift)
        tshift.interface().set_default_terminal_output(terminal_output)
    else:
        tshift = afni.TShift(terminal_output=terminal_output).run

    out_tshift = tshift(in_file=func_file,
                        out_file=fname_presuffix(func_file,
                                                 suffix='_tshifted',
                                                 newpath=write_dir),
                        tpattern='altplus',
                        tr=str(t_r),
                        environ=environ)
    return out_tshift.outputs.out_file
Esempio n. 5
0
def coregister(unifized_anat_file,
               unbiased_m0_file,
               write_dir,
               anat_brain_file=None,
               m0_brain_file=None,
               prior_rigid_body_registration=False,
               apply_to_file=None,
               voxel_size_x=.1,
               voxel_size_y=.1,
               caching=False,
               verbose=True,
               **environ_kwargs):
    """
    Coregistration of the subject's M0 and anatomical images.
    The M0 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
    ----------
    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
    -------
    data : sklearn.datasets.base.Bunch
    Dictionary-like object, the interest attributes are :
        - `coreg_perf_` : str
                          Path to paths to the coregistered perfusion
                          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/>`_
    """
    environ = {'AFNI_DECONFLICT': 'OVERWRITE'}
    for (key, value) in environ_kwargs.items():
        environ[key] = value

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

    if caching:
        memory = Memory(write_dir)
        catmatvec = memory.cache(afni.CatMatvec)
    else:
        catmatvec = afni.CatMatvec().run

    output_files = []

    #############################################
    # Rigid-body registration anat -> mean func #
    #############################################
    if prior_rigid_body_registration:
        if anat_brain_file is None:
            raise ValueError("'anat_brain_mask_file' is needed for prior "
                             "rigid-body registration")
        if m0_brain_file is None:
            raise ValueError("'m0_brain_mask_file' is needed for prior "
                             "rigid-body registration")
        allineated_anat_file, rigid_transform_file = \
            _rigid_body_register(unifized_anat_file,
                                 unbiased_m0_file,
                                 write_dir, anat_brain_file,
                                 m0_brain_file,
                                 caching=caching,
                                 terminal_output=terminal_output,
                                 environ=environ)
        output_files.extend([rigid_transform_file, allineated_anat_file])
    else:
        allineated_anat_file = unifized_anat_file

    ############################################
    # Nonlinear registration anat -> mean func #
    ############################################
    registered_anat_oblique_file, mat_file =\
        _warp(allineated_anat_file, unbiased_m0_file, write_dir,
              caching=caching, verbose=verbose,
              terminal_output=terminal_output,
              environ=environ)

    # Concatenate all the anat to func tranforms
    output_files.append(mat_file)
    transform_file = fname_presuffix(registered_anat_oblique_file,
                                     suffix='_anat_to_func.aff12.1D',
                                     use_ext=False)
    _ = catmatvec(in_file=[(mat_file, 'ONELINE')],
                  oneline=True,
                  out_file=transform_file,
                  environ=environ)

    ##################################################
    # Per-slice non-linear registration func -> anat #
    ##################################################
    warped_m0_file, warp_files, warped_apply_to_file =\
        _per_slice_qwarp(unbiased_m0_file,
                         registered_anat_oblique_file,
                         voxel_size_x, voxel_size_y,
                         apply_to_file=apply_to_file,
                         verbose=verbose,
                         write_dir=write_dir,
                         caching=caching, terminal_output=terminal_output,
                         environ=environ)

    # Remove the intermediate outputs
    if not caching:
        for out_file in output_files:
            os.remove(out_file)

    return Bunch(coreg_apply_to_=warped_apply_to_file,
                 coreg_m0_=warped_m0_file,
                 coreg_anat_=registered_anat_oblique_file,
                 coreg_transform_=transform_file,
                 coreg_warps_=warp_files)
Esempio n. 6
0
def _func_to_template(func_coreg_filename,
                      template_filename,
                      write_dir,
                      func_to_anat_oned_filename,
                      anat_to_template_oned_filename,
                      anat_to_template_warp_filename,
                      voxel_size=None,
                      caching=False,
                      verbose=True):
    """ Applies successive transforms to coregistered functional to put it in
    template space.

    Parameters
    ----------
    coreg_func_filename : str
        Path to functional volume, coregistered to a common space with the
        anatomical volume.

    template_filename : str
        Template to register the functional to.

    func_to_anat_oned_filename : str
        Path to the affine 1D transform from functional to coregistration
        space.

    anat_to_template_oned_filename : str
        Path to the affine 1D transform from anatomical to template space.

    anat_to_template_warp_filename : str
        Path to the warp transform from anatomical to template space.

    voxel_size : 3-tuple of floats, optional
        Voxel size of the registered functional, 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 = {}
    if verbose:
        terminal_output = 'allatonce'
    else:
        terminal_output = 'none'

    if caching:
        memory = Memory(write_dir)
        resample = memory.cache(afni.Resample)
        catmatvec = memory.cache(afni.CatMatvec)
        allineate = memory.cache(afni.Allineate)
        warp_apply = memory.cache(afni.NwarpApply)
        for step in [resample, allineate, warp_apply]:
            step.interface().set_default_terminal_output(terminal_output)
    else:
        resample = afni.Resample(terminal_output=terminal_output).run
        catmatvec = afni.CatMatvec().run
        allineate = afni.Allineate(terminal_output=terminal_output).run
        warp_apply = afni.NwarpApply(terminal_output=terminal_output).run
        environ['AFNI_DECONFLICT'] = 'OVERWRITE'

    current_dir = os.getcwd()
    os.chdir(write_dir)  # XXX to remove
    normalized_filename = fname_presuffix(func_coreg_filename,
                                          suffix='_normalized')
    if voxel_size is None:
        func_template_filename = template_filename
    else:
        out_resample = resample(in_file=template_filename,
                                voxel_size=voxel_size,
                                outputtype='NIFTI_GZ',
                                environ=environ)
        func_template_filename = out_resample.outputs.out_file

    if anat_to_template_warp_filename is None:
        affine_transform_filename = fname_presuffix(func_to_anat_oned_filename,
                                                    suffix='_to_template')
        _ = catmatvec(in_file=[(anat_to_template_oned_filename, 'ONELINE'),
                               (func_to_anat_oned_filename, 'ONELINE')],
                      oneline=True,
                      out_file=affine_transform_filename,
                      environ=environ)
        _ = allineate(in_file=func_coreg_filename,
                      master=func_template_filename,
                      in_matrix=affine_transform_filename,
                      out_file=normalized_filename,
                      environ=environ)
    else:
        warp = "'{0} {1} {2}'".format(anat_to_template_warp_filename,
                                      anat_to_template_oned_filename,
                                      func_to_anat_oned_filename)

        _ = warp_apply(in_file=func_coreg_filename,
                       master=func_template_filename,
                       warp=warp,
                       out_file=normalized_filename,
                       environ=environ)
    os.chdir(current_dir)
    return normalized_filename
Esempio n. 7
0
def func_to_anat(func_filename, anat_filename, tr, write_dir, caching=False):
    """
    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). This pipeline includes
    slice timing.
    """
    if caching:
        memory = Memory(write_dir)
        tshift = memory.cache(afni.TShift)
        clip_level = memory.cache(afni.ClipLevel)
        threshold = memory.cache(fsl.Threshold)
        volreg = memory.cache(afni.Volreg)
        allineate = memory.cache(afni.Allineate)
        copy_geom = memory.cache(fsl.CopyGeom)
        bias_correct = memory.cache(ants.N4BiasFieldCorrection)
        tstat = memory.cache(afni.TStat)
        rats = memory.cache(RatsMM)
        calc = memory.cache(afni.Calc)
        allineate = memory.cache(afni.Allineate)
        allineate2 = memory.cache(afni.Allineate)
        unifize = memory.cache(afni.Unifize)
        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(fsl.Merge)
    else:
        tshift = afni.TShift().run
        clip_level = afni.ClipLevel().run
        threshold = fsl.Threshold().run
        volreg = afni.Volreg().run
        allineate = afni.Allineate().run
        allineate2 = afni.Allineate().run  # TODO: remove after fixed bug
        copy_geom = fsl.CopyGeom().run
        bias_correct = ants.N4BiasFieldCorrection().run
        tstat = afni.TStat().run
        rats = RatsMM().run
        calc = afni.Calc().run
        allineate = afni.Allineate().run
        unifize = afni.Unifize().run
        catmatvec = afni.CatMatvec().run
        warp = afni.Warp().run
        resample = afni.Resample().run
        slicer = afni.ZCutUp().run
        warp_apply = afni.NwarpApply().run
        qwarp = afni.Qwarp().run
        merge = fsl.Merge().run

    # Correct slice timing
    os.chdir(write_dir)
    out_tshift = tshift(in_file=func_filename,
                        outputtype='NIFTI_GZ',
                        tpattern='altplus',
                        tr=str(tr))
    tshifted_filename = out_tshift.outputs.out_file

    # Register to the first volume
    # XXX why do you need a thresholded image ?
    out_clip_level = clip_level(in_file=tshifted_filename)
    out_threshold = threshold(in_file=tshifted_filename,
                              thresh=out_clip_level.outputs.clip_val)
    thresholded_filename = out_threshold.outputs.out_file

    oned_filename = fname_presuffix(thresholded_filename,
                                    suffix='Vr.1Dfile.1D',
                                    use_ext=False)
    oned_matrix_filename = fname_presuffix(thresholded_filename,
                                           suffix='Vr.aff12.1D',
                                           use_ext=False)
    out_volreg = volreg(
        in_file=thresholded_filename,
        outputtype='NIFTI_GZ',
        oned_file=oned_filename,  # XXX dfile not saved
        oned_matrix_save=oned_matrix_filename)
    # XXX: bad output: up and down on y-axis

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

    # 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

    # XXX: bad output: up and down on y-axis

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

    # Correct the functional average for intensities bias
    out_bias_correct = bias_correct(input_image=averaged_filename, dimension=3)
    unbiased_func_filename = out_bias_correct.outputs.output_image

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

    # Mask the mean functional volume outside the brain.
    out_clip_level = clip_level(in_file=unbiased_func_filename)
    # XXX bad: brain mask cut
    out_rats = rats(in_file=unbiased_func_filename,
                    volume_threshold=400,
                    intensity_threshold=int(out_clip_level.outputs.clip_val))
    out_cacl = calc(in_file_a=unbiased_func_filename,
                    in_file_b=out_rats.outputs.out_file,
                    expr='a*b',
                    outputtype='NIFTI_GZ')

    # Compute the transformation from the functional image to the anatomical
    # XXX: why in this sense
    out_allineate = allineate2(
        in_file=out_cacl.outputs.out_file,
        reference=unbiased_anat_filename,
        out_matrix=fname_presuffix(out_cacl.outputs.out_file,
                                   suffix='_shr.aff12.1D',
                                   use_ext=False),
        center_of_mass='',
        warp_type='shift_rotate',
        out_file=fname_presuffix(out_cacl.outputs.out_file, suffix='_shr'))
    rigid_transform_file = out_allineate.outputs.out_matrix

    # apply the inverse transformation to register to the anatomical volume
    catmatvec_out_file = fname_presuffix(rigid_transform_file, suffix='INV')
    if not os.path.isfile(catmatvec_out_file):
        _ = catmatvec(in_file=[(rigid_transform_file, 'I')],
                      oneline=True,
                      out_file=catmatvec_out_file)
        # XXX not cached I don't understand why
    out_allineate = allineate(in_file=unbiased_anat_filename,
                              master=unbiased_func_filename,
                              in_matrix=catmatvec_out_file,
                              out_file=fname_presuffix(
                                  unbiased_anat_filename,
                                  suffix='_shr_in_func_space'))

    # suppanatwarp="$base"_BmBe_shr.aff12.1D

    # Non-linear registration
    # XXX what is the difference between Warp and 3dQwarp?
    out_warp = warp(in_file=out_allineate.outputs.out_file,
                    oblique_parent=unbiased_func_filename,
                    interp='quintic',
                    gridset=unbiased_func_filename,
                    outputtype='NIFTI_GZ',
                    verbose=True)
    registered_anat_filename = out_warp.outputs.out_file
    mat_filename = fname_presuffix(registered_anat_filename,
                                   suffix='_warp.mat',
                                   use_ext=False)
    if not os.path.isfile(mat_filename):
        np.savetxt(mat_filename, [out_warp.runtime.stdout], fmt='%s')

    # 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
    registered_anat_oblique_filename = fix_obliquity(registered_anat_filename,
                                                     unbiased_func_filename,
                                                     overwrite=False)

    # 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} {1}'.format(slice_n, slice_n),
                            out_file=fname_presuffix(
                                registered_anat_oblique_filename,
                                suffix='Sl%d' % slice_n))
        sliced_registered_anat_filenames.append(out_slicer.outputs.out_file)

    # 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} {1}'.format(slice_n, slice_n),
                            out_file=fname_presuffix(unbiased_func_filename,
                                                     suffix='Sl%d' % slice_n))
        sliced_bias_corrected_filenames.append(out_slicer.outputs.out_file)

    # 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
    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=(.1, .1, voxel_size_z),
                                outputtype='NIFTI_GZ')
        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=(.1, .1, voxel_size_z),
                                outputtype='NIFTI_GZ')
        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,
                          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)
        warped_slices.append(out_qwarp.outputs.warped_source)
        warp_filenames.append(out_qwarp.outputs.source_warp)

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

    # fix the obliquity
    for (resampled_registered_anat_filename,
         resampled_warped_slice) in zip(resampled_registered_anat_filenames,
                                        resampled_warped_slices):
        _ = fix_obliquity(resampled_warped_slice,
                          resampled_registered_anat_filename)

    # Merge all slices !
#    out_merge_mean = merge(in_files=resampled_warped_slices, dimension='z')

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

    # resample functional slices
    resampled_func_filenames = []
    for sliced_func_filename in sliced_func_filenames:
        out_resample = resample(in_file=sliced_func_filename,
                                voxel_size=(.1, .1, voxel_size_z),
                                outputtype='NIFTI_GZ')
        resampled_func_filenames.append(out_resample.outputs.out_file)

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

    # Fix the obliquity
    # XXX why no resampling back before ?
    for (resampled_registered_anat_filename,
         warped_func_slice) in zip(resampled_registered_anat_filenames,
                                   warped_func_slices):
        _ = fix_obliquity(warped_func_slice,
                          resampled_registered_anat_filename)

    # Finally, merge all slices !
    out_merge_func = merge(in_files=warped_func_slices, dimension='z')
    out_merge_anat = merge(in_files=resampled_registered_anat_filenames,
                           dimension='z')
    return (out_merge_func.outputs.merged_file,
            out_merge_anat.outputs.merged_file)
Esempio n. 8
0
            sammba_dir = os.path.join(
                os.path.expanduser(
                    '~/inhouse_mouse_perf_to_reoriented_head100'), mouse_id)
        else:
            raise ValueError('Unknown user')

        template_ventricles_mask_file = os.path.join(
            os.path.expanduser(
                '~/appning_data/my_home/inhouse_mouse_perf_to_reoriented_head100/labels100_ventricles_mask.nii.gz'
            ))

        # Create a precise brain mask, by combining RATS and SPM
        ventricles_mask_file = os.path.join(spm_dir,
                                            'manual_ventricles_mask.nii')

        sammba_registered_ventricles_file = fname_presuffix(
            ventricles_mask_file, suffix='_allineated', newpath=sammba_dir)
        allineate = afni.Allineate().run
        out_allineate = allineate(in_file=ventricles_mask_file,
                                  master=template_ventricles_mask_file,
                                  in_matrix=os.path.join(
                                      sammba_dir,
                                      'anat_n0_unifized_masked_aff.aff12.1D'),
                                  out_file=sammba_registered_ventricles_file,
                                  interpolation='nearestneighbour',
                                  environ={'AFNI_DECONFLICT': 'OVERWRITE'})

        spm_registered_ventricles_file = os.path.join(
            spm_dir, 'wmanual_ventricles_mask.nii')

        spm_registered_ventricles_data = check_niimg(
            spm_registered_ventricles_file).get_data()
Esempio n. 9
0
def fix_obliquity(to_fix_filename,
                  reference_filename,
                  caching=False,
                  caching_dir=None,
                  clear_memory=False,
                  overwrite=False):
    if caching:
        memory = Memory(caching_dir)

    if caching_dir is None:
        caching_dir = os.getcwd()

    if overwrite:
        environ = {'AFNI_DECONFLICT': 'OVERWRITE'}
    else:
        environ = {}

    if caching:
        copy = memory.cache(afni.Copy)
    else:
        copy = afni.Copy().run

    tmp_folder = os.path.join(caching_dir, 'tmp')
    if not os.path.isdir(tmp_folder):
        os.makedirs(tmp_folder)

    reference_basename = os.path.basename(reference_filename)
    orig_reference_filename = fname_presuffix(os.path.join(
        tmp_folder, reference_basename),
                                              suffix='+orig.BRIK',
                                              use_ext=False)
    if not os.path.isfile(orig_reference_filename) or overwrite:
        out_copy_oblique = copy(in_file=reference_filename,
                                out_file=orig_reference_filename,
                                environ=environ)
        orig_reference_filename = out_copy_oblique.outputs.out_file

    to_fix_basename = os.path.basename(to_fix_filename)
    orig_to_fix_filename = fname_presuffix(os.path.join(
        tmp_folder, to_fix_basename),
                                           suffix='+orig.BRIK',
                                           use_ext=False)
    if not os.path.isfile(orig_to_fix_filename) or overwrite:
        out_copy = copy(in_file=to_fix_filename,
                        out_file=orig_to_fix_filename,
                        environ=environ)
        orig_to_fix_filename = out_copy.outputs.out_file

    if caching:
        refit = memory.cache(afni.Refit)
    else:
        refit = afni.Refit().run

    out_refit = refit(in_file=orig_to_fix_filename,
                      atrcopy=(orig_reference_filename, 'IJK_TO_DICOM_REAL'))

    out_copy = copy(in_file=out_refit.outputs.out_file,
                    environ={'AFNI_DECONFLICT': 'OVERWRITE'},
                    out_file=to_fix_filename)

    if clear_memory:
        shutil.rmtree(tmp_folder)
        memory.clear_previous_run()

    return out_copy.outputs.out_file
Esempio n. 10
0
def copy_geometry(filename_to_copy,
                  filename_to_change,
                  out_filename=None,
                  copy_shape=True,
                  in_place=True,
                  allow_resampling=False):
    """ Mimics FSL command fslcpgeom to copy geometry information from header.

    filename_to_copy : str
        Path to the image with the header information to copy.

    to_change_filename : str
        Path to the image with the new geometry.

    out_filename : str or None, optional
        Path to save the image with the changed header to.

    copy_shape : bool, optional
        If False, image data shape is not copied.

    in_place : bool, optional
        If False, a new image is created with the copied geometry information.

    allow_resampling : bool, optional
        If True, resampling is done when the two images have different shapes.
    """
    img_to_copy = nibabel.load(filename_to_copy)
    img_to_change = nibabel.load(filename_to_change)
    header_to_copy = img_to_copy.header
    header_to_change = img_to_change.header
    new_header = header_to_change.copy()
    geometry_keys = [
        'sform_code', 'qform_code', 'quatern_b', 'quatern_c', 'quatern_d',
        'qoffset_x', 'qoffset_y', 'qoffset_z', 'srow_x', 'srow_y', 'srow_z'
    ]
    data_to_change = img_to_change.get_data()
    if copy_shape:
        geometry_keys += ['dim']
        geometry_keys += ['dim_info']
        geometry_keys += ['slice_end']
        target_shape = img_to_copy.get_data().shape
        if data_to_change.shape != target_shape:
            if allow_resampling:
                img_to_change = image.resample_to_img(img_to_change,
                                                      img_to_copy)
                data_to_copy = img_to_change.get_data()
                data_to_change = np.squeeze(
                    data_to_copy[..., :header_to_copy['slice_end'] + 1])
            else:
                raise ValueError('images have different shapes: {0} and {1}. '
                                 'You need to set `allow_resampling` to True. '
                                 ''.format(data_to_change.shape, target_shape))
    for key in geometry_keys:
        new_header[key] = header_to_copy[key]

    new_header['pixdim'][:4] = header_to_copy['pixdim'][:4]
    new_img = nibabel.Nifti1Image(data_to_change,
                                  img_to_copy.affine,
                                  header=new_header)

    if not in_place:
        if out_filename is None:
            out_filename = fname_presuffix(filename_to_change,
                                           suffix='copied_geom')
    else:
        out_filename = filename_to_change
    new_img.to_filename(out_filename)
    return out_filename
Esempio n. 11
0
def fix_obliquity(to_fix_filename,
                  reference_filename,
                  caching=False,
                  caching_dir=None,
                  overwrite=False,
                  verbose=True,
                  environ=None):
    if caching_dir is None:
        caching_dir = os.getcwd()
    if caching:
        memory = Memory(caching_dir)

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

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

    if caching:
        copy = memory.cache(afni.Copy)
        refit = memory.cache(afni.Refit)
        copy.interface().set_default_terminal_output(terminal_output)
        refit.interface().set_default_terminal_output(terminal_output)
    else:
        copy = afni.Copy(terminal_output=terminal_output).run
        refit = afni.Refit(terminal_output=terminal_output).run

    tmp_folder = os.path.join(caching_dir, 'tmp')
    if not os.path.isdir(tmp_folder):
        os.makedirs(tmp_folder)

    reference_basename = os.path.basename(reference_filename)
    orig_reference_filename = fname_presuffix(os.path.join(
        tmp_folder, reference_basename),
                                              suffix='+orig.BRIK',
                                              use_ext=False)
    out_copy_oblique = copy(in_file=reference_filename,
                            out_file=orig_reference_filename,
                            environ=environ)
    orig_reference_filename = out_copy_oblique.outputs.out_file

    to_fix_basename = os.path.basename(to_fix_filename)
    orig_to_fix_filename = fname_presuffix(os.path.join(
        tmp_folder, to_fix_basename),
                                           suffix='+orig.BRIK',
                                           use_ext=False)
    out_copy = copy(in_file=to_fix_filename,
                    out_file=orig_to_fix_filename,
                    environ=environ)
    orig_to_fix_filename = out_copy.outputs.out_file

    out_refit = refit(in_file=orig_to_fix_filename,
                      atrcopy=(orig_reference_filename, 'IJK_TO_DICOM_REAL'))

    out_copy = copy(in_file=out_refit.outputs.out_file,
                    out_file=fname_presuffix(to_fix_filename,
                                             suffix='_oblique'),
                    environ=environ)

    if not caching:
        shutil.rmtree(tmp_folder)

    return out_copy.outputs.out_file
Esempio n. 12
0
    def _run_interface(self, runtime):
        if isdefined(self.inputs.intensity_threshold):
            threshold = self.inputs.intensity_threshold
            img = image.math_img('img>{0}'.format(threshold),
                                 img=self.inputs.in_file)
        else:
            img = nibabel.load(self.inputs.in_file)

        lower_cutoff = self.inputs.upper_cutoff - 0.05
        mask_img = masking.compute_epi_mask(
            img,
            lower_cutoff=lower_cutoff,
            upper_cutoff=self.inputs.upper_cutoff,
            connected=self.inputs.connected,
            opening=self.inputs.opening)
        mask_data = mask_img.get_data()
        n_voxels_mask = np.sum(mask_data > 0)

        # Find the optimal lower cutoff
        affine_det = np.abs(np.linalg.det(mask_img.affine[:3, :3]))
        n_voxels_min = int(self.inputs.volume_threshold * .9 / affine_det)
        while (n_voxels_mask < n_voxels_min) and (lower_cutoff >
                                                  self.inputs.lower_cutoff):
            lower_cutoff -= .05
            mask_img = masking.compute_epi_mask(
                img,
                lower_cutoff=lower_cutoff,
                upper_cutoff=self.inputs.upper_cutoff,
                connected=self.inputs.connected,
                opening=self.inputs.opening)
            mask_data = mask_img.get_data()
            n_voxels_mask = np.sum(mask_data > 0)
            if self.inputs.verbose:
                print('volume {0}, lower_cutoff {1}'.format(
                    n_voxels_mask * affine_det, lower_cutoff))

        n_voxels_max = int(self.inputs.volume_threshold * 1.1 / affine_det)
        previous_n_voxels_mask = copy.copy(lower_cutoff)
        while (n_voxels_mask > n_voxels_max) and (
                previous_n_voxels_mask >= n_voxels_mask) and (
                    lower_cutoff + 0.01 < self.inputs.upper_cutoff):
            lower_cutoff += .01
            mask_img = masking.compute_epi_mask(
                img,
                lower_cutoff=lower_cutoff,
                upper_cutoff=self.inputs.upper_cutoff,
                connected=self.inputs.connected,
                opening=self.inputs.opening)
            mask_data = mask_img.get_data()
            n_voxels_mask = np.sum(mask_data > 0)
            if self.inputs.verbose:
                print('volume {0}, lower_cutoff {1}'.format(
                    n_voxels_mask * affine_det, lower_cutoff))

        else:
            if n_voxels_mask < n_voxels_min:
                lower_cutoff -= .01
                mask_img = masking.compute_epi_mask(
                    img,
                    lower_cutoff=lower_cutoff,
                    upper_cutoff=self.inputs.upper_cutoff,
                    connected=self.inputs.connected,
                    opening=self.inputs.opening)
                mask_data = mask_img.get_data()
                n_voxels_mask = np.sum(mask_data > 0)
                if self.inputs.verbose:
                    print('volume {0}, lower_cutoff {1}'.format(
                        n_voxels_mask * affine_det, lower_cutoff))

        # Find the optimal opening
        n_voxels_max = int(self.inputs.volume_threshold * 1.5 / affine_det)
        opening = 0
        while n_voxels_mask > n_voxels_max and opening < self.inputs.opening:
            opening += 1
            mask_img = masking.compute_epi_mask(
                img,
                lower_cutoff=lower_cutoff,
                upper_cutoff=self.inputs.upper_cutoff,
                connected=self.inputs.connected,
                opening=opening)
            mask_data = mask_img.get_data()
            n_voxels_mask = np.sum(mask_data > 0)
            if self.inputs.verbose:
                print('volume {0}, lower_cutoff {1}, opening {2}'.format(
                    n_voxels_mask * affine_det, lower_cutoff, opening))

        # Find the optimal closing
        iterations = 0
        n_voxels_min = int(self.inputs.volume_threshold * .8 / affine_det)
        while (n_voxels_mask < n_voxels_min) and (iterations <
                                                  self.inputs.closing):
            iterations += 1
            for structure_size in range(1, 4):
                structure = generate_binary_structure(3, structure_size)
                mask_data = binary_closing(mask_data,
                                           structure=structure,
                                           iterations=iterations)
                n_voxels_mask = np.sum(mask_data > 0)
                if self.inputs.verbose:
                    print('volume {0}, lower_cutoff {1}, opening {2}, closing '
                          '{3}'.format(n_voxels_mask * affine_det,
                                       lower_cutoff, opening, iterations))
                if n_voxels_mask > n_voxels_min:
                    break

        if self.inputs.verbose:
            print('volume {0}, lower_cutoff {1}, opening {2}, closing '
                  '{3}'.format(n_voxels_mask * affine_det, lower_cutoff,
                               opening, iterations))

        # Fill holes
        n_voxels_min = int(self.inputs.volume_threshold / affine_det)
        if n_voxels_mask < n_voxels_min:
            for structure_size in range(1, 4):
                structure = generate_binary_structure(3, structure_size)
                mask_data = binary_fill_holes(mask_data, structure=structure)
                n_voxels_mask = np.sum(mask_data > 0)
                if self.inputs.verbose:
                    print('volume {0}, structure_size {1}'.format(
                        n_voxels_mask * affine_det, structure_size))
                if n_voxels_mask > n_voxels_min:
                    break

        # Dilation if needed
        size = self.inputs.dilation_size
        for n in range(3):
            if n_voxels_mask < n_voxels_min * .9:
                previous_n_voxels_mask = copy.copy(n_voxels_mask)
                mask_data = grey_dilation(mask_data, size=size)
                n_voxels_mask = np.sum(mask_data > 0)
                if n_voxels_mask == previous_n_voxels_mask:
                    size2 = (size[0] + 1, size[1] + 1, size[2] + 1)
                    mask_data = grey_dilation(mask_data, size=size2)
                    n_voxels_mask = np.sum(mask_data > 0)

                if self.inputs.verbose:
                    print('volume {0}, grey dilation {1}'.format(
                        n_voxels_mask * affine_det, n))
            else:
                break

        # Fill holes
        for structure_size in range(1, 4):
            structure = generate_binary_structure(3, structure_size)
            mask_data = binary_fill_holes(mask_data, structure=structure)
            n_voxels_mask = np.sum(mask_data > 0)

        if self.inputs.verbose:
            print('final volume {0}'.format(n_voxels_mask * affine_det))

        mask_img = image.new_img_like(mask_img, mask_data, mask_img.affine)
        if isdefined(self.inputs.out_file):
            mask_img.to_filename(os.path.abspath(self.inputs.out_file))
        else:
            mask_img.to_filename(
                os.path.abspath(
                    fname_presuffix(os.path.basename(self.inputs.in_file),
                                    suffix='_histo_mask')))
        return runtime
Esempio n. 13
0
 memory = Memory(write_dir)
 mm = memory.cache(MathMorphoMask)
 if 'Bj1' in anat_file:
     brain_mask_file = compute_brain_mask(anat_file,
                                          400,
                                          os.path.join(
                                              output_dir, 'custom_masks'),
                                          bias_correct=False,
                                          caching=True)
     registrator.fit_anat(anat_file, brain_mask_file=brain_mask_file)
 elif 'Xx1' in anat_file:
     out_mm = mm(in_file=anat_file,
                 volume_threshold=400,
                 intensity_threshold=1900,
                 out_file=fname_presuffix(anat_file,
                                          newpath=write_dir,
                                          suffix='_brain_mask'))
     registrator.fit_anat(anat_file,
                          brain_mask_file=out_mm.outputs.out_file)
 elif 'y11' in anat_file:
     n4_file = _bias_correct(anat_file, write_dir=write_dir, caching=True)
     out_mm = mm(in_file=n4_file,
                 volume_threshold=400,
                 intensity_threshold=900,
                 out_file=fname_presuffix(n4_file,
                                          newpath=write_dir,
                                          suffix='_brain_mask'))
     registrator.fit_anat(anat_file,
                          brain_mask_file=out_mm.outputs.out_file)
 else:
     registrator.fit_anat(anat_file)
Esempio n. 14
0
    anat_files.remove(
        os.path.expanduser('~/nilearn_data/mrm_2010/C57_ab1_invivo.nii.gz'))

    # Generate random transforms
    rand_gen = np.random.RandomState(12)
    idenity_transform = np.zeros((43, ))
    idenity_transform[6:9] = np.ones((3, ))
    std = .005 * np.ones((43, ))  # 0.025
    std[:6] = 0.1
    std[6:9] = 0.02
    std[9:12] = 0.01
    transforms = idenity_transform + rand_gen.randn(len(anat_files), 43) * std
    for anat_file, transform in zip(anat_files, transforms):
        atlas_file = anat_file.replace('C57', 'Atlas')
        reoriented_anat_file = fname_presuffix(anat_file,
                                               newpath=spm_dir,
                                               suffix='.nii',
                                               use_ext=False)
        if 'ab2' in anat_file:
            raw_atlas_file = atlas_file.replace('ab2', 'Ab2')
        elif 'y81' in anat_file:
            raw_atlas_file = atlas_file.replace('Invivo', 'invivo')
        else:
            raw_atlas_file = atlas_file

        reoriented_atlas_file = fname_presuffix(raw_atlas_file,
                                                newpath=spm_dir,
                                                suffix='.nii',
                                                use_ext=False)
        print(reoriented_anat_file, reoriented_atlas_file)
        param_file = fname_presuffix(anat_file,
                                     newpath=sammba_transformed_dir,
Esempio n. 15
0
def fetch_atlas_dorr_2008(image_format='nifti',
                          downsample='30',
                          data_dir=None,
                          url=None,
                          resume=True,
                          verbose=1):
    """Download and load Dorr et al. atlas and average (dated 2008)

    Parameters
    ----------
    image_format : one of {'nifti', 'minc'}, optional
        Format to download

    downsample : one of {'30', '100'}, optional
        Downsampling resolution in microns.

    data_dir : str, optional
        Path of the data directory. Use to forec data storage in a non-
        standard location. Default: None (meaning: default)

    url: string, optional
        Download URL of the dataset. Overwrite the default URL.

    resume : bool
        whether to resumed download of a partly-downloaded file.

    verbose : int
        verbosity level (0 means no message).

    Returns
    -------
    data: sklearn.datasets.base.Bunch
        dictionary-like object, contains:

        - 't2' : str, path to nifti file containing the T2 weighted average.

        - 'maps' : str, path to nifti file containing regions definition.

        - 'names' : str list containing the names of the regions.

        - 'labels' : int list containing the label value of each region.

        - 'description' : description about the atlas and the template.

    References
    ----------

    A.E. Dorr, J.P. Lerch, S. Spring, N. Kabani and R.M. Henkelman. "High
    resolution three dimensional brain atlas using an average magnetic
    resonance image of 40 adult C57Bl/6j mice", NeuroImage 42(1):60-69, 2008.

    See http://www.mouseimaging.ca/research/mouse_atlas.html for more
    information on this parcellation.

    Licence: Unknown
    """
    if image_format not in ['nifti', 'minc']:
        raise ValueError("Images format must be 'nifti' or 'minc', you "
                         "entered {0}".format(image_format))

    if downsample not in ['30', '100']:
        raise ValueError("'downsample' must be '30' or '100', you "
                         "provided {0}".format(downsample))

    if url is None:
        if image_format == 'minc':
            url = [
                'http://www.mouseimaging.ca/mnc/C57Bl6j_mouse_atlas/',
                'http://www.mouseimaging.ca/mnc/C57Bl6j_mouse_atlas/',
                'http://www.mouseimaging.ca/research/C57Bl6j_mouse_atlas/'
            ]
        else:
            url = [
                'http://repo.mouseimaging.ca/repo/Dorr_2008_nifti/',
                'http://repo.mouseimaging.ca/repo/Dorr_2008_nifti/',
                'http://www.mouseimaging.ca/research/C57Bl6j_mouse_atlas/'
            ]

    if image_format == 'minc':
        files = [
            'male-female-mouse-atlas.mnc', 'c57_fixed_labels_resized.mnc',
            'c57_brain_atlas_labels.csv'
        ]
    else:
        files = [
            'Dorr_2008_average.nii.gz', 'Dorr_2008_labels.nii.gz',
            'c57_brain_atlas_labels.csv'
        ]

    files = [(f, u + f, {}) for f, u in zip(files, url)]

    dataset_name = 'dorr_2008'
    data_dir = _get_dataset_dir(dataset_name,
                                data_dir=data_dir,
                                verbose=verbose)
    files_ = _fetch_files(data_dir, files, resume=resume, verbose=verbose)

    fdescr = _get_dataset_descr(dataset_name)
    csv_data = np.recfromcsv(files_[2],
                             skip_header=True,
                             names=('roi_id', 'roi_label', 'right_index',
                                    'left_index'))

    #TODO try dictionary with their region id as key and name as value
    left_rois = []
    right_rois = []
    lateral_rois = []
    for (idx, label, right_index, left_index) in csv_data:
        label = label.decode('UTF-8')  # for python3
        if right_index == left_index:
            lateral_rois.append((label, right_index))
        else:
            left_rois.append(('L {}'.format(label), left_index))
            right_rois.append(('R {}'.format(label), right_index))

    rois = lateral_rois + right_rois + left_rois
    labels, indices = map(list, zip(*rois))
    t2 = files_[0]
    maps = files_[1]
    if downsample == '100':
        t2_img = nibabel.load(t2)
        maps_img = check_niimg(maps, dtype=int)
        t2 = fname_presuffix(t2, suffix='_100um')
        maps = fname_presuffix(maps, suffix='_100um')
        if not os.path.isfile(t2):
            target_affine = np.eye(3) * .1
            t2_img = image.resample_img(t2_img, target_affine)
            t2_img.to_filename(t2)
        if not os.path.isfile(maps):
            maps_img = image.resample_img(maps_img,
                                          target_affine,
                                          interpolation='nearest')
            maps_img.to_filename(maps)

    params = dict(t2=t2,
                  maps=maps,
                  names=np.array(labels)[np.argsort(indices)],
                  labels=np.sort(indices),
                  description=fdescr)

    return Bunch(**params)
    '~/nilearn_data/mrm_2010/correct_headers/Average_template_invivo_corrected.nii.gz'
)
for (in_file, out_file) in zip(
    [template_file, template_brain_mask_file, template_atlas_file], [
        correct_template_file, correct_template_brain_mask_file,
        correct_template_atlas_file
    ]):
    img = nibabel.load(in_file)
    header = img.header.copy()
    qform = header.get_qform()
    header.set_sform(qform, 1)
    nibabel.Nifti1Image(img.get_data(), qform, header).to_filename(out_file)

for anat_file in anat_files:
    correct_anat_file = fname_presuffix(anat_file,
                                        prefix='correct_headers/',
                                        suffix='_corrected')

    atlas_file = anat_file.replace('C57', 'Atlas')
    if 'y81' in anat_file:
        raw_atlas_file = atlas_file.replace('Invivo', 'invivo')

    correct_atlas_file = fname_presuffix(atlas_file,
                                         prefix='correct_headers/',
                                         suffix='_corrected')
    for (in_file, out_file) in zip([atlas_file, anat_file],
                                   [correct_atlas_file, correct_anat_file]):

        img = nibabel.load(in_file)
        header = img.header.copy()
        qform = header.get_qform()
Esempio n. 17
0
def _func_to_template(func_coreg_filename,
                      template_filename,
                      write_dir,
                      func_to_anat_oned_filename,
                      anat_to_template_oned_filename,
                      anat_to_template_warp_filename,
                      voxel_size=None,
                      caching=False,
                      verbose=True):
    """ Applies successive transforms to coregistered functional to put it in
    template space.

    Parameters
    ----------
    coreg_func_filename : str
        Path to functional volume, coregistered to a common space with the
        anatomical volume.

    template_filename : str
        Template to register the functional to.

    func_to_anat_oned_filename : str
        Path to the affine 1D transform from functional to coregistration
        space.

    anat_to_template_oned_filename : str
        Path to the affine 1D transform from anatomical to template space.

    anat_to_template_warp_filename : str
        Path to the warp transform from anatomical to template space.

    voxel_size : 3-tuple of floats, optional
        Voxel size of the registered functional, 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.
    """
    if verbose:
        terminal_output = 'allatonce'
    else:
        terminal_output = 'none'

    if caching:
        memory = Memory(write_dir)
        warp_apply = memory.cache(afni.NwarpApply)
        resample = memory.cache(afni.Resample)
        warp_apply.interface().set_default_terminal_output(terminal_output)
        resample.interface().set_default_terminal_output(terminal_output)
    else:
        warp_apply = afni.NwarpApply(terminal_output=terminal_output).run
        resample = afni.Resample(terminal_output=terminal_output).run

    current_dir = os.getcwd()
    os.chdir(write_dir)  # XXX to remove
    normalized_filename = fname_presuffix(func_coreg_filename,
                                          suffix='_normalized')
    if voxel_size is None:
        func_template_filename = template_filename
    else:
        out_resample = resample(in_file=template_filename,
                                voxel_size=voxel_size,
                                outputtype='NIFTI_GZ')
        func_template_filename = out_resample.outputs.out_file

    warp = "'{0} {1} {2}'".format(anat_to_template_warp_filename,
                                  anat_to_template_oned_filename,
                                  func_to_anat_oned_filename)

    _ = warp_apply(in_file=func_coreg_filename,
                   master=func_template_filename,
                   warp=warp,
                   out_file=normalized_filename)
    os.chdir(current_dir)
    return normalized_filename
Esempio n. 18
0
    anat_files = glob.glob(
        os.path.expanduser('~/nilearn_data/mrm_2010/C57*.nii.gz'))
    anat_files.remove(
        os.path.expanduser('~/nilearn_data/mrm_2010/C57_ab1_invivo.nii.gz'))

    # Generate random transforms
    rand_gen = np.random.RandomState(12)
    idenity_transform = np.array(
        [1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0.])
    std = .1 * np.array(
        [.01, .01, .01, .1, .01, .01, .01, .1, .01, .01, .01, .1])
    transforms = idenity_transform + rand_gen.randn(len(anat_files), 12) * std
    for anat_file, transform in zip(anat_files, transforms):
        atlas_file = anat_file.replace('C57', 'Atlas')
        reoriented_anat_file = fname_presuffix(anat_file,
                                               newpath=spm_dir,
                                               suffix='.nii',
                                               use_ext=False)
        if 'ab2' in anat_file:
            raw_atlas_file = atlas_file.replace('ab2', 'Ab2')
        elif 'y81' in anat_file:
            raw_atlas_file = atlas_file.replace('Invivo', 'invivo')
        else:
            raw_atlas_file = atlas_file

        reoriented_atlas_file = fname_presuffix(raw_atlas_file,
                                                newpath=spm_dir,
                                                suffix='.nii',
                                                use_ext=False)
        print(reoriented_anat_file, reoriented_atlas_file)
        matrix_file = fname_presuffix(anat_file,
                                      newpath=sammba_transformed_dir,
Esempio n. 19
0
        my_dir, 'perfFAIREPI_n0_M0_unbiased_perslice_oblique.nii.gz')
    spm_anat = os.path.join(
        spm_dir,
        'reoriented/anat_n0_clear_hd.nii')  # anat_n0_unifized_clean_hd.nii
    spm_perf = os.path.join(
        spm_dir, 'reoriented/rperfFAIREPI_n0_M0.nii'
    )  # replace by rperfFAIREPI_n0_M0_unbiased_clean_hd.nii)

    perf_to_anat_transform = os.path.join(
        my_dir, 'anat_n0_unifized_warped_oblique_anat_to_func.aff12.1D')
    my_anat = os.path.join(my_dir, 'anat_n0_unifized.nii.gz')
    allineate = afni.Allineate().run
    out_allineate = allineate(in_file=my_perf1,
                              master=my_anat,
                              in_matrix=perf_to_anat_transform,
                              out_file=fname_presuffix(my_perf1,
                                                       suffix='_in_anat'),
                              environ={'AFNI_DECONFLICT': 'OVERWRITE'})
    my_perf_in_anat_space = out_allineate.outputs.out_file
    my_perf_data = nibabel.load(my_perf_in_anat_space).get_data()
    my_perf_mask_img = image.math_img('img > {}'.format(my_perf_data.min()),
                                      img=my_perf_in_anat_space)
    my_perf_mask_data = my_perf_mask_img.get_data().astype(bool)
    my_perf_mask = fname_presuffix(my_perf_in_anat_space, suffix='_mask')
    my_perf_mask_img.to_filename(my_perf_mask)

    spm_perf_data = nibabel.load(spm_perf).get_data()
    spm_perf_mask_img = image.math_img('img > {}'.format(
        np.nanmin(spm_perf_data)),
                                       img=my_perf_in_anat_space)
    spm_perf_mask_data = spm_perf_mask_img.get_data().astype(bool)
    spm_perf_mask = fname_presuffix(spm_perf, suffix='_mask')
        spm_labels_img = image.math_img('img * (np.argmax(imgs, axis=-1) + 1)',
                                        img=mask_img,
                                        imgs=spm_tissues_imgs)
        check_niimg(spm_labels_img, dtype=float).to_filename(spm_labels_file)

    nwarp_apply = afni.NwarpApply().run
    transforms = [
        os.path.join(sammba_dir,
                     'anat_n0_unifized_affine_general_warped_WARP.nii.gz'),
        os.path.join(sammba_dir, 'anat_n0_unifized_masked_aff.aff12.1D')
    ]
    warp = "'" + ' '.join(transforms) + "'"
    sammba_tissues_files = []
    for tissue_file in spm_tissues_imgs:
        sammba_tissue_file = fname_presuffix(tissue_file,
                                             suffix='_warped',
                                             newpath=sammba_dir)
        out_warp_apply = nwarp_apply(in_file=tissue_file,
                                     master=template_file,
                                     warp=warp,
                                     out_file=sammba_tissue_file)
        sammba_tissues_files.append(sammba_tissue_file)

    sammba_brain_mask_file = '/home/bougacha/inhouse_mouse/brain100_binarized.nii.gz'
    mask_img = image.math_img('np.max(imgs, axis=-1) > .01',
                              imgs=sammba_tissues_files)
    sammba_labels_img = image.math_img('img * (np.argmax(imgs, axis=-1) + 1)',
                                       img=mask_img,
                                       imgs=sammba_tissues_files)
    sammba_labels_file = sammba_tissue_file.replace('c3', 'labeled_c')
    sammba_labels_img.to_filename(sammba_labels_file)
Esempio n. 21
0
        [sammba_brain_mask_file, spm_gm_wm_img], threshold=0)
    brain_mask_file = os.path.join(sammba_dir,
                                   'anat_n0_precise_brain_mask.nii.gz')
    brain_contour_file = compute_mask_contour(brain_mask_file)
    check_niimg(brain_contour_file).to_filename(
        os.path.join(spm_dir, 'anat_n0_precise_brain_mask_contour.nii'))

    nwarp_apply = afni.NwarpApply().run
    transforms = [
        os.path.join(sammba_dir,
                     'anat_n0_unifized_affine_general_warped_WARP.nii.gz'),
        os.path.join(sammba_dir, 'anat_n0_unifized_masked_aff.aff12.1D')
    ]
    warp = "'" + ' '.join(transforms) + "'"
    sammba_registered_contour_file = fname_presuffix(brain_contour_file,
                                                     suffix='_warped',
                                                     newpath=sammba_dir)
    out_warp_apply = nwarp_apply(in_file=brain_contour_file,
                                 master=template_brain_mask_file,
                                 warp=warp,
                                 interp='nearestneighbor',
                                 out_file=sammba_registered_contour_file,
                                 environ={'AFNI_DECONFLICT': 'OVERWRITE'})

    spm_registered_contour_file = os.path.join(
        spm_dir, 'wanat_n0_precise_brain_mask_contour.nii')

    spm_registered_contour_data = check_niimg(
        spm_registered_contour_file).get_data()
    template_shape = check_niimg(template_brain_mask_file).shape
    if spm_registered_contour_data.shape != template_shape:
Esempio n. 22
0
     ))
 anat_files.remove(
     os.path.expanduser(
         '~/mrm_bil2_transformed/correct_headers/bil2_transfo_C57_Az1_invivo_corrected.nii.gz'
     ))
 #    anat_files.remove(os.path.expanduser(
 #        '~/mrm_bil2_transformed/bil2_transfo_C57_ab1_invivo.nii.gz'))
 mice_ids = [os.path.basename(a)[12:] for a in anat_files]
 sammba_dices = []
 sammba_dices2 = []
 spm_dices = []
 original_dices = []
 for mouse_id in mice_ids:
     atlas_id = mouse_id.replace('C57_', '')
     sammba_mouse_atlas_file = fname_presuffix(atlas_id,
                                               newpath=sammba_raw_dir,
                                               prefix='bil2_transfo_Atlas')
     matrix_file = fname_presuffix(mouse_id,
                                   newpath=sammba_dir,
                                   prefix='bil2_transfo',
                                   suffix='_unifized_masked_aff.aff12.1D',
                                   use_ext=False)
     warp_file = fname_presuffix(
         mouse_id,
         newpath=sammba_dir,
         prefix='bil2_transfo',
         suffix='_unifized_affine_general_warped_WARP')
     sammba_registered_atlas_file = fname_presuffix(atlas_id,
                                                    suffix='_allineated',
                                                    newpath=sammba_dir)
     allineate = afni.Allineate().run
    sammba_template_file = os.path.expanduser(
        '~/mrm_reoriented_bil2/Average_template_invivo.nii.gz')
    sammba_template_atlas_file = os.path.expanduser(
        '~/mrm_reoriented_bil2/Average_atlas_invivo.nii.gz')

    anat_files = glob.glob(
        os.path.expanduser('~/mrm_reoriented_bil2/bil2_transfo_C57*.nii.gz'))
    mice_ids = [os.path.basename(a)[12:] for a in anat_files]
    sammba_dices = []
    sammba_dices2 = []
    spm_dices = []
    original_dices = []
    for mouse_id in mice_ids:
        atlas_id = mouse_id.replace('C57_', '')
        sammba_mouse_atlas_file = fname_presuffix(atlas_id,
                                                  newpath=sammba_raw_dir,
                                                  prefix='bil2_transfo_Atlas')
        matrix_file = fname_presuffix(mouse_id,
                                      newpath=sammba_dir,
                                      prefix='bil2_transfo',
                                      suffix='_unifized_masked_aff.aff12.1D',
                                      use_ext=False)
        warp_file = fname_presuffix(
            mouse_id,
            newpath=sammba_dir,
            prefix='bil2_transfo',
            suffix='_unifized_affine_general_warped_WARP')
        sammba_registered_atlas_file = fname_presuffix(atlas_id,
                                                       suffix='_allineated',
                                                       newpath=sammba_dir)
        allineate = afni.Allineate().run
    anat_files.remove(
        os.path.expanduser('~/nilearn_data/mrm_2010/C57_ab1_invivo.nii.gz'))
    mice_ids = [os.path.basename(a)[3:] for a in anat_files]
    sammba_dices = []
    spm_dices = []
    original_dices = []
    for mouse_id in mice_ids:
        if mouse_id == '_ab2_invivo.nii.gz':
            atlas_id = '_Ab2_invivo.nii.gz'
        elif mouse_id == '_y81_Invivo.nii.gz':
            atlas_id = '_y81_invivo.nii.gz'
        else:
            atlas_id = mouse_id

        sammba_mouse_atlas_file = fname_presuffix(atlas_id,
                                                  newpath=sammba_raw_dir,
                                                  prefix='Atlas')
        matrix_file = fname_presuffix(mouse_id,
                                      newpath=sammba_dir,
                                      prefix='C57',
                                      suffix='_unifized_masked_aff.aff12.1D',
                                      use_ext=False)
        sammba_registered_atlas_file = fname_presuffix(atlas_id,
                                                       suffix='_allineated',
                                                       newpath=sammba_dir)
        allineate = afni.Allineate().run
        out_allineate = allineate(in_file=sammba_mouse_atlas_file,
                                  master=sammba_template_file,
                                  in_matrix=matrix_file,
                                  out_file=sammba_registered_atlas_file,
                                  interpolation='nearestneighbour',
Esempio n. 25
0
common_m_file = '/home/Pmamobipet/0_Dossiers-Personnes/Salma/batches/c57_mrm_normalization_common.m'
with open(common_m_file, 'r') as file_content:
    common_lines = file_content.read()

for anat_file in anat_files:
    base_file = os.path.basename(anat_file)
    atlas_base_file = base_file.replace('C57', 'Atlas')

    if 'ab2' in anat_file:
        atlas_base_file = atlas_base_file.replace('ab2', 'Ab2')
    elif 'y81' in anat_file:
        atlas_base_file = atlas_base_file.replace('Invivo', 'invivo')

    m_script_file = fname_presuffix(anat_file[:-11],
                                    newpath='/home/Pmamobipet/0_Dossiers-Personnes/Salma/batches',
                                    prefix='normalize_', suffix='.m',
                                    use_ext=False)
    print(m_script_file)
    windows_atlas_file = "\'Y:\\0_Dossiers-Personnes\\Salma\\mrm_2010\\reoriented\\bil2_transformed\\" +\
        atlas_base_file + ",1\'"

    windows_transform_file = "\'Y:\\0_Dossiers-Personnes\\Salma\\mrm_2010\\reoriented\\bil2_transformed\\" +\
        base_file[:-4] + "_seg_sn.mat\'"

    lines = "matlabbatch{1}.spm.spatial.normalise.write.subj.matname = {"
    lines += windows_transform_file
    lines += '};\n'

    lines += "matlabbatch{1}.spm.spatial.normalise.write.subj.resample = {"
    lines += windows_atlas_file
    lines += '};\n'
Esempio n. 26
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(terminal_output=terminal_output).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)
Esempio n. 27
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)
Esempio n. 28
0
def anats_to_common(t1_filenames, write_dir, brain_volume=400,
                    registration_kind='affine',
                    nonlinear_levels=[1, 2, 3],
                    nonlinear_minimal_patch=75,
                    convergence=0.005, caching=False, verbose=0):
    """ Create common template from native T1 weighted images and achieve
    their registration to it.

    Parameters
    ----------
    t1_filenames : list of str
        Paths to the T1 weighted images.

    write_dir : str
        Path to an existant directory to save output files to.

    brain_volume : float, optional
        Volumes of the brain as passed to Rats_MM brain extraction tool.
        Default to 400 for the mouse brain.

    registration_kind : one of {'rigid', 'affine', 'nonlinear'}, optional
        The allowed transform kind.

    nonlinear_levels : list of int, optional
        Maximal levels for each nonlinear warping iteration. Passed iteratively
        to sammba.externals.nipype.interfaces.afni.Qwarp

    nonlinear_minimal_patch : int, optional
        Minimal patch for the final nonlinear warp, passed to
        sammba.externals.nipype.interfaces.afni.Qwarp

    caching : bool, optional
        If True, caching is used for all the registration steps.

    convergence : float, optional
        Convergence limit, passed to

    verbose : bool, optional
        If True, all steps are verbose.

    Returns
    -------
    data : sklearn.datasets.base.Bunch
        Dictionary-like object, the interest attributes are :

        - 'registered' : list of str.
                         Paths to registered images. Note that
                         they have undergone a bias correction step before.
        - 'transforms' : list of str.
                         Paths to the transforms from the raw
                         images to the registered images.
    """
    registration_kinds = ['rigid', 'affine', 'nonlinear']
    if registration_kind not in registration_kinds:
        raise ValueError(
            'Registration kind must be one of {0}, you entered {1}'.format(
                registration_kinds, registration_kind))

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

    if caching:
        memory = Memory(write_dir)
        copy = memory.cache(afni.Copy)
        unifize = memory.cache(afni.Unifize)
        clip_level = memory.cache(afni.ClipLevel)
        rats = memory.cache(RatsMM)
        apply_mask = memory.cache(fsl.ApplyMask)
        center_mass = memory.cache(afni.CenterMass)
        refit = memory.cache(afni.Refit)
        tcat = memory.cache(afni.TCat)
        tstat = memory.cache(afni.TStat)
        undump = memory.cache(afni.Undump)
        resample = memory.cache(afni.Resample)
        allineate = memory.cache(afni.Allineate)
        allineate2 = memory.cache(afni.Allineate)
        mask_tool = memory.cache(afni.MaskTool)
        catmatvec = memory.cache(afni.CatMatvec)
        qwarp = memory.cache(afni.Qwarp)
        nwarp_cat = memory.cache(afni.NwarpCat)
        warp_apply = memory.cache(afni.NwarpApply)
        for func in [copy, unifize, rats, apply_mask, refit,
                     tcat, tstat, undump, resample, allineate, allineate2,
                     mask_tool, catmatvec, qwarp, nwarp_cat, warp_apply]:
            func.interface().set_default_terminal_output(terminal_output)
    else:
        copy = afni.Copy(terminal_output=terminal_output).run
        unifize = afni.Unifize(terminal_output=terminal_output).run
        clip_level = afni.ClipLevel().run  # XXX fix nipype bug with 'none'
        rats = RatsMM(terminal_output=terminal_output).run
        apply_mask = fsl.ApplyMask(terminal_output=terminal_output).run
        center_mass = afni.CenterMass().run  # XXX fix nipype bug with 'none'
        refit = afni.Refit(terminal_output=terminal_output).run
        tcat = afni.TCat(terminal_output=terminal_output).run
        tstat = afni.TStat(terminal_output=terminal_output).run
        undump = afni.Undump(terminal_output=terminal_output).run
        resample = afni.Resample(terminal_output=terminal_output).run
        allineate = afni.Allineate(terminal_output=terminal_output).run
        allineate2 = afni.Allineate(terminal_output=terminal_output).run
        mask_tool = afni.MaskTool(terminal_output=terminal_output).run
        catmatvec = afni.CatMatvec(terminal_output=terminal_output).run
        qwarp = afni.Qwarp(terminal_output=terminal_output).run
        nwarp_cat = afni.NwarpCat(terminal_output=terminal_output).run
        warp_apply = afni.NwarpApply(terminal_output=terminal_output).run

    current_dir = os.getcwd()
    os.chdir(write_dir)

    ###########################################################################
    # First copy anatomical files, to make sure they are never changed
    # and they have different names across individuals
    copied_t1_filenames = []
    for n, anat_file in enumerate(t1_filenames):
        suffixed_file = fname_presuffix(anat_file, suffix='_{}'.format(n))
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_copy = copy(in_file=anat_file, out_file=out_file)
        copied_t1_filenames.append(out_copy.outputs.out_file)

    ###########################################################################
    # Register using center of mass
    # -----------------------------
    # An initial coarse registration is done using brain centre of mass (CoM).
    #
    # First we loop through anatomical scans and correct intensities for bias.
    unifized_files = []
    for n, anat_file in enumerate(copied_t1_filenames):
        out_unifize = unifize(in_file=anat_file, outputtype='NIFTI_GZ')
        unifized_files.append(out_unifize.outputs.out_file)

    ###########################################################################
    # Second extract brains, aided by an approximate guessed brain volume,
    # and set the NIfTI image centre (as defined in the header) to the CoM
    # of the extracted brain.
    brain_files = []
    for unifized_file in unifized_files:
        out_clip_level = clip_level(in_file=unifized_file)
        out_rats = rats(
            in_file=unifized_file,
            volume_threshold=brain_volume,
            intensity_threshold=int(out_clip_level.outputs.clip_val),
            terminal_output=terminal_output)
        out_apply_mask = apply_mask(in_file=unifized_file,
                                    mask_file=out_rats.outputs.out_file)
        out_center_mass = center_mass(
            in_file=out_apply_mask.outputs.out_file,
            cm_file=fname_presuffix(unifized_file, suffix='_cm.txt',
                                    use_ext=False),
            set_cm=(0, 0, 0))
        brain_files.append(out_center_mass.outputs.out_file)

    ###########################################################################
    # Same header change, for head files.
    head_files = []
    for unifized_file, brain_file in zip(unifized_files, brain_files):
        out_refit = refit(in_file=unifized_file, duporigin_file=brain_file)
        head_files.append(out_refit.outputs.out_file)

    ###########################################################################
    # The brain files with new image center are concatenated to produce
    # a quality check video
    out_tcat = tcat(in_files=brain_files, outputtype='NIFTI_GZ',
                    terminal_output=terminal_output)

    ###########################################################################
    # and averaged
    out_tstat = tstat(in_file=out_tcat.outputs.out_file, outputtype='NIFTI_GZ')

    ###########################################################################
    # to create an empty template, with origin placed at CoM
    out_undump = undump(in_file=out_tstat.outputs.out_file,
                        outputtype='NIFTI_GZ')
    out_refit = refit(in_file=out_undump.outputs.out_file,
                      xorigin='cen', yorigin='cen', zorigin='cen')

    ###########################################################################
    # Finally, we shift heads and brains within the images to place the CoM at
    # the image center.
    centered_head_files = []
    for head_file in head_files:
        out_resample = resample(in_file=head_file,
                                master=out_refit.outputs.out_file,
                                outputtype='NIFTI_GZ')
        centered_head_files.append(out_resample.outputs.out_file)

    centered_brain_files = []
    for brain_file in brain_files:
        out_resample = resample(in_file=brain_file,
                                master=out_refit.outputs.out_file,
                                outputtype='NIFTI_GZ')
        centered_brain_files.append(out_resample.outputs.out_file)

    ###########################################################################
    # Quality check videos and average brain
    out_tcat = tcat(in_files=centered_brain_files,
                    out_file=os.path.join(write_dir, 'centered_brains.nii.gz'))
    out_tstat_centered_brain = tstat(in_file=out_tcat.outputs.out_file,
                                     outputtype='NIFTI_GZ')

    ###########################################################################
    # At this point, we achieved a translation-only registration of the raw
    # anatomical images to each other's brain's (as defined by the brain
    # extractor) CoMs.
    ###########################################################################
    # Shift rotate
    # ------------
    # Now we move to rigid-body registration of CoM brains, and application of
    # this registration to CoM heads. This registration requires a target
    #  template. Here we use mean of all bias-corrected, brain-extracted,
    # mass-centered images. Other possibilities include an externally-sourced
    # image or, more biased, a nicely-aligned individual.
    shift_rotated_brain_files = []
    rigid_transform_files = []
    for centered_brain_file in centered_brain_files:
        suffixed_matrix = fname_presuffix(centered_brain_file,
                                          suffix='_shr.aff12.1D',
                                          use_ext=False)
        out_matrix = os.path.join(write_dir, os.path.basename(suffixed_matrix))
        out_allineate = allineate(
            in_file=centered_brain_file,
            reference=out_tstat_centered_brain.outputs.out_file,
            out_matrix=out_matrix,
            convergence=convergence,
            two_blur=1,
            warp_type='shift_rotate',
            out_file=fname_presuffix(centered_brain_file, suffix='_shr'))
        rigid_transform_files.append(out_allineate.outputs.out_matrix)
        shift_rotated_brain_files.append(out_allineate.outputs.out_file)

    ###########################################################################
    # Application to the whole head image. can also be used for a good
    # demonstration of linear vs. non-linear registration quality
    shift_rotated_head_files = []
    for centered_head_file, rigid_transform_file in zip(centered_head_files,
                                                        rigid_transform_files):
        suffixed_file = fname_presuffix(centered_head_file, suffix='_shr')
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_allineate = allineate2(
            in_file=centered_head_file,
            master=out_tstat_centered_brain.outputs.out_file,
            in_matrix=rigid_transform_file,
            out_file=out_file)
        shift_rotated_head_files.append(out_allineate.outputs.out_file)

    ###########################################################################
    # Note that this rigid body registration may need to be run more than once.
    # Now we produce an average of rigid body registered heads
    out_tcat = tcat(
        in_files=shift_rotated_head_files,
        out_file=os.path.join(write_dir, 'rigid_body_registered_heads.nii.gz'))
    out_tstat_shr = tstat(in_file=out_tcat.outputs.out_file,
                          outputtype='NIFTI_GZ')

    if registration_kind == 'rigid':
        os.chdir(current_dir)
        return Bunch(registered=shift_rotated_head_files,
                     transforms=rigid_transform_files)

    ###########################################################################
    # Affine transform
    # ----------------
    # We begin by achieving an affine registration on aligned heads.
    # A weighting mask is used to ...
    out_mask_tool = mask_tool(in_file=out_tcat.outputs.out_file,
                              count=True,
                              outputtype='NIFTI_GZ')

    ###########################################################################
    # The count mask is also useful for looking at brain extraction efficiency
    # and differences in brain size.
    affine_transform_files = []
    for shift_rotated_head_file, rigid_transform_file in zip(
            shift_rotated_head_files, rigid_transform_files):
        out_allineate = allineate(
            in_file=shift_rotated_head_file,
            reference=out_tstat_shr.outputs.out_file,
            out_matrix=fname_presuffix(shift_rotated_head_file,
                                       suffix='_affine.aff12.1D',
                                       use_ext=False),
            convergence=convergence,
            two_blur=1,
            one_pass=True,
            weight=out_mask_tool.outputs.out_file,
            out_file=fname_presuffix(shift_rotated_head_file,
                                     suffix='_affine'))

        suffixed_matrix = fname_presuffix(shift_rotated_head_file,
                                          suffix='_affine_catenated.aff12.1D',
                                          use_ext=False)
        catmatvec_out_file = os.path.join(write_dir,
                                          os.path.basename(suffixed_matrix))
        out_catmatvec = catmatvec(in_file=[(rigid_transform_file, 'ONELINE'),
                                           (out_allineate.outputs.out_matrix,
                                            'ONELINE')],
                                  out_file=catmatvec_out_file)
        affine_transform_files.append(catmatvec_out_file)

    ###########################################################################
    # Each resulting registration matrix is concatenated to the corresponding
    # rigid bory registration matrix then directly applied to the CoM brain
    # and head, reducing reslice errors in the final result.
    allineated_brain_files = []
    for centered_brain_file, affine_transform_file in zip(
            centered_brain_files, affine_transform_files):
        out_allineate = allineate2(
            in_file=centered_brain_file,
            master=out_tstat_shr.outputs.out_file,
            in_matrix=affine_transform_file,
            out_file=fname_presuffix(centered_brain_file,
                                     suffix='_shr_affine_catenated'))
        allineated_brain_files.append(out_allineate.outputs.out_file)

    ###########################################################################
    # The application to the whole head image can also be used for a good
    # demonstration of linear vs. non-linear registration quality.
    allineated_head_files = []
    for centered_head_file, affine_transform_file in zip(
            centered_head_files, affine_transform_files):
        suffixed_file = fname_presuffix(centered_head_file,
                                        suffix='_shr_affine_catenated')
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_allineate = allineate2(
            in_file=centered_head_file,
            master=out_tstat_shr.outputs.out_file,
            in_matrix=affine_transform_file,
            out_file=out_file)
        allineated_head_files.append(out_allineate.outputs.out_file)

    ###########################################################################
    # Quality check videos and template
    out_tcat_head = tcat(
        in_files=allineated_head_files,
        out_file=os.path.join(write_dir, 'affine_registered_heads.nii.gz'))
    out_tstat_allineated_head = tstat(in_file=out_tcat_head.outputs.out_file,
                                      outputtype='NIFTI_GZ')

    if registration_kind == 'affine':
        os.chdir(current_dir)
        return Bunch(registered=allineated_head_files,
                     transforms=affine_transform_files)

    ###########################################################################
    # Non-linear registration
    # -----------------------
    # A weight mask that extends beyond the brain, incorporating some
    # surrounding tissue, is needed to help better define the brain head
    # boundary.
    out_mask_tool = mask_tool(in_file=out_tcat.outputs.out_file, count=True,
                              outputtype='NIFTI_GZ')
    out_mask_tool = mask_tool(in_file=out_tcat.outputs.out_file, union=True,
                              outputtype='NIFTI_GZ')
    out_mask_tool = mask_tool(in_file=out_mask_tool.outputs.out_file,
                              dilate_inputs='4',
                              outputtype='NIFTI_GZ')

    ###########################################################################
    # The input source images are initially transformed prior to registration,
    # to ensure that they are already quite well-aligned to the template.
    # To save time, we only achieve one refinement level per step
    if nonlinear_levels is None:
        nonlinear_levels = [1, 2, 3]

    warped_files = []
    warp_files = []
    for affine_transform_file, centered_head_file in zip(
            affine_transform_files, centered_head_files):
        out_qwarp = qwarp(
            in_file=centered_head_file,
            base_file=out_tstat_allineated_head.outputs.out_file,
            nmi=True,
            noneg=True,
            iwarp=True,
            weight=out_mask_tool.outputs.out_file,
            iniwarp=[affine_transform_file],
            inilev=0,
            maxlev=nonlinear_levels[0],
            out_file=fname_presuffix(centered_head_file, suffix='_warped1'))
        warp_files.append(out_qwarp.outputs.source_warp)
        warped_files.append(out_qwarp.outputs.warped_source)

    out_tcat = tcat(
        in_files=warped_files,
        out_file=os.path.join(write_dir, 'warped_1iter_heads.nii.gz'))
    out_tstat_warp_head = tstat(in_file=out_tcat.outputs.out_file,
                                outputtype='NIFTI_GZ')

    ###########################################################################
    # Then iterative registration from a given level to another is achieved.
    # Note that any level below a patch size of 25 will not be done (see
    # 3dQwarp help for further detail).
    # The input transform is the former warp and needs to be concatenated to
    # IDENT initially; I forget why, I think it is to avoid some weird bug.
    if len(nonlinear_levels) > 1:
        previous_warp_files = warp_files
        warped_files = []
        warp_files = []
        for warp_file, centered_head_file in zip(previous_warp_files,
                                                 centered_head_files):
            out_nwarp_cat = nwarp_cat(
                in_files=[('IDENT', out_tstat_warp_head.outputs.out_file),
                          warp_file], out_file='iniwarp.nii.gz')
            out_qwarp = qwarp(
                in_file=centered_head_file,
                base_file=out_tstat_warp_head.outputs.out_file,
                nmi=True,
                noneg=True,
                iwarp=True,
                weight=out_mask_tool.outputs.out_file,
                iniwarp=[out_nwarp_cat.outputs.out_file],
                inilev=nonlinear_levels[0],
                maxlev=nonlinear_levels[1],
                out_file=fname_presuffix(centered_head_file,
                                         suffix='_warped2'))
            warp_files.append(out_qwarp.outputs.source_warp)
            warped_files.append(out_qwarp.outputs.warped_source)

        out_tcat = tcat(in_files=warped_files,
                        out_file='warped_2iters_heads.nii.gz')
        out_tstat_warp_head = tstat(in_file=out_tcat.outputs.out_file,
                                    outputtype='NIFTI_GZ')

    ###########################################################################
    # Using previous files and concatenated transforms can be exploited to
    # avoid building up reslice errors.
    # Warp with mini-patch
    # In this particular case, minpatch=75 corresponds to a level of 4
    if len(nonlinear_levels) > 2:
        if nonlinear_minimal_patch is None:
            nonlinear_minimal_patch = 75

        for n_iter, inilev in enumerate(nonlinear_levels[2:]):
            previous_warp_files = warp_files
            warped_files = []
            warp_files = []
            for warp_file, centered_head_file in zip(previous_warp_files,
                                                     centered_head_files):
                suffixed_file = fname_presuffix(
                    centered_head_file,
                    suffix='_warped{}'.format(n_iter + 3))
                if n_iter == len(nonlinear_levels):
                    out_file = os.path.join(write_dir,
                                            os.path.basename(suffixed_file))
                else:
                    out_file = suffixed_file

                out_qwarp = qwarp(
                    in_file=centered_head_file,
                    base_file=out_tstat_warp_head.outputs.out_file,
                    nmi=True,
                    noneg=True,
                    iwarp=True,
                    weight=out_mask_tool.outputs.out_file,
                    iniwarp=[warp_file],
                    inilev=inilev,
                    minpatch=nonlinear_minimal_patch,
                    out_file=out_file)
                warped_files.append(out_qwarp.outputs.warped_source)
                warp_files.append(out_qwarp.outputs.source_warp)

            out_tcat = tcat(
                in_files=warped_files,
                out_file=os.path.join(
                    write_dir, 'warped_{0}iters_heads.nii.gz'.format(n_iter +
                                                                     3)))
            out_tstat_warp_head = tstat(in_file=out_tcat.outputs.out_file,
                                        outputtype='NIFTI_GZ')

    ###########################################################################
    # We can repeat this very last warp while using the last average until we
    # are satisfied with the template quality

    ###########################################################################
    # Register to template
    # --------------------
    # Apply non-linear registration results to uncorrected images
    warped_files = []
    for centered_head_file, warp_file in zip(centered_head_files, warp_files):
        suffixed_file = fname_presuffix(
            centered_head_file,
            suffix='affine_warp{}_catenated'.format(len(nonlinear_levels)))
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_warp_apply = warp_apply(
            in_file=centered_head_file,
            warp=warp_file,
            master=out_tstat_warp_head.outputs.out_file,
            out_file=out_file)
        warped_files.append(out_warp_apply.outputs.out_file)

    os.chdir(current_dir)
    return Bunch(registered=warped_files,
                 transforms=warp_files)
Esempio n. 29
0
            '~/nilearn_data/mrm_2010/correct_headers/C57_Az1_invivo_corrected.nii.gz'
        )
    ]

    # Generate random transforms
    for anat_file in anat_files:
        atlas_file = anat_file.replace('C57', 'Atlas')
        if 'ab2' in anat_file:
            raw_atlas_file = atlas_file.replace('ab2', 'Ab2')
        elif 'y81' in anat_file:
            raw_atlas_file = atlas_file.replace('Invivo', 'invivo')
        else:
            raw_atlas_file = atlas_file

        param_file = fname_presuffix(anat_file.replace('_corrected', ''),
                                     newpath=sammba_params_dir,
                                     suffix='_bil2_transform.1D',
                                     use_ext=False)
        sammba_anat_file = fname_presuffix(anat_file,
                                           newpath=sammba_transformed_dir,
                                           prefix='bil2_transfo_')
        sammba_atlas_file = fname_presuffix(atlas_file,
                                            newpath=sammba_transformed_dir,
                                            prefix='bil2_transfo_')
        print(anat_file)
        assert (os.path.isfile(raw_atlas_file))

        allineate = afni.Allineate().run
        copy_geom = fsl.CopyGeom().run

        if True:
            out_allineate = allineate(in_file=anat_file,
Esempio n. 30
0
def anats_to_common(anat_filenames,
                    write_dir,
                    brain_volume,
                    registration_kind='affine',
                    use_rats_tool=True,
                    nonlinear_levels=[1, 2, 3],
                    nonlinear_minimal_patches=[75],
                    nonlinear_weight_file=None,
                    convergence=0.005,
                    blur_radius_coarse=1.1,
                    caching=False,
                    verbose=1,
                    unifize_kwargs=None,
                    brain_masking_unifize_kwargs=None):
    """ Create common template from native anatomical images and achieve
    their registration to it.

    Parameters
    ----------
    anat_filenames : list of str
        Paths to the anatomical images.

    write_dir : str
        Path to an existant directory to save output files to.

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

    registration_kind : one of {'rigid', 'affine', 'nonlinear'}, optional
        The allowed transform kind.

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

    nonlinear_levels : list of int, optional
        Maximal levels for each nonlinear warping iteration. Passed iteratively
        to sammba.externals.nipype.interfaces.afni.Qwarp

    nonlinear_minimal_patches : list of int, optional
        Minimal patches for the final nonlinear warps, passed to
        sammba.externals.nipype.interfaces.afni.Qwarp
        
    nonlinear_weight_file : str, optional
        Path to a mask used to weight non-linear registration. Ideally should 
        include not just the whole brain but also extend in all directions to 
        include some amount of surrounding head tissue.
        
    convergence : float, optional
        Convergence limit, passed to
        sammba.externals.nipype.interfaces.afni.Allineate
        
    blur_radius_coarse : float, optional
        Radius passed to sammba.externals.nipype.interfaces.afni.Allineate for
        the "-twoblur" option

    caching : bool, optional
        If True, caching is used for all the registration steps.

    verbose : int, optional
        Verbosity level. Note that caching implies some
        verbosity in any case.

    unifize_kwargs : dict, optional
        Is passed to sammba.externals.nipype.interfaces.afni.Unifize, to
        control bias correction of the template.

    brain_masking_unifize_kwargs : dict, optional
        Is passed to sammba.externals.nipype.interfaces.afni.Unifize, to tune
        the seperate bias correction step done prior to brain masking.

    Returns
    -------
    data : sklearn.datasets.base.Bunch
        Dictionary-like object, the interest attributes are :

        - `registered` : list of str.
                         Paths to registered images. Note that
                         they have undergone a bias correction step before.
        - `transforms` : list of str.
                         Paths to the transforms from the raw
                         images to the registered images.
                         
    Notes
    -----    
    nonlinear_weight_file:

    Without this weight mask, for non-linear registration a mask is generated by 
    binarizing the mean of images that have been brain and affine-registered, 
    then evenly dilating it to include some surrounding head tissue. The 
    non-linear registration is then weighted to work only within this mask. This 
    substantially improves performance by 1) reducing the number of voxels to 
    analyse, and 2) avoiding other parts of the head where structures are highly 
    variable and signal often poor. However, this automatically-generated mask 
    is frequently sub-optimal, usually due to missing paraflocculi and 
    inappropriate dilation.
    
    Of course, it is impossible to know ahead of time where to weight the image 
    before the brains/heads have been registered to each other. So in practice a 
    first running of this script is done up until and including the affine stage 
    (the default). The user should then manually use 3dmask_tool or some other 
    software tool to create an intersect/frac/union mask of the 
    _Unifized_for_brain_extraction_masked_resample_shr_affine_catenated files. 
    These can then be dilated as needed to include some surrounding head tissue 
    (which helps to better distinguish the brain-non-brain boundary). Missing 
    regions can be added manually. This does not have to be done precisely, only 
    roughly, and it is better to include too much tissue than too little. The 
    procedure should then be rerun as non-linear, but using this weight mask.                     

    use_rats_tool:
    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/>`_
    """
    registration_kinds = ['rigid', 'affine', 'nonlinear']
    if registration_kind not in registration_kinds:
        raise ValueError(
            'Registration kind must be one of {0}, you entered {1}'.format(
                registration_kinds, registration_kind))

    if registration_kind is 'nonlinear' and len(anat_filenames) < 5:
        raise ValueError('At least 5 input files are required to make a '
                         'template by non-linear \n registration. Only '
                         '{0} have been provided.'.format(len(anat_filenames)))

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

    if verbose:
        terminal_output = 'stream'
        verbosity_kwargs = {'verb': verbose > 1}
        quietness_kwargs = {}
        verbosity_quietness_kwargs = {'verb': verbose > 2}
    else:
        terminal_output = 'none'
        verbosity_kwargs = {}
        quietness_kwargs = {'quiet': True}
        verbosity_quietness_kwargs = {'quiet': True}

    if caching:
        memory = Memory(write_dir)
        copy = memory.cache(afni.Copy)
        unifize = memory.cache(afni.Unifize)
        clip_level = memory.cache(afni.ClipLevel)
        compute_mask = memory.cache(ComputeMask)
        calc = memory.cache(afni.Calc)
        center_mass = memory.cache(afni.CenterMass)
        refit = memory.cache(afni.Refit)
        tcat = memory.cache(afni.TCat)
        tstat = memory.cache(afni.TStat)
        undump = memory.cache(afni.Undump)
        resample = memory.cache(afni.Resample)
        allineate = memory.cache(afni.Allineate)
        allineate2 = memory.cache(afni.Allineate)
        mask_tool = memory.cache(afni.MaskTool)
        catmatvec = memory.cache(afni.CatMatvec)
        qwarp = memory.cache(afni.Qwarp)
        qwarp2 = memory.cache(afni.Qwarp)  # workaround to initialize inputs
        nwarp_cat = memory.cache(afni.NwarpCat)
        warp_apply = memory.cache(afni.NwarpApply)
        nwarp_adjust = memory.cache(afni.NwarpAdjust)
        for step in [
                copy, unifize, compute_mask, calc, refit, tcat, tstat, undump,
                resample, allineate, allineate2, mask_tool, catmatvec, qwarp,
                nwarp_cat, warp_apply, nwarp_adjust
        ]:
            step.interface().set_default_terminal_output(terminal_output)
    else:
        copy = afni.Copy(terminal_output=terminal_output).run
        unifize = afni.Unifize(terminal_output=terminal_output).run
        clip_level = afni.ClipLevel().run  # XXX fix nipype bug with 'none'
        compute_mask = ComputeMask(terminal_output=terminal_output).run
        calc = afni.Calc(terminal_output=terminal_output).run
        center_mass = afni.CenterMass().run  # XXX fix nipype bug with 'none'
        refit = afni.Refit(terminal_output=terminal_output).run
        tcat = afni.TCat(terminal_output=terminal_output).run
        tstat = afni.TStat(terminal_output=terminal_output).run
        undump = afni.Undump(terminal_output=terminal_output).run
        resample = afni.Resample(terminal_output=terminal_output).run
        allineate = afni.Allineate(terminal_output=terminal_output).run
        allineate2 = afni.Allineate(terminal_output=terminal_output).run
        mask_tool = afni.MaskTool(terminal_output=terminal_output).run
        catmatvec = afni.CatMatvec(terminal_output=terminal_output).run
        qwarp = afni.Qwarp(terminal_output=terminal_output).run
        qwarp2 = afni.Qwarp(terminal_output=terminal_output).run
        nwarp_cat = afni.NwarpCat(terminal_output=terminal_output).run
        warp_apply = afni.NwarpApply(terminal_output=terminal_output).run
        nwarp_adjust = afni.NwarpAdjust(terminal_output=terminal_output).run

    current_dir = os.getcwd()
    os.chdir(write_dir)

    ###########################################################################
    # First copy anatomical files to make sure the originals are never changed
    # and they have different names across individuals. Then produce a video of
    # this raw data and a mean
    copied_anat_filenames = []
    for n, anat_file in enumerate(anat_filenames):
        suffixed_file = fname_presuffix(anat_file, suffix='_{}'.format(n))
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_copy = copy(in_file=anat_file,
                        out_file=out_file,
                        **verbosity_kwargs)
        copied_anat_filenames.append(out_copy.outputs.out_file)

    out_tcat = tcat(in_files=copied_anat_filenames,
                    out_file=os.path.join(write_dir, 'raw_heads.nii.gz'),
                    outputtype='NIFTI_GZ',
                    **verbosity_kwargs)
    out_tstat = tstat(in_file=out_tcat.outputs.out_file, outputtype='NIFTI_GZ')

    ###########################################################################
    # Bias correct and register using center of mass
    # -----------------------------
    # An initial coarse registration is done using brain centre of mass (CoM).
    #
    # First we loop through anatomical scans and correct intensities for bias.
    # This is done twice with parameters that can be set differently: once to
    # create an image for automatic brain mask generation, and a another time
    # for the image that will actually have its brain extracted by this mask and
    # also be passed on to the rest of the function. This separation is useful
    # because in some circumstances the ideal bias correction can create zones
    # of signal and noise that confuse the brain masker, so it is best if that
    # calculation is performed on a differently-corrected image. In a lot(most?)
    # cases, the same parameters can be used for both bias correctors (the
    # default) as though the correction was only ever done once.
    #
    # Second, image centers are redefined based on the CoM of brains extracted
    # by the brain masks. The images are then translated to force the new
    # centers to all be at the same position: the center of the image matrix.
    # This is a crude form of translation-only registration amongst images that
    # simultaneously shifts the position of all brains to being in the centre of
    # the image if this was not already the case (which it often is not in small
    # mammal head imaging where the brain is usually in the upper half).
    #
    # Note that the heads created at the end will be the start point for all
    # subsequent transformations (meaning any transformation generated from now
    # on will be a concatenation of itself and previous ones for direct
    # application to CoM-registered heads). This avoids the accumulation of
    # reslice error from one registration to the next. Ideally, the start point
    # should be the bias-corrected images prior to center correction (which
    # itself involes reslicing). However, I have not yet figured out the best
    # way to convert CoM change into an affine transform and then use it. The
    # conversion should be relatively easy, using nibabel to extract the two
    # affines then numpy to calculate the difference. Using it is not so simple.
    # Unlike 3dQwarp, 3dAllineate does not have a simple initialization flag.
    # Instead, it is necessary to use -parini to initialize any given affine
    # parameter individually. However, -parini can be overidden by other flags,
    # so careful checks need to be made to ensure that this will never happen
    # with the particular command or set of commands used here.

    # bias correction for images to be used for brain mask creation
    if brain_masking_unifize_kwargs is None:
        brain_masking_unifize_kwargs = {}
    brain_masking_unifize_kwargs.update(quietness_kwargs)
    brain_masking_in_files = []
    for n, anat_file in enumerate(copied_anat_filenames):
        out_unifize = unifize(in_file=anat_file,
                              out_file='%s_Unifized_for_brain_masking',
                              outputtype='NIFTI_GZ',
                              **brain_masking_unifize_kwargs)
        brain_masking_in_files.append(out_unifize.outputs.out_file)

    # brain mask creation
    brain_mask_files = []
    for n, brain_masking_in_file in enumerate(brain_masking_in_files):
        out_clip_level = clip_level(in_file=brain_masking_in_file)
        out_compute_mask = compute_mask(
            in_file=brain_masking_in_file,
            out_file=fname_presuffix(brain_masking_in_file, suffix='_mask'),
            volume_threshold=brain_volume,
            intensity_threshold=int(out_clip_level.outputs.clip_val),
            terminal_output=terminal_output)
        brain_mask_files.append(out_compute_mask.outputs.out_file)

    # bias correction for images to be both brain-extracted with the mask
    # generated above and then passed on to the rest of the function
    if unifize_kwargs is None:
        unifize_kwargs = {}

    unifize_kwargs.update(quietness_kwargs)
    unifized_files = []
    for n, anat_file in enumerate(copied_anat_filenames):
        out_unifize = unifize(in_file=anat_file,
                              out_file='%s_Unifized_for_brain_extraction',
                              outputtype='NIFTI_GZ',
                              **unifize_kwargs)
        unifized_files.append(out_unifize.outputs.out_file)

    # extrcat brains and set NIfTI image center (as defined in the header) to
    # the brain CoM
    brain_files = []
    for (brain_mask_file, unifized_file) in zip(brain_mask_files,
                                                unifized_files):
        out_calc_mask = calc(in_file_a=unifized_file,
                             in_file_b=brain_mask_file,
                             expr='a*b',
                             outputtype='NIFTI_GZ')
        out_center_mass = center_mass(in_file=out_calc_mask.outputs.out_file,
                                      cm_file=fname_presuffix(unifized_file,
                                                              suffix='_cm.txt',
                                                              use_ext=False),
                                      set_cm=(0, 0, 0))
        brain_files.append(out_center_mass.outputs.out_file)

    # apply center change to head files too
    head_files = []
    for unifized_file, brain_file in zip(unifized_files, brain_files):
        out_refit = refit(in_file=unifized_file, duporigin_file=brain_file)
        head_files.append(out_refit.outputs.out_file)

    # create an empty template with a center at the image matrix center
    out_undump = undump(in_file=out_tstat.outputs.out_file,
                        out_file=os.path.join(write_dir, 'undump.nii.gz'),
                        outputtype='NIFTI_GZ')
    out_refit = refit(in_file=out_undump.outputs.out_file,
                      xorigin='cen',
                      yorigin='cen',
                      zorigin='cen')

    # shift brains to place their new centers at the same central position.
    # make a quality check video and mean
    centered_brain_files = []
    for brain_file in brain_files:
        out_resample = resample(in_file=brain_file,
                                resample_mode='Cu',
                                master=out_refit.outputs.out_file,
                                outputtype='NIFTI_GZ')
        centered_brain_files.append(out_resample.outputs.out_file)
    out_tcat = tcat(in_files=centered_brain_files,
                    out_file=os.path.join(write_dir, 'centered_brains.nii.gz'),
                    **verbosity_kwargs)
    out_tstat_centered_brain = tstat(in_file=out_tcat.outputs.out_file,
                                     outputtype='NIFTI_GZ')

    # do the same for heads. is also a better quality check than the brain
    centered_head_files = []
    for head_file in head_files:
        out_resample = resample(in_file=head_file,
                                resample_mode='Cu',
                                master=out_refit.outputs.out_file,
                                outputtype='NIFTI_GZ')
        centered_head_files.append(out_resample.outputs.out_file)
    out_tcat = tcat(in_files=centered_head_files,
                    out_file=os.path.join(write_dir, 'centered_heads.nii.gz'),
                    **verbosity_kwargs)
    out_tstat_centered_brain = tstat(in_file=out_tcat.outputs.out_file,
                                     outputtype='NIFTI_GZ')

    ###########################################################################
    # At this point, we have achieved a translation-only registration of the
    # anatomical images to each other's brain's (as defined by the brain
    # masker) CoMs.
    ###########################################################################
    # Rigid-body registration (shift rotate in AFNI parlance)
    # -------------------------------------------------------
    # Now we move on to the rigid-body registration of CoM brains, and
    # application of this registration to CoM heads. This requires a target
    # template. Here we use the mean of all bias-corrected, brain-extracted,
    # mass-centered images. Other possibilities include an externally-sourced
    # image or, more biased, a nicely-aligned individual.
    #
    # In extreme cases where acquisitions were done at highly variable head
    # angles, it may be worth running this twice or even more (for which there
    # is no current functionality), but we have never found a case that extreme
    # so it is not implemented.

    # rigid-body registration
    shift_rotated_brain_files = []
    rigid_transform_files = []
    for centered_brain_file in centered_brain_files:
        suffixed_matrix = fname_presuffix(centered_brain_file,
                                          suffix='_shr.aff12.1D',
                                          use_ext=False)
        out_matrix = os.path.join(write_dir, os.path.basename(suffixed_matrix))
        out_allineate = allineate(
            in_file=centered_brain_file,
            reference=out_tstat_centered_brain.outputs.out_file,
            out_matrix=out_matrix,
            convergence=convergence,
            two_blur=blur_radius_coarse,
            warp_type='shift_rotate',
            out_file=fname_presuffix(centered_brain_file, suffix='_shr'),
            **verbosity_quietness_kwargs)
        rigid_transform_files.append(out_allineate.outputs.out_matrix)
        shift_rotated_brain_files.append(out_allineate.outputs.out_file)

    # application to the head images
    shift_rotated_head_files = []
    for centered_head_file, rigid_transform_file in zip(
            centered_head_files, rigid_transform_files):
        suffixed_file = fname_presuffix(centered_head_file, suffix='_shr')
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_allineate = allineate2(
            in_file=centered_head_file,
            master=out_tstat_centered_brain.outputs.out_file,
            in_matrix=rigid_transform_file,
            out_file=out_file,
            **verbosity_quietness_kwargs)
        shift_rotated_head_files.append(out_allineate.outputs.out_file)

    # quality check video and mean for head and brain
    out_tcat = tcat(in_files=shift_rotated_head_files,
                    out_file=os.path.join(
                        write_dir, 'rigid_body_registered_heads.nii.gz'),
                    **verbosity_kwargs)
    out_tstat_shr = tstat(in_file=out_tcat.outputs.out_file,
                          outputtype='NIFTI_GZ')
    out_tcat = tcat(in_files=shift_rotated_brain_files,
                    out_file=os.path.join(
                        write_dir, 'rigid_body_registered_brains.nii.gz'),
                    **verbosity_kwargs)
    out_tstat_shr = tstat(in_file=out_tcat.outputs.out_file,
                          outputtype='NIFTI_GZ')

    if registration_kind == 'rigid':
        os.chdir(current_dir)
        return Bunch(registered=shift_rotated_head_files,
                     transforms=rigid_transform_files)

    ###########################################################################
    # Affine transform
    # ----------------
    # Similar to the previous rigid-body registration but with the following
    # differences:
    # 1) The registration target is now the product of rigid-body rather than
    #    CoM registration.
    # 2) Rather than using the mean brain as a target, the mean head is used,
    #    weighted by a mask made by binarizing the brains and making a count
    #    mask out of them. This should mathematically be exactly the same thing
    #    and was done this way partially for fun, partially to make more use of
    #    the count mask, whose main purpose is to demonstrate variability in
    #    brain size and extraction quality.
    # 3) There is an extra step for concatenation of transform results.

    # make the count mask
    out_mask_tool = mask_tool(in_file=out_tcat.outputs.out_file,
                              count=True,
                              verbose=verbose,
                              outputtype='NIFTI_GZ')

    #affine transform
    affine_transform_files = []
    for shift_rotated_head_file, rigid_transform_file in zip(
            shift_rotated_head_files, rigid_transform_files):
        out_allineate = allineate(
            in_file=shift_rotated_head_file,
            reference=out_tstat_shr.outputs.out_file,
            out_matrix=fname_presuffix(shift_rotated_head_file,
                                       suffix='_affine.aff12.1D',
                                       use_ext=False),
            convergence=convergence,
            two_blur=blur_radius_coarse,
            one_pass=True,
            weight=out_mask_tool.outputs.out_file,
            out_file=fname_presuffix(shift_rotated_head_file,
                                     suffix='_affine'),
            **verbosity_quietness_kwargs)
        # matrix concatenation
        suffixed_matrix = fname_presuffix(shift_rotated_head_file,
                                          suffix='_affine_catenated.aff12.1D',
                                          use_ext=False)
        catmatvec_out_file = os.path.join(write_dir,
                                          os.path.basename(suffixed_matrix))
        out_catmatvec = catmatvec(in_file=[(rigid_transform_file, 'ONELINE'),
                                           (out_allineate.outputs.out_matrix,
                                            'ONELINE')],
                                  out_file=catmatvec_out_file)
        affine_transform_files.append(catmatvec_out_file)

    # application to brains
    allineated_brain_files = []
    for centered_brain_file, affine_transform_file in zip(
            centered_brain_files, affine_transform_files):
        out_allineate = allineate2(in_file=centered_brain_file,
                                   master=out_tstat_shr.outputs.out_file,
                                   in_matrix=affine_transform_file,
                                   out_file=fname_presuffix(
                                       centered_brain_file,
                                       suffix='_shr_affine_catenated'),
                                   **verbosity_quietness_kwargs)
        allineated_brain_files.append(out_allineate.outputs.out_file)

    # application to heads
    allineated_head_files = []
    for centered_head_file, affine_transform_file in zip(
            centered_head_files, affine_transform_files):
        suffixed_file = fname_presuffix(centered_head_file,
                                        suffix='_shr_affine_catenated')
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_allineate = allineate2(in_file=centered_head_file,
                                   master=out_tstat_shr.outputs.out_file,
                                   in_matrix=affine_transform_file,
                                   out_file=out_file,
                                   **verbosity_quietness_kwargs)
        allineated_head_files.append(out_allineate.outputs.out_file)

    #quality check videos and template for head and brain
    out_tcat_head = tcat(in_files=allineated_head_files,
                         out_file=os.path.join(
                             write_dir, 'affine_registered_heads.nii.gz'),
                         **verbosity_kwargs)
    out_tstat_allineated_head = tstat(in_file=out_tcat_head.outputs.out_file,
                                      outputtype='NIFTI_GZ')
    out_tcat_brain = tcat(in_files=allineated_brain_files,
                          out_file=os.path.join(
                              write_dir, 'affine_registered_brains.nii.gz'),
                          **verbosity_kwargs)
    out_tstat_allineated_brain = tstat(in_file=out_tcat_brain.outputs.out_file,
                                       outputtype='NIFTI_GZ')

    if registration_kind == 'affine':
        os.chdir(current_dir)
        return Bunch(registered=allineated_head_files,
                     transforms=affine_transform_files)

    ###########################################################################
    # Non-linear registration
    # -----------------------
    # A weight mask that extends beyond the brain, incorporating some
    # surrounding tissue, is needed to help better define the brain head
    # boundary.
    if nonlinear_weight_file is None:
        out_mask_tool = mask_tool(
            in_file=out_tcat.outputs.out_file,
            union=True,
            out_file=os.path.join(write_dir,
                                  'affine_registered_brains_unionmask.nii.gz'),
            outputtype='NIFTI_GZ',
            verbose=verbose)
        out_mask_tool = mask_tool(
            in_file=out_mask_tool.outputs.out_file,
            out_file=os.path.join(
                write_dir, 'affine_registered_brains_unionmask_dil4.nii.gz'),
            dilate_inputs='4',
            outputtype='NIFTI_GZ',
            verbose=verbose)
        nonlinear_weight_file = out_mask_tool.outputs.out_file

    ###########################################################################
    # Description to fill
    #
    #
    if nonlinear_levels is None:
        nonlinear_levels = [1, 2, 3]
    if nonlinear_minimal_patches is None:
        nonlinear_minimal_patches = []
    levels_minpatches = nonlinear_levels + nonlinear_minimal_patches

    for n_iter, level_or_minpatch in enumerate(levels_minpatches):

        if n_iter == 0:
            previous_warp_files = affine_transform_files
        warped_files = []
        warp_files = []

        for warp_file, centered_head_file in zip(previous_warp_files,
                                                 centered_head_files):

            out_file = fname_presuffix(centered_head_file,
                                       suffix='_warped{}'.format(n_iter))

            if n_iter == 0:
                out_nwarp_cat = nwarp_cat(
                    in_files=[('IDENT', centered_head_file), warp_file],
                    out_file=fname_presuffix(centered_head_file,
                                             suffix='_iniwarp'))
                out_qwarp = qwarp(
                    in_file=centered_head_file,
                    base_file=out_tstat_allineated_head.outputs.out_file,
                    noneg=True,
                    iwarp=True,
                    weight=nonlinear_weight_file,
                    iniwarp=[out_nwarp_cat.outputs.out_file],
                    inilev=0,
                    maxlev=level_or_minpatch,
                    out_file=out_file,
                    **verbosity_quietness_kwargs)

            elif n_iter < len(nonlinear_levels):
                out_qwarp = qwarp(in_file=centered_head_file,
                                  base_file=nwarp_adjusted_mean,
                                  noneg=True,
                                  iwarp=True,
                                  weight=nonlinear_weight_file,
                                  iniwarp=[warp_file],
                                  inilev=levels_minpatches[n_iter - 1] + 1,
                                  maxlev=level_or_minpatch,
                                  out_file=out_file,
                                  **verbosity_quietness_kwargs)

            else:
                out_qwarp = qwarp2(
                    in_file=centered_head_file,
                    base_file=nwarp_adjusted_mean,
                    noneg=True,
                    iwarp=True,
                    weight=nonlinear_weight_file,
                    iniwarp=[warp_file],
                    inilev=nonlinear_levels[-1] + 1,  # not ideal
                    minpatch=level_or_minpatch,
                    out_file=out_file)

            warped_files.append(out_qwarp.outputs.warped_source)
            warp_files.append(out_qwarp.outputs.source_warp)
            previous_warp_files = warp_files

        out_tcat = tcat(
            in_files=warped_files,
            out_file=os.path.join(
                write_dir,
                'warped_{0}iters_hetemplate_filenameads.nii.gz'.format(
                    n_iter)),
            **verbosity_kwargs)
        out_tstat_warp_head = tstat(in_file=out_tcat.outputs.out_file,
                                    outputtype='NIFTI_GZ')

        nwarp_adjusted_mean = 'warped_{0}_adjusted_mean.nii.gz'.format(n_iter)
        out_nwarp_adjust = nwarp_adjust(warps=warp_files,
                                        in_files=centered_head_files,
                                        out_file=nwarp_adjusted_mean)

    ###########################################################################
    # Register to template
    # --------------------
    # Apply non-linear registration results to uncorrected images
    warped_files = []
    for centered_head_file, warp_file in zip(centered_head_files, warp_files):
        suffixed_file = fname_presuffix(
            centered_head_file,
            suffix='affine_warp{}_catenated'.format(len(nonlinear_levels)))
        out_file = os.path.join(write_dir, os.path.basename(suffixed_file))
        out_warp_apply = warp_apply(
            in_file=centered_head_file,
            warp=warp_file,
            master=out_tstat_warp_head.outputs.out_file,
            out_file=out_file,
            **verbosity_quietness_kwargs)
        warped_files.append(out_warp_apply.outputs.out_file)

    os.chdir(current_dir)
    return Bunch(registered=warped_files, transforms=warp_files)