Esempio n. 1
0
def main(argv):
    from mindboggle.utils.io_vtk import write_vtk
    closed_fundus_lines, points, faces = propagate_fundus_lines(argv[1],
                                                                argv[2],
                                                                argv[3])
    write_vtk(argv[4], points, faces=faces, scalars=closed_fundus_lines,
              scalar_type='int')
Esempio n. 2
0
def fundiFromPits(Pits, Maps, Mesh, FundiVTK, SulciThld, SulciMap, Extract_Fundi_on_Map):
    '''Connecting pits into fundus curves

    Parameters
    ============

        Pits: list of integers
            IDs of vertexes that are pits

        Maps: dictionary of lists of floats
            Keys are strings, e.g., meancurv, depth, etc.
            Values are list of per-vertex values that will be used as structure feature vectors, e.g., thickness

        Mesh: List of two lists of floats/integers
            The first are points from a VTK file.
            The second are triangular faces from a VTK file.

        Vrtx: list of 3-tuples of floats
            Each element is the X-, Y- and Z-cooridnates of a vertex on the surface, normally pial

        Fc: list of 3-tuples of integers
            Each element is the ids of 3 vertexes that form one triangle on the surface

        SulciThld: a float
            The number that was used to threhold the surface to get sulci.
            This is need for loading component file, but it has nothing to do fundi extraction itself

        Extract_Fundi_on_Map: string
            The key for the map on which fundi will be built (default: depth)

    Notes
    ========

        Function and variable names are not fully changed yet. Names like curvature is bad.

    '''

    [Vrtx, Fc] = Mesh

    scalar_names = [Name for Name in Maps.iterkeys()]
    scalar_lists = [scalar_list for scalar_list in Maps.itervalues()]

    LastSlash = len(FundiVTK) - FundiVTK[::-1].find('/')
    Hemi =  FundiVTK[:FundiVTK[LastSlash:].find('.')+LastSlash]# path up to which hemisphere, e.g., /home/data/lh
    NbrLst = libbasin.vrtxNbrLst(len(Vrtx), Fc, Hemi)

    FcCmpnt, VrtxCmpnt = libbasin.compnent([], [], [], ".".join([Hemi, SulciMap, str(SulciThld)]))

    PSegs, NodeColor, FundusLen, FundusID = lineUp(Pits, NbrLst, VrtxCmpnt, Vrtx, Maps[Extract_Fundi_on_Map])

    len_scalars = [0 for i in xrange(0,len(NbrLst))]
    for Key, Value in FundusLen.iteritems():
        len_scalars[Key] = Value
    scalar_names.append('fundusLength')
    scalar_lists.append(len_scalars)

    FIDscalars = [-1 for i in xrange(0,len(NbrLst))] # value for gyri is now -1 Forrest 2011-11-01
    for Key, Value in FundusID.iteritems():
        FIDscalars[Key] = Value
    scalar_names.append('fundusID')
    scalar_lists.append(FIDscalars)

#    io_vtk.write_lines(FundiVTK, Vrtx, Pits, PSegs, scalar_lists, scalar_names)
    io_vtk.write_vtk(FundiVTK, Vrtx, indices=Pits, lines=PSegs, faces=[],
     scalars=scalar_lists, scalar_names=scalar_names, scalar_type='int')
Esempio n. 3
0
def close_surface_pair_from_files(patch_surface1, whole_surface2,
                                  background_value=-1, output_vtk=''):
    """
    Close a surface patch by connecting its border vertices with
    corresponding vertices in a second surface file.

    Assumes no lines or indices when reading VTK files in.

    Note ::

        The first VTK file contains scalar values different than background
        for a surface patch.  The second VTK file contains the (entire)
        surface whose corresponding vertices are shifted in position.
        For pial vs. gray-white matter, the two surfaces are not parallel,
        so connecting the vertices leads to intersecting faces.

    Parameters
    ----------
    patch_surface1 : string
        vtk file with surface patch of non-background scalar values
    whole_surface2 : string
        second vtk file with 1-to-1 vertex correspondence with patch_surface1
        (whole surface so as to derive vertex neighbor lists)
    background_value : integer
        scalar value for background vertices
    output_vtk : string
        output vtk file name with closed surface patch

    Returns
    -------
    output_vtk : string
        output vtk file name with closed surface patch

    Examples
    --------
    >>> import os
    >>> from mindboggle.utils.morph import close_surface_pair_from_files
    >>> from mindboggle.utils.plots import plot_surfaces
    >>> from mindboggle.utils.io_vtk import read_scalars, read_vtk, read_points, write_vtk
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> patch_surface1 = 'fold.pial.vtk'
    >>> whole_surface2 = 'fold.white.vtk'
    >>> # Select a single fold:
    >>> folds_file = os.path.join(path, 'arno', 'features', 'folds.vtk')
    >>> points = read_points(folds_file)
    >>> folds, name = read_scalars(folds_file, True, True)
    >>> fold_number = 11
    >>> folds[folds != fold_number] = -1
    >>> white_surface = os.path.join(path, 'arno', 'freesurfer', 'lh.white.vtk')
    >>> faces, u1, u2, points2, N, u3, u4, u5 = read_vtk(white_surface)
    >>> write_vtk(patch_surface1, points, [], [], faces, folds, name)
    >>> write_vtk(whole_surface2, points2, [], [], faces, folds, name)
    >>> background_value = -1
    >>> output_vtk = ''
    >>> close_surface_pair_from_files(patch_surface1, whole_surface2, background_value, output_vtk)
    >>> # View:
    >>> plot_surfaces('closed.vtk') # doctest: +SKIP

    """
    import os
    import numpy as np

    from mindboggle.utils.io_vtk import read_vtk, write_vtk
    from mindboggle.utils.morph import close_surface_pair

    # Read VTK surface mesh files:
    u1, u2, u3, points1, N, scalars, name, u4 = read_vtk(patch_surface1,
                                                         True, True)
    faces, u1, u2, points2, N, u3, u4, u5 = read_vtk(whole_surface2,
                                                     True, True)

    # Close surface:
    closed_faces, closed_points, closed_scalars = close_surface_pair(faces,
        points1, points2, scalars, background_value)

    # Write output file:
    if not output_vtk:
        output_vtk = os.path.join(os.getcwd(), 'closed.vtk')
    # closed_scalars is a list
    if np.ndim(closed_scalars) == 1:
        scalar_type = type(closed_scalars[0]).__name__
    elif np.ndim(closed_scalars) == 2:
        scalar_type = type(closed_scalars[0][0]).__name__
    else:
        print("Undefined scalar type!")
    write_vtk(output_vtk, closed_points, [], [], closed_faces, closed_scalars,
              name, scalar_type=scalar_type)

    return output_vtk
Esempio n. 4
0
def close_surface_pair_from_files(patch_surface1,
                                  whole_surface2,
                                  background_value=-1,
                                  output_vtk=''):
    """
    Close a surface patch by connecting its border vertices with
    corresponding vertices in a second surface file.

    Assumes no lines or indices when reading VTK files in.

    Note ::

        The first VTK file contains scalar values different than background
        for a surface patch.  The second VTK file contains the (entire)
        surface whose corresponding vertices are shifted in position.
        For pial vs. gray-white matter, the two surfaces are not parallel,
        so connecting the vertices leads to intersecting faces.

    Parameters
    ----------
    patch_surface1 : string
        vtk file with surface patch of non-background scalar values
    whole_surface2 : string
        second vtk file with 1-to-1 vertex correspondence with patch_surface1
        (whole surface so as to derive vertex neighbor lists)
    background_value : integer
        scalar value for background vertices
    output_vtk : string
        output vtk file name with closed surface patch

    Returns
    -------
    output_vtk : string
        output vtk file name with closed surface patch

    Examples
    --------
    >>> import os
    >>> from mindboggle.utils.morph import close_surface_pair_from_files
    >>> from mindboggle.utils.plots import plot_surfaces
    >>> from mindboggle.utils.io_vtk import read_scalars, read_vtk, read_points, write_vtk
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> patch_surface1 = 'fold.pial.vtk'
    >>> whole_surface2 = 'fold.white.vtk'
    >>> # Select a single fold:
    >>> folds_file = os.path.join(path, 'arno', 'features', 'folds.vtk')
    >>> points = read_points(folds_file)
    >>> folds, name = read_scalars(folds_file, True, True)
    >>> fold_number = 11
    >>> folds[folds != fold_number] = -1
    >>> white_surface = os.path.join(path, 'arno', 'freesurfer', 'lh.white.vtk')
    >>> faces, u1, u2, points2, N, u3, u4, u5 = read_vtk(white_surface)
    >>> write_vtk(patch_surface1, points, [], [], faces, folds, name)
    >>> write_vtk(whole_surface2, points2, [], [], faces, folds, name)
    >>> background_value = -1
    >>> output_vtk = ''
    >>> close_surface_pair_from_files(patch_surface1, whole_surface2, background_value, output_vtk)
    >>> # View:
    >>> plot_surfaces('closed.vtk') # doctest: +SKIP

    """
    import os
    import numpy as np

    from mindboggle.utils.io_vtk import read_vtk, write_vtk
    from mindboggle.utils.morph import close_surface_pair

    # Read VTK surface mesh files:
    u1, u2, u3, points1, N, scalars, name, u4 = read_vtk(
        patch_surface1, True, True)
    faces, u1, u2, points2, N, u3, u4, u5 = read_vtk(whole_surface2, True,
                                                     True)

    # Close surface:
    closed_faces, closed_points, closed_scalars = close_surface_pair(
        faces, points1, points2, scalars, background_value)

    # Write output file:
    if not output_vtk:
        output_vtk = os.path.join(os.getcwd(), 'closed.vtk')
    # closed_scalars is a list
    if np.ndim(closed_scalars) == 1:
        scalar_type = type(closed_scalars[0]).__name__
    elif np.ndim(closed_scalars) == 2:
        scalar_type = type(closed_scalars[0][0]).__name__
    else:
        print("Undefined scalar type!")
    write_vtk(output_vtk,
              closed_points, [], [],
              closed_faces,
              closed_scalars,
              name,
              scalar_type=scalar_type)

    return output_vtk
def realign_boundaries_to_fundus_lines(
    surf_file, init_label_file, fundus_lines_file, thickness_file,
    out_label_file=None):
    """
    Fix label boundaries to fundus lines.

    Parameters
    ----------
    surf_file : file containing the surface geometry in vtk format
    init_label_file : file containing scalars that represent the
                      initial guess at labels
    fundus_lines_file : file containing scalars representing fundus lines.
    thickness_file: file containing cortical thickness scalar data
    (for masking out the medial wall only)
    out_label_file : if specified, the realigned labels will be writen to
                     this file

    Returns
    -------
    numpy array representing the realigned label for each surface vertex.
    """

    import numpy as np
    from mindboggle.utils.segment import extract_borders
    import mindboggle.utils.graph as go
    from mindboggle.utils.io_vtk import read_vtk, read_scalars, write_vtk
    from mindboggle.utils.mesh import find_neighbors
    import propagate_fundus_lines

    ## read files
    faces, _, indices, points, num_points, _, _, _ = read_vtk(
        surf_file, return_first=True, return_array=True)
    indices = range(num_points)

    init_labels, _ = read_scalars(init_label_file,
                                  return_first=True, return_array=True)

    fundus_lines, _ = read_scalars(fundus_lines_file,
                                   return_first=True, return_array=True)

    thickness, _ = read_scalars(thickness_file,
                             return_first=True, return_array=True)

    # remove labels from vertices with zero thickness (get around
    # DKT40 annotations having the label '3' for all the Corpus
    # Callosum vertices).
    cc_inds = [x for x in indices if thickness[x] < 0.001]
    init_labels[cc_inds] = 0

    ## setup seeds from initial label boundaries
    neighbor_lists = find_neighbors(faces, num_points)

    # extract all vertices that are on a boundary between labels
    boundary_indices, label_pairs, _ = extract_borders(
        indices, init_labels, neighbor_lists,
        return_label_pairs=True)

    # split boundary vertices into segments with common boundary pairs.
    boundary_segments = {}
    for boundary_index, label_pair in zip(boundary_indices, label_pairs):
        key = ((label_pair[0], label_pair[1]) if label_pair[0] < label_pair[1]
               else (label_pair[1], label_pair[0]))
        if key not in boundary_segments:
            boundary_segments[key] = []

        boundary_segments[key].append(boundary_index)

    boundary_matrix, boundary_matrix_keys = _build_boundary_matrix(
        boundary_segments, num_points)

    # build the affinity matrix
    affinity_matrix = go.weight_graph(
       np.array(points), indices, np.array(faces), sigma=10, add_to_graph=False)

    ## propagate boundaries to fundus line vertices
    learned_matrix = _propagate_labels(
       affinity_matrix, boundary_matrix, boundary_indices, 100, 1)

    # assign labels to fundus line vertices based on highest probability
    new_boundaries = -1 * np.ones(init_labels.shape)
    fundus_line_indices = [i for i, x in enumerate(fundus_lines) if x > 0.5]

    # tile the surface into connected components delimited by fundus lines
    closed_fundus_lines, _, _ = propagate_fundus_lines.propagate_fundus_lines(
        points, faces, fundus_line_indices, thickness)

    closed_fundus_line_indices = np.where(closed_fundus_lines > 0)[0]

    # split surface into connected components
    connected_component_faces = _remove_boundary_faces(
        points, faces, closed_fundus_line_indices)

    # label components based on most probable label assignment
    new_labels = _label_components(
        connected_component_faces, num_points, boundary_indices, learned_matrix,
        boundary_matrix_keys)

    # propagate new labels to fill holes
    label_matrix, label_map = _build_label_matrix(new_labels)
    new_learned_matrix = _propagate_labels(
        affinity_matrix, label_matrix,
        [i for i in range(num_points) if new_labels[i] >= 0], 100, 1)

    # assign most probable labels
    for idx in [i for i in range(num_points) if new_labels[i] == -1]:
        max_idx = np.argmax(new_learned_matrix[idx])
        new_labels[idx] = label_map[max_idx]

    # save
    if out_label_file is not None:
        write_vtk(out_label_file, points, faces=faces,
                  scalars=[int(x) for x in new_labels], scalar_type='int')

    return new_labels
Esempio n. 6
0
def explode_scalars(input_indices_vtk, input_values_vtk='', output_stem='',
                    exclude_values=[-1], background_value=-1,
                    output_scalar_name='scalars',
                    remove_background_faces=True, reindex=True):
    """
    Write out a separate VTK file for each integer (not in exclude_values)
    in (the first) scalar list of an input VTK file.
    Optionally write the values drawn from a second VTK file,
    remove background values, and reindex indices.

    Parameters
    ----------
    input_indices_vtk : string
        path of the input VTK file that contains indices as scalars
        (assumes that the scalars are a list of floats or integers)
    input_values_vtk : string
        path of the input VTK file that contains values as scalars
    output_stem : string
        path and stem of the output VTK file
    exclude_values : list or array
        values to exclude
    background_value : integer or float
        background value in output VTK files
    remove_background_faces : Boolean
        remove all faces whose three vertices are not all a given index?
    reindex : Boolean
        reindex all indices in faces?

    Examples
    --------
    >>> # Example 1:  explode sulci with thickness values
    >>> import os
    >>> from mindboggle.utils.io_vtk import explode_scalars
    >>> from mindboggle.utils.plots import plot_surfaces
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> input_indices_vtk = os.path.join(path, 'arno', 'features', 'sulci.vtk')
    >>> input_values_vtk = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk')
    >>> output_stem = 'sulci_depth'
    >>> #
    >>> explode_scalars(input_indices_vtk, input_values_vtk, output_stem)
    >>> #
    >>> # View:
    >>> example_vtk = os.path.join(os.getcwd(), output_stem + '0.vtk')
    >>> plot_surfaces(example_vtk)
    >>> #
    >>> # Example 2:  explode labels
    >>> import os
    >>> from mindboggle.utils.io_vtk import explode_scalars
    >>> from mindboggle.utils.plots import plot_surfaces
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> input_values_vtk = os.path.join(path, 'arno', 'labels',
    >>>                                 'lh.labels.DKT25.manual.vtk')
    >>> input_indices_vtk = input_values_vtk
    >>> output_stem = 'label'
    >>> exclude_values = [-1]
    >>> background_value = -1,
    >>> output_scalar_name = 'scalars'
    >>> remove_background_faces = True
    >>> reindex = True
    >>> #
    >>> explode_scalars(input_indices_vtk, input_values_vtk, output_stem,
    >>>                 exclude_values, background_value,
    >>>                 output_scalar_name, remove_background_faces, reindex)
    >>> # View:
    >>> example_vtk = os.path.join(os.getcwd(), output_stem + '2.vtk')
    >>> plot_surfaces(example_vtk)

    """
    import os
    import numpy as np
    from mindboggle.utils.io_vtk import read_scalars, read_vtk, write_vtk
    from mindboggle.utils.mesh import reindex_faces_points, remove_faces

    # Load VTK file:
    faces, lines, indices, points, npoints, scalars, scalar_names, \
        foo1 = read_vtk(input_indices_vtk, True, True)
    print("Explode the scalar list in {0}".
          format(os.path.basename(input_indices_vtk)))
    if input_values_vtk != input_indices_vtk:
        values, name = read_scalars(input_values_vtk, True, True)
        print("Explode the scalar list of values in {0} "
              "with the scalar list of indices in {1}".
              format(os.path.basename(input_values_vtk),
                     os.path.basename(input_indices_vtk)))
    else:
        values = np.copy(scalars)

    # Loop through unique (non-excluded) scalar values:
    unique_scalars = np.unique(scalars)
    if all(unique_scalars==np.round(unique_scalars)):
        unique_scalars = [int(x) for x in unique_scalars
                          if x not in exclude_values]
    else:
        unique_scalars = [x for x in unique_scalars
                          if x not in exclude_values]

    for scalar in unique_scalars:

        # Remove background (keep only faces with the scalar):
        if remove_background_faces:
            scalar_indices = [i for i,x in enumerate(scalars) if x == scalar]
            scalar_faces = remove_faces(faces, scalar_indices)
        else:
            scalar_faces = faces

        # Reindex:
        if reindex:
            scalar_faces, select_points, \
            o1 = reindex_faces_points(scalar_faces, points)
        else:
            select_points = points

        # Create array and indices for scalar value:
        if reindex:
            len_indices = len(select_points)
            select_values = scalar * np.ones(len_indices)
        else:
            select_values = np.copy(values)
            select_values[scalars != scalar] = background_value
            len_indices = len([i for i,x in enumerate(select_values)
                               if x != background_value])

        print("  Scalar {0}: {1} vertices".format(scalar, len_indices))

        # Write VTK file with scalar values (list of values):
        if np.ndim(select_values) == 1:
            scalar_type = type(select_values[0]).__name__
        elif np.ndim(select_values) == 2:
            scalar_type = type(select_values[0][0]).__name__
        else:
            print("Undefined scalar type!")
        output_vtk = os.path.join(os.getcwd(),
                                  output_stem + str(scalar) + '.vtk')
        write_vtk(output_vtk, select_points, indices, lines, scalar_faces,
                  select_values.tolist(), output_scalar_name,
                  scalar_type=scalar_type)
Esempio n. 7
0
def apply_affine_transform(transform_file, vtk_or_points,
                           transform_format='itk', vtk_file_stem='affine_'):
    """
    Transform coordinates using an affine matrix.

    Parameters
    ----------
    transform file : string
        name of affine transform file
    vtk_or_points : string or list of lists of three integers
        name of VTK file containing point coordinate data, or the data
        (if vtk file, assumes scalars are a list of floats or integers)
    transform_format : string
        format for transform file (currently 'itk');
        complications arise with other formats, such as
        'txt' for text, or 'mat' for Matlab format, since
        software-specific assignment of parameters such as
        the origin need to be taken into account
    vtk_file_stem : string
        save transformed coordinates in a vtk file with this file append
        (empty string if vtk_or_points is points)

    Returns
    -------
    affine_points : list of lists of floats
        transformed coordinates
    output_file : string or None (if not vtk_file_stem or vtk_or_points is points)
        name of VTK file containing transformed point data

    Examples
    --------
    >>> import os
    >>> from mindboggle.utils.io_vtk import apply_affine_transform
    >>> from mindboggle.utils.plots import plot_surfaces
    >>> #path = os.environ['MINDBOGGLE_DATA']
    >>> #transform_file = os.path.join(path, 'arno', 'mri',
    >>> #   't1weighted_brain.MNI152Affine.txt')
    >>> transform_file = '/Users/arno/mindboggle_working/OASIS-TRT-20-1/Mindboggle/Compose_affine_transform/affine.txt'
    >>> vtk_or_points = '/Users/arno/mindboggle_working/OASIS-TRT-20-1/Mindboggle/_hemi_lh/Surface_to_vtk/lh.pial.vtk'
    >>> transform_format = 'itk'
    >>> vtk_file_stem = True
    >>> affine_points, output_file = apply_affine_transform(transform_file, vtk_or_points, transform_format, vtk_file_stem)
    >>> # View
    >>> plot_surfaces('affine_lh.pial.vtk')

    """
    import os
    import numpy as np
    from scipy.io import loadmat

    from mindboggle.utils.io_vtk import read_vtk, write_vtk, read_itk_transform
    from mindboggle.utils.ants import antsApplyTransformsToPoints

    # Read affine transform file:
    if transform_format == 'itk':
        #pass
        transform = read_itk_transform(transform_file)
    elif transform_format == 'txt':
        transform = np.loadtxt(transform_file)
    elif transform_format == 'mat':
        transform = loadmat(transform_file)
    else:
        import sys
        sys.exit('Transform file format not understood.')

    # Read VTK file:
    if isinstance(vtk_or_points, str):
        faces, lines, indices, points, npoints, scalars, name, \
            foo1 = read_vtk(vtk_or_points)
        points = np.array(points)
    elif isinstance(vtk_or_points, list):
        points = np.array(vtk_or_points)
        vtk_file_stem = ''
    elif isinstance(vtk_or_points, np.ndarray):
        points = vtk_or_points.copy()
        vtk_file_stem = ''

    # Transform points:
    if transform_format == 'itk':
        affine_points = antsApplyTransformsToPoints(points,
                                                    [transform_file], [0])
        #points = np.concatenate((points,
        #                         np.ones((np.shape(points)[0],1))), axis=1)
        #affine_points = np.transpose(np.dot(transform,
        #                                    np.transpose(points)))[:,0:3]
        #affine_points = [x.tolist() for x in affine_points]
    else:
        points = np.concatenate((points,
                                 np.ones((np.shape(points)[0],1))), axis=1)
        affine_points = np.transpose(np.dot(transform,
                                            np.transpose(points)))[:,0:3]
        affine_points = [x.tolist() for x in affine_points]

    # Write transformed VTK file:
    if vtk_file_stem and isinstance(vtk_or_points, str):
        output_file = os.path.join(os.getcwd(), vtk_file_stem +
                                   os.path.basename(vtk_or_points))
        if np.size(scalars):
            if np.ndim(scalars) == 1:
                scalar_type = type(scalars[0]).__name__
            elif np.ndim(scalars) == 2:
                scalar_type = type(scalars[0][0]).__name__
            else:
                print("Undefined scalar type!")
        else:
            scalars = []
            scalar_type = 'int'

        write_vtk(output_file, affine_points, indices, lines, faces,
                  scalars, name, scalar_type)
    else:
        output_file = None

    return affine_points, output_file
Esempio n. 8
0
def relabel_surface(vtk_file, hemi='', old_labels=[], new_labels=[],
                    output_file=''):
    """
    Relabel surface in a VTK file.

    Parameters
    ----------
    vtk_file : string
        input labeled VTK file
    hemi : string
        hemisphere ('lh' or 'rh' or '')
    old_labels : list of integers
        old labels
    new_labels : list of integers
        new labels
    output_file : string
        new vtk file name

    Returns
    -------
    output_file : string
        new vtk file name

    Examples
    --------
    >>> import os
    >>> from mindboggle.labels.relabel import relabel_surface
    >>> from mindboggle.utils.plots import plot_vtk
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> vtk_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk')
    >>> hemi = 'lh'
    >>> old_labels = []
    >>> new_labels = []
    >>> output_file = ''
    >>> #
    >>> relabel_surface(vtk_file, hemi, old_labels, new_labels, output_file)
    >>> # View
    >>> plot_vtk('relabeled_lh.labels.DKT25.manual.vtk')

    """
    import os
    import numpy as np
    from mindboggle.utils.io_vtk import read_vtk, write_vtk

    # Load labeled vtk surfaces:
    faces, lines, indices, points, npoints, scalars, \
        name, input_vtk = read_vtk(vtk_file, return_first=True, return_array=True)

    # Add a hemisphere value to each label:
    if hemi:
        ulabels = np.unique(scalars)
        for label in ulabels:
            I = np.where(scalars == int(label))[0]
            if hemi == 'lh':
                scalars[I] = 1000 + int(label)
            elif hemi == 'rh':
                scalars[I] = 2000 + int(label)
    # OR replace each old label with a corresponding new label:
    else:
        for ilabel, new_label in enumerate(new_labels):
            I = np.where(scalars == int(old_labels[ilabel]))[0]
            scalars[I] = int(new_label)

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'relabeled_' + os.path.basename(vtk_file))
    write_vtk(output_file, points, indices, lines, faces,
              [scalars.tolist()], ['Labels'])

    return output_file
Esempio n. 9
0
def realign_boundaries_to_fundus_lines(
    surf_file, init_label_file, fundus_lines_file, out_label_file=None):
    """
    Fix label boundaries to fundus lines.

    Parameters
    ----------
    surf_file : file containing the surface geometry in vtk format
    init_label_file : file containing scalars that represent the
                      initial guess at labels
    fundus_lines_file : file containing scalars representing fundus  lines.
    out_label_file : if specified, the realigned labels will be writen to
                     this file

    Returns
    -------
    numpy array representing the realigned label for each surface vertex.
    """

#    import os
    import numpy as np
    from mindboggle.labels.labels import extract_borders
    import mindboggle.utils.graph as go
    from mindboggle.utils.io_vtk import read_vtk, read_scalars, write_vtk
#    import mindboggle.utils.kernels as kernels
    from mindboggle.utils.mesh import find_neighbors
#    from mindboggle.labels.protocol import dkt_protocol
#
#    protocol = 'DKT25'
#    sulcus_names, sulcus_label_pair_lists, unique_sulcus_label_pairs, \
#        label_names, label_numbers, cortex_names, cortex_numbers, \
#        noncortex_names, noncortex_numbers = dkt_protocol(protocol)

    ## read files
    faces, _, indices, points, num_points, _, _, _ = read_vtk(
        surf_file, return_first=True, return_array=True)
    indices = range(num_points)

    init_labels, _ = read_scalars(init_label_file,
                                  return_first=True, return_array=True)

    fundus_lines, _ = read_scalars(fundus_lines_file,
                                   return_first=True, return_array=True)

    ## setup seeds from initial label boundaries
    neighbor_lists = find_neighbors(faces, num_points)

    # extract all vertices that are on a boundary between labels
    boundary_indices, label_pairs, _ = extract_borders(
        indices, init_labels, neighbor_lists,
        return_label_pairs=True)

    # split boundary vertices into segments with common boundary pairs.
    boundary_segments = {}
    for boundary_index, label_pair in zip(boundary_indices, label_pairs):
        key = ((label_pair[0], label_pair[1]) if label_pair[0] < label_pair[1]
               else (label_pair[1], label_pair[0]))
        if key not in boundary_segments:
            boundary_segments[key] = []

        boundary_segments[key].append(boundary_index)

    boundary_matrix, boundary_matrix_keys = _build_boundary_matrix(
        boundary_segments, num_points)

    # build the affinity matrix
    affinity_matrix = go.weight_graph(
       np.array(points), indices, np.array(faces), sigma=10, add_to_graph=False)

    ## propagate boundaries to fundus line vertices
    learned_matrix = _propagate_labels(
       affinity_matrix, boundary_matrix, boundary_indices, 1000, 1)

    # assign labels to fundus line vertices based on highest probability
    new_boundaries = -1 * np.ones(init_labels.shape)
    fundus_line_indices = [i for i, x in enumerate(fundus_lines) if x > 0.5]

    # TODO: this currently only works for fundus lines that tile the
    # surface into connected components (which is fine when you want
    # to test this method on fundus lines generated from manual
    # labeling). However, to work on real data, fundus lines will
    # need to be connected together using shortest paths.

    # split surface into connected components
    connected_component_faces = _remove_boundary_faces(
        points, faces, fundus_line_indices)

    # label components based on most probable label assignment
    new_labels = _label_components(
        connected_component_faces, num_points, boundary_indices, learned_matrix,
        boundary_matrix_keys)

    # propagate new labels to fill holes
    label_matrix, label_map = _build_label_matrix(new_labels)
    new_learned_matrix = _propagate_labels(
        affinity_matrix, label_matrix,
        [i for i in range(num_points) if new_labels[i] >= 0], 100, 1)

    # assign most probable labels
    for idx in [i for i in range(num_points) if new_labels[i] == -1]:
        max_idx = np.argmax(new_learned_matrix[idx])
        new_labels[idx] = label_map[max_idx]

    # save
    if out_label_file is not None:
        write_vtk(out_label_file, points, faces=faces,
            scalars=new_labels.tolist())

    return new_labels
Esempio n. 10
0
def relabel_surface(vtk_file,
                    hemi='',
                    old_labels=[],
                    new_labels=[],
                    erase_remaining=True,
                    erase_labels=[],
                    erase_value=-1,
                    output_file=''):
    """
    Relabel surface in a VTK file.

    Parameters
    ----------
    vtk_file : string
        input labeled VTK file
    hemi : string
        hemisphere ('lh' or 'rh' or '')
        if set, add 1000 to left and 2000 to right hemisphere labels;
    old_labels : list of integers
        old labels (empty list if labels drawn from vtk scalars);
        may be used in conjunction with hemi
    new_labels : list of integers
        new labels (empty list if labels drawn from vtk scalars);
        may be used in conjunction with hemi
    erase_remaining : Boolean
        set all values not in old_labels to erase_value?
    erase_labels : list of integers
        values to erase (set to erase_value)
    erase_value : integer
        set vertices with labels in erase_labels to this value
    output_file : string
        new vtk file name

    Returns
    -------
    output_file : string
        new vtk file name

    Examples
    --------
    >>> import os
    >>> from mindboggle.labels.relabel import relabel_surface
    >>> from mindboggle.utils.plots import plot_surfaces
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> vtk_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk')
    >>> hemi = 'lh'
    >>> old_labels = [1003,1009,1030]
    >>> new_labels = [3,9,30]
    >>> erase_remaining = True
    >>> erase_labels = [0]
    >>> erase_value = -1
    >>> output_file = ''
    >>> #
    >>> relabel_surface(vtk_file, hemi, old_labels, new_labels, erase_remaining, erase_labels, erase_value, output_file)
    >>> # View
    >>> plot_surfaces('relabeled_FreeSurfer_cortex_labels.vtk')

    """
    import os
    import numpy as np
    from mindboggle.utils.io_vtk import read_vtk, write_vtk

    # Load labeled vtk surfaces:
    faces, lines, indices, points, npoints, scalars, \
        name, input_vtk = read_vtk(vtk_file, return_first=True, return_array=True)
    new_scalars = scalars[:]

    # Raise an error if inputs set incorrectly:
    if (new_labels and not old_labels) or \
            (hemi and hemi not in ['lh','rh']) or \
            (erase_remaining and not old_labels):
        raise IOError("Please check inputs for relabel_surface().")

    # Loop through unique labels in scalars:
    ulabels = np.unique(scalars)
    for label in ulabels:
        I = np.where(scalars == label)[0]

        # If label in erase_labels list, replace with erase_value:
        if label in erase_labels:
            new_scalars[I] = erase_value

        # If label in old_labels list, replace with corresponding new label,
        # and if hemi set, add 1000 or 2000 to the new label:
        elif label in old_labels and (len(old_labels) == len(new_labels)):
            new_label = new_labels[old_labels.index(label)]
            if hemi == 'lh':
                new_scalars[I] = 1000 + new_label
            elif hemi == 'rh':
                new_scalars[I] = 2000 + new_label
            else:
                new_scalars[I] = new_label

        # If labels not set then optionally add hemi value:
        elif hemi and not new_labels:
            if hemi == 'lh':
                new_scalars[I] = 1000 + label
            elif hemi == 'rh':
                new_scalars[I] = 2000 + label

        # If label unaccounted for and erase_remaining, set to erase_value:
        elif erase_remaining:
            new_scalars[I] = erase_value

    # Ensure that the new scalars are integer values:
    new_scalars = [int(x) for x in new_scalars]

    # Write output VTK file:
    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'relabeled_' + os.path.basename(vtk_file))
    write_vtk(output_file,
              points,
              indices,
              lines,
              faces, [new_scalars], ['Labels'],
              scalar_type='int')
    if not os.path.exists(output_file):
        s = "relabel_surface() did not create " + output_file + "."
        raise (IOError(s))

    return output_file
Esempio n. 11
0
def plot_mask_surface(vtk_file, mask_file='', nonmask_value=-1,
                      masked_output='', remove_nonmask=False,
                      program='vtkviewer',
                      use_colormap=False, colormap_file=''):
    """
    Use vtkviewer or mayavi2 to visualize VTK surface mesh data.

    If a mask_file is provided, a temporary masked file is saved,
    and it is this file that is viewed.

    If using vtkviewer, can optionally provide colormap file
    or set $COLORMAP environment variable.

    Parameters
    ----------
    vtk_file : string
        name of VTK surface mesh file
    mask_file : string
        name of VTK surface mesh file to mask vtk_file vertices
    nonmask_value : integer
        nonmask (usually background) value
    masked_output : string
        temporary masked output file name
    remove_nonmask : Boolean
        remove vertices that are not in mask? (otherwise assign nonmask_value)
    program : string {'vtkviewer', 'mayavi2'}
        program to visualize VTK file
    use_colormap : Boolean
        use Paraview-style XML colormap file set by $COLORMAP env variable?
    colormap_file : string
        use colormap in given file if use_colormap==True?  if empty and
        use_colormap==True, use file set by $COLORMAP environment variable

    Examples
    --------
    >>> import os
    >>> from mindboggle.utils.plots import plot_mask_surface
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> vtk_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT31.manual.vtk')
    >>> mask_file = os.path.join(path, 'test_one_label.vtk')
    >>> nonmask_value = 0 #-1
    >>> masked_output = ''
    >>> remove_nonmask = True
    >>> program = 'vtkviewer'
    >>> use_colormap = True
    >>> colormap_file = '' #'/software/mindboggle_tools/colormap.xml'
    >>> plot_mask_surface(vtk_file, mask_file, nonmask_value, masked_output, remove_nonmask, program, use_colormap, colormap_file)

    """
    import os
    import numpy as np

    from mindboggle.utils.mesh import remove_faces, reindex_faces_points
    from mindboggle.utils.utils import execute
    from mindboggle.utils.plots import plot_surfaces
    from mindboggle.utils.io_vtk import read_scalars, rewrite_scalars, \
                                        read_vtk, write_vtk

    #-------------------------------------------------------------------------
    # Filter mesh with non-background values from a second (same-size) mesh:
    #-------------------------------------------------------------------------
    if mask_file:
        mask, name = read_scalars(mask_file, True, True)
        if not masked_output:
            masked_output = os.path.join(os.getcwd(), 'temp.vtk')
        file_to_plot = masked_output

        #---------------------------------------------------------------------
        # Remove nonmask-valued vertices:
        #---------------------------------------------------------------------
        if remove_nonmask:
            #-----------------------------------------------------------------
            # Load VTK files:
            #-----------------------------------------------------------------
            faces, lines, indices, points, npoints, scalars, scalar_names, \
            o1 = read_vtk(vtk_file, True, True)
            #-----------------------------------------------------------------
            # Find mask indices, remove nonmask faces, and reindex:
            #-----------------------------------------------------------------
            Imask = [i for i,x in enumerate(mask) if x != nonmask_value]
            mask_faces = remove_faces(faces, Imask)
            mask_faces, points, \
            original_indices = reindex_faces_points(mask_faces, points)
            #-----------------------------------------------------------------
            # Write VTK file with scalar values:
            #-----------------------------------------------------------------
            if np.ndim(scalars) == 1:
                scalar_type = type(scalars[0]).__name__
            elif np.ndim(scalars) == 2:
                scalar_type = type(scalars[0][0]).__name__
            else:
                print("Undefined scalar type!")
            write_vtk(file_to_plot, points, [], [], mask_faces,
                      scalars[original_indices].tolist(), scalar_names,
                      scalar_type=scalar_type)
        else:
            scalars, name = read_scalars(vtk_file, True, True)
            scalars[mask == nonmask_value] = nonmask_value
            rewrite_scalars(vtk_file, file_to_plot, scalars)
    else:
        file_to_plot = vtk_file

    #-------------------------------------------------------------------------
    # Display with vtkviewer.py:
    #-------------------------------------------------------------------------
    if program == 'vtkviewer':
        plot_surfaces(file_to_plot, use_colormap=use_colormap,
                      colormap_file=colormap_file)
    #-------------------------------------------------------------------------
    # Display with mayavi2:
    #-------------------------------------------------------------------------
    elif program == 'mayavi2':
        cmd = ["mayavi2", "-d", file_to_plot, "-m", "Surface", "&"]
        execute(cmd, 'os')
Esempio n. 12
0
def relabel_surface(vtk_file, hemi='', old_labels=[], new_labels=[],
                    output_file=''):
    """
    Relabel surface in a VTK file.

    Parameters
    ----------
    vtk_file : string
        input labeled VTK file
    hemi : string
        hemisphere ('lh' or 'rh' or '')
        if set, add 1000 to left and 2000 to right hemisphere labels;
    old_labels : list of integers
        old labels (empty list if labels drawn from vtk scalars);
        may be used in conjunction with hemi
    new_labels : list of integers
        new labels (empty list if labels drawn from vtk scalars);
        may be used in conjunction with hemi
    output_file : string
        new vtk file name

    Returns
    -------
    output_file : string
        new vtk file name

    Examples
    --------
    >>> import os
    >>> from mindboggle.labels.relabel import relabel_surface
    >>> from mindboggle.utils.plots import plot_vtk
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> vtk_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk')
    >>> hemi = 'lh'
    >>> old_labels = []
    >>> new_labels = []
    >>> output_file = ''
    >>> #
    >>> relabel_surface(vtk_file, hemi, old_labels, new_labels, output_file)
    >>> # View
    >>> plot_vtk('relabeled_lh.labels.DKT25.manual.vtk')

    """
    import os
    import numpy as np
    from mindboggle.utils.io_vtk import read_vtk, write_vtk

    # Load labeled vtk surfaces:
    faces, lines, indices, points, npoints, scalars, \
        name, input_vtk = read_vtk(vtk_file, return_first=True, return_array=True)

    # Add a hemisphere value to each unique label drawn from scalars:
    if hemi and not old_labels and not new_labels:
        ulabels = np.unique(scalars)
        for label in ulabels:
            I = np.where(scalars == int(label))[0]
            if hemi == 'lh':
                scalars[I] = 1000 + int(label)
            elif hemi == 'rh':
                scalars[I] = 2000 + int(label)
    # OR replace each old label with a corresponding new label
    # (hemisphere setting optionally adds 1000 or 2000 to the new label):
    else:
        for ilabel, new_label in enumerate(new_labels):
            I = np.where(scalars == int(old_labels[ilabel]))[0]
            if hemi == 'lh':
                scalars[I] = 1000 + int(new_label)
            elif hemi == 'rh':
                scalars[I] = 2000 + int(new_label)
            else:
                scalars[I] = int(new_label)

    if not output_file:
        output_file = os.path.join(os.getcwd(),
                                   'relabeled_' + os.path.basename(vtk_file))
    write_vtk(output_file, points, indices, lines, faces,
              [scalars.tolist()], ['Labels'])

    if not os.path.exists(output_file):
        raise(IOError(output_file + " not found"))

    return output_file
Esempio n. 13
0
def apply_affine_transform(transform_file, vtk_or_points,
                           transform_format='txt', save_file=False):
    """
    Transform coordinates using an affine matrix.

    Parameters
    ----------
    transform file : string
        name of ITK affine transform file
    vtk_or_points : string or list of lists of three integers
        name of VTK file containing point coordinate data, or the data
    transform_format : string
        format for transform file
        Ex: 'txt' for text, 'itk' for ITK, and 'mat' for Matlab format
    save_file : Boolean
        save transformed coordinates in a vtk file?
        (False if vtk_or_points is points)

    Returns
    -------
    affine_points : list of lists of floats
        transformed coordinates
    output_file : string or None (if save_file==False or vtk_or_points is points)
        name of VTK file containing transformed point data

    Examples
    --------
    >>> import os
    >>> from mindboggle.utils.io_vtk import apply_affine_transform
    >>> from mindboggle.utils.plots import plot_vtk
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> transform_file = os.path.join(path, 'arno', 'mri',
    >>>    't1weighted_brain.MNI152Affine.txt')
    >>> #    'affine_to_template.mat')
    >>> transform_format = 'itk'
    >>> #transform_format = 'mat'
    >>> vtk_or_points = os.path.join(path, 'arno', 'shapes', 'lh.pial.mean_curvature.vtk')
    >>> save_file = True
    >>> #
    >>> apply_affine_transform(transform_file, vtk_or_points,
    >>>                        transform_format, save_file)
    >>> # View
    >>> plot_vtk('affine_lh.pial.mean_curvature.vtk')

    """
    import os
    import numpy as np
    from scipy.io import loadmat

    from mindboggle.utils.io_vtk import read_vtk, write_vtk, read_itk_transform

    # Read ITK affine transform file:
    if transform_format == 'txt':
        transform = np.loadtxt(transform_file)
    elif transform_format == 'mat':
        transform = loadmat(transform_file)
    elif transform_format == 'itk':
        transform = read_itk_transform(transform_file)
    else:
        import sys
        sys.exit('Transform file format not understood.')

    # Read VTK file:
    if isinstance(vtk_or_points, str):
        faces, lines, indices, points, npoints, scalars, name, \
            foo1 = read_vtk(vtk_or_points)
        points = np.array(points)
    elif isinstance(vtk_or_points, list):
        points = np.array(vtk_or_points)
        save_file = False
    elif isinstance(vtk_or_points, np.ndarray):
        points = vtk_or_points.copy()
        save_file = False

    # Transform points:
    points = np.concatenate((points, np.ones((np.shape(points)[0],1))), axis=1)
    affine_points = np.transpose(np.dot(transform, np.transpose(points)))[:,0:3]
    affine_points.tolist()
    affine_points = [x.tolist() for x in affine_points]

    # Write transformed VTK file:
    if save_file:
        output_file = os.path.join(os.getcwd(), 'affine_' + os.path.basename(vtk_or_points))
        write_vtk(output_file, affine_points, indices, lines, faces,
                  scalars, name)
    else:
        output_file = None

    return affine_points, output_file
Esempio n. 14
0
def evaluate_deep_features(features_file, labels_file, sulci_file='', hemi='',
                           excludeIDs=[-1], output_vtk_name='', verbose=True):
    """
    Evaluate deep surface features by computing the minimum distance from each
    label boundary vertex to all of the feature vertices in the same sulcus,
    and from each feature vertex to all of the label boundary vertices in the
    same sulcus.  The label boundaries run along the deepest parts of sulci
    and correspond to fundi in the DKT cortical labeling protocol.

    Parameters
    ----------
    features_file : string
        VTK surface file with feature numbers for vertex scalars
    labels_file : string
        VTK surface file with label numbers for vertex scalars
    sulci_file : string
        VTK surface file with sulcus numbers for vertex scalars
    excludeIDs : list of integers
        feature/sulcus/label IDs to exclude (background set to -1)
    output_vtk_name : Boolean
        if not empty, output a VTK file beginning with output_vtk_name that
        contains a surface with mean distances as scalars
    verbose : Boolean
        print mean distances to standard output?

    Returns
    -------
    feature_to_fundus_mean_distances : numpy array [number of features x 1]
        mean distance from each feature to sulcus label boundary ("fundus")
    feature_to_fundus_sd_distances : numpy array [number of features x 1]
        standard deviations of feature-to-fundus distances
    feature_to_fundus_mean_distances_vtk : string
        VTK surface file containing feature_to_fundus_mean_distances
    fundus_to_feature_mean_distances : numpy array [number of features x 1]
        mean distances from each sulcus label boundary ("fundus") to feature
    fundus_to_feature_sd_distances : numpy array [number of features x 1]
        standard deviations of fundus-to-feature distances
    fundus_to_feature_mean_distances_vtk : string
        VTK surface file containing fundus_to_feature_mean_distances

    """
    import os
    import sys
    import numpy as np
    from mindboggle.utils.io_vtk import read_vtk, read_scalars, write_vtk
    from mindboggle.utils.mesh import find_neighbors, remove_faces
    from mindboggle.utils.segment import extract_borders
    from mindboggle.utils.compute import source_to_target_distances
    from mindboggle.LABELS import DKTprotocol

    dkt = DKTprotocol()
    #-------------------------------------------------------------------------
    # Load labels, features, and sulci:
    #-------------------------------------------------------------------------
    faces, lines, indices, points, npoints, labels, scalar_names, \
        input_vtk = read_vtk(labels_file, True, True)
    features, name = read_scalars(features_file, True, True)
    if sulci_file:
        sulci, name = read_scalars(sulci_file, True, True)
        # List of indices to sulcus vertices:
        sulcus_indices = [i for i,x in enumerate(sulci) if x != -1]
        segmentIDs = sulci
        sulcus_faces = remove_faces(faces, sulcus_indices)
    else:
        sulcus_indices = range(len(labels))
        segmentIDs = []
        sulcus_faces = faces

    #-------------------------------------------------------------------------
    # Prepare neighbors, label pairs, fundus IDs, and outputs:
    #-------------------------------------------------------------------------
    # Calculate neighbor lists for all points:
    print('Find neighbors to all vertices...')
    neighbor_lists = find_neighbors(faces, npoints)

    # Find label boundary points in any of the sulci:
    print('Find label boundary points in any of the sulci...')
    border_indices, border_label_tuples, unique_border_label_tuples = \
        extract_borders(sulcus_indices, labels, neighbor_lists,
                        ignore_values=[], return_label_pairs=True)
    if not len(border_indices):
        sys.exit('There are no label boundary points!')

    # Initialize an array of label boundaries fundus IDs
    # (label boundary vertices that define sulci in the labeling protocol):
    print('Build an array of label boundary fundus IDs...')
    label_boundary_fundi = -1 * np.ones(npoints)

    if hemi == 'lh':
        nsulcus_lists = len(dkt.left_sulcus_label_pair_lists)
    else:
        nsulcus_lists = len(dkt.right_sulcus_label_pair_lists)
    feature_to_fundus_mean_distances = -1 * np.ones(nsulcus_lists)
    feature_to_fundus_sd_distances = -1 * np.ones(nsulcus_lists)
    fundus_to_feature_mean_distances = -1 * np.ones(nsulcus_lists)
    fundus_to_feature_sd_distances = -1 * np.ones(nsulcus_lists)
    feature_to_fundus_mean_distances_vtk = ''
    fundus_to_feature_mean_distances_vtk = ''

    #-------------------------------------------------------------------------
    # Loop through sulci:
    #-------------------------------------------------------------------------
    # For each list of sorted label pairs (corresponding to a sulcus):
    for isulcus, label_pairs in enumerate(dkt.sulcus_label_pair_lists):

        # Keep the boundary points with label pair labels:
        fundus_indices = [x for i,x in enumerate(border_indices)
                          if np.unique(border_label_tuples[i]).tolist()
                          in label_pairs]

        # Store the points as sulcus IDs in the fundus IDs array:
        if fundus_indices:
            label_boundary_fundi[fundus_indices] = isulcus

    if len(np.unique(label_boundary_fundi)) > 1:

        #---------------------------------------------------------------------
        # Construct a feature-to-fundus distance matrix and VTK file:
        #---------------------------------------------------------------------
        # Construct a distance matrix:
        print('Construct a feature-to-fundus distance matrix...')
        sourceIDs = features
        targetIDs = label_boundary_fundi
        distances, distance_matrix = source_to_target_distances(
            sourceIDs, targetIDs, points, segmentIDs, excludeIDs)

        # Compute mean distances for each feature:
        nfeatures = min(np.shape(distance_matrix)[1], nsulcus_lists)
        for ifeature in range(nfeatures):
            feature_distances = [x for x in distance_matrix[:, ifeature]
                                 if x != -1]
            feature_to_fundus_mean_distances[ifeature] = \
                np.mean(feature_distances)
            feature_to_fundus_sd_distances[ifeature] = \
                np.std(feature_distances)

        if verbose:
            print('Feature-to-fundus mean distances:')
            print(feature_to_fundus_mean_distances)
            print('Feature-to-fundus standard deviations of distances:')
            print(feature_to_fundus_sd_distances)

        # Write resulting feature-label boundary distances to VTK file:
        if output_vtk_name:
            feature_to_fundus_mean_distances_vtk = os.path.join(os.getcwd(),
                output_vtk_name + '_feature_to_fundus_mean_distances.vtk')
            print('Write feature-to-fundus distances to {0}...'.
                  format(feature_to_fundus_mean_distances_vtk))
            write_vtk(feature_to_fundus_mean_distances_vtk, points,
                      [], [], sulcus_faces, [distances],
                      ['feature-to-fundus_distances'], 'float')

        #---------------------------------------------------------------------
        # Construct a fundus-to-feature distance matrix and VTK file:
        #---------------------------------------------------------------------
        # Construct a distance matrix:
        print('Construct a fundus-to-feature distance matrix...')
        sourceIDs = label_boundary_fundi
        targetIDs = features
        distances, distance_matrix = source_to_target_distances(
            sourceIDs, targetIDs, points, segmentIDs, excludeIDs)

        # Compute mean distances for each feature:
        nfeatures = min(np.shape(distance_matrix)[1], nsulcus_lists)
        for ifeature in range(nfeatures):
            fundus_distances = [x for x in distance_matrix[:, ifeature]
                                if x != -1]
            fundus_to_feature_mean_distances[ifeature] = \
                np.mean(fundus_distances)
            fundus_to_feature_sd_distances[ifeature] = \
                np.std(fundus_distances)

        if verbose:
            print('Fundus-to-feature mean distances:')
            print(fundus_to_feature_mean_distances)
            print('Fundus-to-feature standard deviations of distances:')
            print(fundus_to_feature_sd_distances)

        # Write resulting feature-label boundary distances to VTK file:
        if output_vtk_name:
            fundus_to_feature_mean_distances_vtk = os.path.join(os.getcwd(),
                output_vtk_name + '_fundus_to_feature_mean_distances.vtk')
            print('Write fundus-to-feature distances to {0}...'.
                  format(fundus_to_feature_mean_distances_vtk))
            write_vtk(fundus_to_feature_mean_distances_vtk, points,
                      [], [], sulcus_faces, [distances],
                      ['fundus-to-feature_distances'], 'float')

    #-------------------------------------------------------------------------
    # Return outputs:
    #-------------------------------------------------------------------------
    return feature_to_fundus_mean_distances, feature_to_fundus_sd_distances,\
           feature_to_fundus_mean_distances_vtk,\
           fundus_to_feature_mean_distances, fundus_to_feature_sd_distances,\
           fundus_to_feature_mean_distances_vtk
Esempio n. 15
0
def plot_mask_surface(vtk_file, mask_file='', nonmask_value=-1,
                      masked_output='', remove_nonmask=False,
                      program='vtkviewer',
                      use_colormap=False, colormap_file=''):
    """
    Use vtkviewer or mayavi2 to visualize VTK surface mesh data.

    If a mask_file is provided, a temporary masked file is saved,
    and it is this file that is viewed.

    If using vtkviewer, can optionally provide colormap file
    or set $COLORMAP environment variable.

    Parameters
    ----------
    vtk_file : string
        name of VTK surface mesh file
    mask_file : string
        name of VTK surface mesh file to mask vtk_file vertices
    nonmask_value : integer
        nonmask (usually background) value
    masked_output : string
        temporary masked output file name
    remove_nonmask : Boolean
        remove vertices that are not in mask? (otherwise assign nonmask_value)
    program : string {'vtkviewer', 'mayavi2'}
        program to visualize VTK file
    use_colormap : Boolean
        use Paraview-style XML colormap file set by $COLORMAP env variable?
    colormap_file : string
        use colormap in given file if use_colormap==True?  if empty and
        use_colormap==True, use file set by $COLORMAP environment variable

    Examples
    --------
    >>> import os
    >>> from mindboggle.utils.plots import plot_mask_surface
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> vtk_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT31.manual.vtk')
    >>> mask_file = os.path.join(path, 'test_one_label.vtk')
    >>> nonmask_value = 0 #-1
    >>> masked_output = ''
    >>> remove_nonmask = True
    >>> program = 'vtkviewer'
    >>> use_colormap = True
    >>> colormap_file = '' #'/software/mindboggle_tools/colormap.xml'
    >>> plot_mask_surface(vtk_file, mask_file, nonmask_value, masked_output, remove_nonmask, program, use_colormap, colormap_file)

    """
    import os
    import numpy as np

    from mindboggle.utils.mesh import remove_faces, reindex_faces_points
    from mindboggle.utils.utils import execute
    from mindboggle.utils.plots import plot_surfaces
    from mindboggle.utils.io_vtk import read_scalars, rewrite_scalars, \
                                        read_vtk, write_vtk

    #-------------------------------------------------------------------------
    # Filter mesh with non-background values from a second (same-size) mesh:
    #-------------------------------------------------------------------------
    if mask_file:
        mask, name = read_scalars(mask_file, True, True)
        if not masked_output:
            masked_output = os.path.join(os.getcwd(), 'temp.vtk')
        file_to_plot = masked_output

        #---------------------------------------------------------------------
        # Remove nonmask-valued vertices:
        #---------------------------------------------------------------------
        if remove_nonmask:
            #-----------------------------------------------------------------
            # Load VTK files:
            #-----------------------------------------------------------------
            faces, lines, indices, points, npoints, scalars, scalar_names, \
            o1 = read_vtk(vtk_file, True, True)
            #-----------------------------------------------------------------
            # Find mask indices, remove nonmask faces, and reindex:
            #-----------------------------------------------------------------
            Imask = [i for i,x in enumerate(mask) if x != nonmask_value]
            mask_faces = remove_faces(faces, Imask)
            mask_faces, points, \
            original_indices = reindex_faces_points(mask_faces, points)
            #-----------------------------------------------------------------
            # Write VTK file with scalar values:
            #-----------------------------------------------------------------
            if np.ndim(scalars) == 1:
                scalar_type = type(scalars[0]).__name__
            elif np.ndim(scalars) == 2:
                scalar_type = type(scalars[0][0]).__name__
            else:
                print("Undefined scalar type!")
            write_vtk(file_to_plot, points, [], [], mask_faces,
                      scalars[original_indices].tolist(), scalar_names,
                      scalar_type=scalar_type)
        else:
            scalars, name = read_scalars(vtk_file, True, True)
            scalars[mask == nonmask_value] = nonmask_value
            rewrite_scalars(vtk_file, file_to_plot, scalars)
    else:
        file_to_plot = vtk_file

    #-------------------------------------------------------------------------
    # Display with vtkviewer.py:
    #-------------------------------------------------------------------------
    if program == 'vtkviewer':
        plot_surfaces(file_to_plot, use_colormap=use_colormap,
                      colormap_file=colormap_file)
    #-------------------------------------------------------------------------
    # Display with mayavi2:
    #-------------------------------------------------------------------------
    elif program == 'mayavi2':
        cmd = ["mayavi2", "-d", file_to_plot, "-m", "Surface", "&"]
        execute(cmd, 'os')
Esempio n. 16
0
def realign_boundaries_to_fundus_lines(surf_file,
                                       init_label_file,
                                       fundus_lines_file,
                                       thickness_file,
                                       out_label_file=None):
    """
    Fix label boundaries to fundus lines.

    Parameters
    ----------
    surf_file : file containing the surface geometry in vtk format
    init_label_file : file containing scalars that represent the
                      initial guess at labels
    fundus_lines_file : file containing scalars representing fundus lines.
    thickness_file: file containing cortical thickness scalar data
    (for masking out the medial wall only)
    out_label_file : if specified, the realigned labels will be writen to
                     this file

    Returns
    -------
    numpy array representing the realigned label for each surface vertex.
    """

    import numpy as np
    from mindboggle.utils.segment import extract_borders
    import mindboggle.utils.graph as go
    from mindboggle.utils.io_vtk import read_vtk, read_scalars, write_vtk
    from mindboggle.utils.mesh import find_neighbors
    import propagate_fundus_lines

    ## read files
    faces, _, indices, points, num_points, _, _, _ = read_vtk(
        surf_file, return_first=True, return_array=True)
    indices = range(num_points)

    init_labels, _ = read_scalars(init_label_file,
                                  return_first=True,
                                  return_array=True)

    fundus_lines, _ = read_scalars(fundus_lines_file,
                                   return_first=True,
                                   return_array=True)

    thickness, _ = read_scalars(thickness_file,
                                return_first=True,
                                return_array=True)

    # remove labels from vertices with zero thickness (get around
    # DKT40 annotations having the label '3' for all the Corpus
    # Callosum vertices).
    cc_inds = [x for x in indices if thickness[x] < 0.001]
    init_labels[cc_inds] = 0

    ## setup seeds from initial label boundaries
    neighbor_lists = find_neighbors(faces, num_points)

    # extract all vertices that are on a boundary between labels
    boundary_indices, label_pairs, _ = extract_borders(indices,
                                                       init_labels,
                                                       neighbor_lists,
                                                       return_label_pairs=True)

    # split boundary vertices into segments with common boundary pairs.
    boundary_segments = {}
    for boundary_index, label_pair in zip(boundary_indices, label_pairs):
        key = ((label_pair[0],
                label_pair[1]) if label_pair[0] < label_pair[1] else
               (label_pair[1], label_pair[0]))
        if key not in boundary_segments:
            boundary_segments[key] = []

        boundary_segments[key].append(boundary_index)

    boundary_matrix, boundary_matrix_keys = _build_boundary_matrix(
        boundary_segments, num_points)

    # build the affinity matrix
    affinity_matrix = go.weight_graph(np.array(points),
                                      indices,
                                      np.array(faces),
                                      sigma=10,
                                      add_to_graph=False)

    ## propagate boundaries to fundus line vertices
    learned_matrix = _propagate_labels(affinity_matrix, boundary_matrix,
                                       boundary_indices, 100, 1)

    # assign labels to fundus line vertices based on highest probability
    new_boundaries = -1 * np.ones(init_labels.shape)
    fundus_line_indices = [i for i, x in enumerate(fundus_lines) if x > 0.5]

    # tile the surface into connected components delimited by fundus lines
    closed_fundus_lines, _, _ = propagate_fundus_lines.propagate_fundus_lines(
        points, faces, fundus_line_indices, thickness)

    closed_fundus_line_indices = np.where(closed_fundus_lines > 0)[0]

    # split surface into connected components
    connected_component_faces = _remove_boundary_faces(
        points, faces, closed_fundus_line_indices)

    # label components based on most probable label assignment
    new_labels = _label_components(connected_component_faces, num_points,
                                   boundary_indices, learned_matrix,
                                   boundary_matrix_keys)

    # propagate new labels to fill holes
    label_matrix, label_map = _build_label_matrix(new_labels)
    new_learned_matrix = _propagate_labels(
        affinity_matrix, label_matrix,
        [i for i in range(num_points) if new_labels[i] >= 0], 100, 1)

    # assign most probable labels
    for idx in [i for i in range(num_points) if new_labels[i] == -1]:
        max_idx = np.argmax(new_learned_matrix[idx])
        new_labels[idx] = label_map[max_idx]

    # save
    if out_label_file is not None:
        write_vtk(out_label_file,
                  points,
                  faces=faces,
                  scalars=[int(x) for x in new_labels],
                  scalar_type='int')

    return new_labels
Esempio n. 17
0
def evaluate_deep_features(features_file,
                           labels_file,
                           sulci_file='',
                           hemi='',
                           excludeIDs=[-1],
                           output_vtk_name='',
                           verbose=True):
    """
    Evaluate deep surface features by computing the minimum distance from each
    label border vertex to all of the feature vertices in the same sulcus,
    and from each feature vertex to all of the label border vertices in the
    same sulcus.  The label borders run along the deepest parts of sulci
    and correspond to fundi in the DKT cortical labeling protocol.

    Parameters
    ----------
    features_file : string
        VTK surface file with feature numbers for vertex scalars
    labels_file : string
        VTK surface file with label numbers for vertex scalars
    sulci_file : string
        VTK surface file with sulcus numbers for vertex scalars
    excludeIDs : list of integers
        feature/sulcus/label IDs to exclude (background set to -1)
    output_vtk_name : Boolean
        if not empty, output a VTK file beginning with output_vtk_name that
        contains a surface with mean distances as scalars
    verbose : Boolean
        print mean distances to standard output?

    Returns
    -------
    feature_to_border_mean_distances : numpy array [number of features x 1]
        mean distance from each feature to sulcus label border
    feature_to_border_sd_distances : numpy array [number of features x 1]
        standard deviations of feature-to-border distances
    feature_to_border_distances_vtk : string
        VTK surface file containing feature-to-border distances
    border_to_feature_mean_distances : numpy array [number of features x 1]
        mean distances from each sulcus label border to feature
    border_to_feature_sd_distances : numpy array [number of features x 1]
        standard deviations of border-to-feature distances
    border_to_feature_distances_vtk : string
        VTK surface file containing border-to-feature distances

    """
    import os
    import sys
    import numpy as np
    from mindboggle.utils.io_vtk import read_vtk, read_scalars, write_vtk
    from mindboggle.utils.mesh import find_neighbors, remove_faces
    from mindboggle.utils.segment import extract_borders
    from mindboggle.utils.compute import source_to_target_distances
    from mindboggle.LABELS import DKTprotocol

    dkt = DKTprotocol()
    #-------------------------------------------------------------------------
    # Load labels, features, and sulci:
    #-------------------------------------------------------------------------
    faces, lines, indices, points, npoints, labels, scalar_names, \
        input_vtk = read_vtk(labels_file, True, True)
    features, name = read_scalars(features_file, True, True)
    if sulci_file:
        sulci, name = read_scalars(sulci_file, True, True)
        # List of indices to sulcus vertices:
        sulcus_indices = [i for i, x in enumerate(sulci) if x != -1]
        segmentIDs = sulci
        sulcus_faces = remove_faces(faces, sulcus_indices)
    else:
        sulcus_indices = range(len(labels))
        segmentIDs = []
        sulcus_faces = faces

    #-------------------------------------------------------------------------
    # Prepare neighbors, label pairs, border IDs, and outputs:
    #-------------------------------------------------------------------------
    # Calculate neighbor lists for all points:
    print('Find neighbors for all vertices...')
    neighbor_lists = find_neighbors(faces, npoints)

    # Find label border points in any of the sulci:
    print('Find label border points in any of the sulci...')
    border_indices, border_label_tuples, unique_border_label_tuples = \
        extract_borders(sulcus_indices, labels, neighbor_lists,
                        ignore_values=[], return_label_pairs=True)
    if not len(border_indices):
        sys.exit('There are no label border points!')

    # Initialize an array of label border IDs
    # (label border vertices that define sulci in the labeling protocol):
    print('Build an array of label border IDs...')
    label_borders = -1 * np.ones(npoints)

    if hemi == 'lh':
        nsulcus_lists = len(dkt.left_sulcus_label_pair_lists)
    else:
        nsulcus_lists = len(dkt.right_sulcus_label_pair_lists)
    feature_to_border_mean_distances = -1 * np.ones(nsulcus_lists)
    feature_to_border_sd_distances = -1 * np.ones(nsulcus_lists)
    border_to_feature_mean_distances = -1 * np.ones(nsulcus_lists)
    border_to_feature_sd_distances = -1 * np.ones(nsulcus_lists)
    feature_to_border_distances_vtk = ''
    border_to_feature_distances_vtk = ''

    #-------------------------------------------------------------------------
    # Loop through sulci:
    #-------------------------------------------------------------------------
    # For each list of sorted label pairs (corresponding to a sulcus):
    for isulcus, label_pairs in enumerate(dkt.sulcus_label_pair_lists):

        # Keep the border points with label pair labels:
        label_pair_border_indices = [
            x for i, x in enumerate(border_indices)
            if np.unique(border_label_tuples[i]).tolist() in label_pairs
        ]

        # Store the points as sulcus IDs in the border IDs array:
        if label_pair_border_indices:
            label_borders[label_pair_border_indices] = isulcus

    if len(np.unique(label_borders)) > 1:

        #---------------------------------------------------------------------
        # Construct a feature-to-border distance matrix and VTK file:
        #---------------------------------------------------------------------
        # Construct a distance matrix:
        print('Construct a feature-to-border distance matrix...')
        sourceIDs = features
        targetIDs = label_borders
        distances, distance_matrix = source_to_target_distances(
            sourceIDs, targetIDs, points, segmentIDs, excludeIDs)

        # Compute mean distances for each feature:
        nfeatures = min(np.shape(distance_matrix)[1], nsulcus_lists)
        for ifeature in range(nfeatures):
            feature_distances = [
                x for x in distance_matrix[:, ifeature] if x != -1
            ]
            feature_to_border_mean_distances[ifeature] = \
                np.mean(feature_distances)
            feature_to_border_sd_distances[ifeature] = \
                np.std(feature_distances)

        if verbose:
            print('Feature-to-border mean distances:')
            print(feature_to_border_mean_distances)
            print('Feature-to-border standard deviations of distances:')
            print(feature_to_border_sd_distances)

        # Write resulting feature-label border distances to VTK file:
        if output_vtk_name:
            feature_to_border_distances_vtk = os.path.join(
                os.getcwd(),
                output_vtk_name + '_feature_to_border_mean_distances.vtk')
            print('Write feature-to-border distances to {0}...'.format(
                feature_to_border_distances_vtk))
            write_vtk(feature_to_border_distances_vtk, points, [], [],
                      sulcus_faces, [distances],
                      ['feature-to-border_distances'], 'float')

        #---------------------------------------------------------------------
        # Construct a border-to-feature distance matrix and VTK file:
        #---------------------------------------------------------------------
        # Construct a distance matrix:
        print('Construct a border-to-feature distance matrix...')
        sourceIDs = label_borders
        targetIDs = features
        distances, distance_matrix = source_to_target_distances(
            sourceIDs, targetIDs, points, segmentIDs, excludeIDs)

        # Compute mean distances for each feature:
        nfeatures = min(np.shape(distance_matrix)[1], nsulcus_lists)
        for ifeature in range(nfeatures):
            border_distances = [
                x for x in distance_matrix[:, ifeature] if x != -1
            ]
            border_to_feature_mean_distances[ifeature] = \
                np.mean(border_distances)
            border_to_feature_sd_distances[ifeature] = \
                np.std(border_distances)

        if verbose:
            print('border-to-feature mean distances:')
            print(border_to_feature_mean_distances)
            print('border-to-feature standard deviations of distances:')
            print(border_to_feature_sd_distances)

        # Write resulting feature-label border distances to VTK file:
        if output_vtk_name:
            border_to_feature_distances_vtk = os.path.join(
                os.getcwd(),
                output_vtk_name + '_border_to_feature_mean_distances.vtk')
            print('Write border-to-feature distances to {0}...'.format(
                border_to_feature_distances_vtk))
            write_vtk(border_to_feature_distances_vtk, points, [], [],
                      sulcus_faces, [distances],
                      ['border-to-feature_distances'], 'float')

    #-------------------------------------------------------------------------
    # Return outputs:
    #-------------------------------------------------------------------------
    return feature_to_border_mean_distances, feature_to_border_sd_distances,\
           feature_to_border_distances_vtk,\
           border_to_feature_mean_distances, border_to_feature_sd_distances,\
           border_to_feature_distances_vtk