Exemplo n.º 1
0
def rescale_by_neighborhood(input_vtk,
                            indices=[],
                            nedges=10,
                            p=99,
                            set_max_to_1=True,
                            save_file=False,
                            output_filestring='rescaled_scalars',
                            background_value=-1):
    """
    Rescale the scalar values of a VTK file by a percentile value
    in each vertex's surface mesh neighborhood.

    Parameters
    ----------
    input_vtk : string
        name of VTK file with a scalar value for each vertex
    indices : list of integers (optional)
        indices of scalars to normalize
    nedges : integer
        number or edges from vertex, defining the size of its neighborhood
    p : float in range of [0,100]
        percentile used to normalize each scalar
    set_max_to_1 : Boolean
        set all rescaled values greater than 1 to 1.0?
    save_file : Boolean
        save output VTK file?
    output_filestring : string (if save_file)
        name of output file
    background_value : integer
        background value

    Returns
    -------
    rescaled_scalars : list of floats
        rescaled scalar values
    rescaled_scalars_file : string (if save_file)
        name of output VTK file with rescaled scalar values

    Examples
    --------
    >>> import os
    >>> from mindboggle.guts.mesh import rescale_by_neighborhood
    >>> from mindboggle.mio.vtks import read_scalars, rewrite_scalars
    >>> from mindboggle.mio.plots import plot_surfaces
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> input_vtk = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk')
    >>> indices = []
    >>> nedges = 10
    >>> p = 99
    >>> set_max_to_1 = True
    >>> save_file = True
    >>> output_filestring = 'rescaled_scalars'
    >>> background_value = -1
    >>> #
    >>> rescaled_scalars, rescaled_scalars_file = rescale_by_neighborhood(input_vtk,
    >>>     indices, nedges, p, set_max_to_1, save_file, output_filestring, background_value)
    >>> #
    >>> # View rescaled scalar values per fold:
    >>> folds_file = os.path.join(path, 'arno', 'features', 'folds.vtk')
    >>> folds, name = read_scalars(folds_file)
    >>> #
    >>> rewrite_scalars(rescaled_scalars_file, rescaled_scalars_file,
    >>>                 rescaled_scalars, 'rescaled_depths', folds)
    >>> plot_surfaces(rescaled_scalars_file)

    """
    import os
    import numpy as np
    from mindboggle.mio.vtks import read_scalars, rewrite_scalars
    from mindboggle.guts.mesh import find_neighbors_from_file, find_neighborhood

    # Load scalars and vertex neighbor lists:
    scalars, name = read_scalars(input_vtk, True, True)
    if not indices:
        indices = [i for i, x in enumerate(scalars) if x != background_value]
    print("  Rescaling {0} scalar values by neighborhood...".format(
        len(indices)))
    neighbor_lists = find_neighbors_from_file(input_vtk)

    # Loop through vertices:
    rescaled_scalars = scalars.copy()
    for index in indices:

        # Determine the scalars in the vertex's neighborhood:
        neighborhood = find_neighborhood(neighbor_lists, [index], nedges)

        # Compute a high neighborhood percentile to normalize vertex's value:
        normalization_factor = np.percentile(scalars[neighborhood], p)
        rescaled_scalar = scalars[index] / normalization_factor
        rescaled_scalars[index] = rescaled_scalar

    # Make any rescaled value greater than 1 equal to 1:
    if set_max_to_1:
        rescaled_scalars[[x for x in indices if rescaled_scalars[x] > 1.0]] = 1

    rescaled_scalars = rescaled_scalars.tolist()

    #-------------------------------------------------------------------------
    # Return rescaled scalars and file name
    #-------------------------------------------------------------------------
    if save_file:

        rescaled_scalars_file = os.path.join(os.getcwd(),
                                             output_filestring + '.vtk')
        rewrite_scalars(input_vtk, rescaled_scalars_file, rescaled_scalars,
                        'rescaled_scalars')
        if not os.path.exists(rescaled_scalars_file):
            raise (IOError(rescaled_scalars_file + " not found"))

    else:
        rescaled_scalars_file = None

    return rescaled_scalars, rescaled_scalars_file
Exemplo n.º 2
0
def concatenate_sulcus_scalars(scalar_files, fold_files, label_files,
                               background_value=-1):
    """
    Prepare data for estimating scalar distributions along and outside fundi.

    Extract (e.g., depth, curvature) scalar values in folds, along sulcus
    label boundaries as well as outside the sulcus label boundaries.
    Concatenate these scalar values across multiple files.

    Parameters
    ----------
    scalar_files : list of strings
        names of surface mesh VTK files with scalar values to concatenate
    fold_files : list of strings (corr. to each list in scalar_files)
        VTK files with fold numbers as scalars (-1 for non-fold vertices)
    label_files : list of strings (corr. to fold_files)
        VTK files with label numbers (-1 for unlabeled vertices)
    background_value : integer or float
        background value

    Returns
    -------
    border_scalars : list of floats
        concatenated scalar values within folds along sulcus label boundaries
    nonborder_scalars : list of floats
        concatenated scalar values within folds outside sulcus label boundaries

    Examples
    --------
    >>> # Concatenate (duplicate) depth scalars:
    >>> import numpy as np
    >>> from mindboggle.shapes.likelihood import concatenate_sulcus_scalars
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> depth_file = fetch_data(urls['left_travel_depth'], '', '.vtk')
    >>> labels_file = fetch_data(urls['left_freesurfer_labels'], '', '.vtk')
    >>> folds_file = fetch_data(urls['left_folds'], '', '.vtk')
    >>> scalar_files = [depth_file, depth_file]
    >>> fold_files = [folds_file, folds_file]
    >>> label_files = [labels_file, labels_file]
    >>> background_value = -1
    >>> border, nonborder = concatenate_sulcus_scalars(scalar_files,
    ...     fold_files, label_files, background_value)
    >>> print(np.array_str(np.array(border[0:5]),
    ...       precision=5, suppress_small=True))
    [ 3.48284  2.57157  4.27596  4.56549  3.84881]
    >>> print(np.array_str(np.array(nonborder[0:5]),
    ...       precision=5, suppress_small=True))
    [ 2.87204  2.89388  3.55364  2.81681  3.70736]

    """
    import numpy as np

    from mindboggle.mio.vtks import read_scalars
    from mindboggle.guts.mesh import find_neighbors_from_file
    from mindboggle.guts.segment import extract_borders
    from mindboggle.mio.labels import DKTprotocol

    dkt = DKTprotocol()

    # Prepare (non-unique) list of sulcus label pairs:
    protocol_label_pairs = [x for lst in dkt.sulcus_label_pair_lists
                            for x in lst]

    border_scalars = []
    nonborder_scalars = []

    # Loop through files with the scalar values:
    for ifile, scalar_file in enumerate(scalar_files):
        #print(scalar_file)

        # Load scalars, folds, and labels:
        folds_file = fold_files[ifile]
        labels_file = label_files[ifile]
        scalars, name = read_scalars(scalar_file, True, True)
        if scalars.shape:
            folds, name = read_scalars(folds_file)
            labels, name = read_scalars(labels_file)
            indices_folds = [i for i,x in enumerate(folds)
                             if x != background_value]
            neighbor_lists = find_neighbors_from_file(labels_file)

            # Find all label border pairs within the folds:
            indices_label_pairs, label_pairs, unique_pairs = extract_borders(
                indices_folds, labels, neighbor_lists, ignore_values=[-1],
                return_label_pairs=True)
            indices_label_pairs = np.array(indices_label_pairs)

            # Find vertices with label pairs in the sulcus labeling protocol:
            Ipairs_in_protocol = [i for i,x in enumerate(label_pairs)
                                  if x in protocol_label_pairs]
            indices_label_pairs = indices_label_pairs[Ipairs_in_protocol]
            indices_outside_pairs = list(frozenset(indices_folds).difference(
                indices_label_pairs))

            # Store scalar values in folds along label border pairs:
            border_scalars.extend(scalars[indices_label_pairs].tolist())

            # Store scalar values in folds outside label border pairs:
            nonborder_scalars.extend(scalars[indices_outside_pairs].tolist())

    return border_scalars, nonborder_scalars
Exemplo n.º 3
0
def concatenate_sulcus_scalars(scalar_files,
                               fold_files,
                               label_files,
                               background_value=-1):
    """
    Prepare data for estimating scalar distributions along and outside fundi.

    Extract (e.g., depth, curvature) scalar values in folds, along sulcus
    label boundaries as well as outside the sulcus label boundaries.
    Concatenate these scalar values across multiple files.

    Parameters
    ----------
    scalar_files : list of strings
        names of surface mesh VTK files with scalar values to concatenate
    fold_files : list of strings (corr. to each list in scalar_files)
        VTK files with fold numbers as scalars (-1 for non-fold vertices)
    label_files : list of strings (corr. to fold_files)
        VTK files with label numbers (-1 for unlabeled vertices)
    background_value : integer or float
        background value

    Returns
    -------
    border_scalars : list of floats
        concatenated scalar values within folds along sulcus label boundaries
    nonborder_scalars : list of floats
        concatenated scalar values within folds outside sulcus label boundaries

    Examples
    --------
    >>> # Concatenate (duplicate) depth scalars:
    >>> import numpy as np
    >>> from mindboggle.shapes.likelihood import concatenate_sulcus_scalars
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> depth_file = fetch_data(urls['left_travel_depth'], '', '.vtk')
    >>> labels_file = fetch_data(urls['left_freesurfer_labels'], '', '.vtk')
    >>> folds_file = fetch_data(urls['left_folds'], '', '.vtk')
    >>> scalar_files = [depth_file, depth_file]
    >>> fold_files = [folds_file, folds_file]
    >>> label_files = [labels_file, labels_file]
    >>> background_value = -1
    >>> border, nonborder = concatenate_sulcus_scalars(scalar_files,
    ...     fold_files, label_files, background_value)
    >>> print(np.array_str(np.array(border[0:5]),
    ...       precision=5, suppress_small=True))
    [ 3.48284  2.57157  4.27596  4.56549  3.84881]
    >>> print(np.array_str(np.array(nonborder[0:5]),
    ...       precision=5, suppress_small=True))
    [ 2.87204  2.89388  3.55364  2.81681  3.70736]

    """
    import numpy as np

    from mindboggle.mio.vtks import read_scalars
    from mindboggle.guts.mesh import find_neighbors_from_file
    from mindboggle.guts.segment import extract_borders
    from mindboggle.mio.labels import DKTprotocol

    dkt = DKTprotocol()

    # Prepare (non-unique) list of sulcus label pairs:
    protocol_label_pairs = [
        x for lst in dkt.sulcus_label_pair_lists for x in lst
    ]

    border_scalars = []
    nonborder_scalars = []

    # Loop through files with the scalar values:
    for ifile, scalar_file in enumerate(scalar_files):
        #print(scalar_file)

        # Load scalars, folds, and labels:
        folds_file = fold_files[ifile]
        labels_file = label_files[ifile]
        scalars, name = read_scalars(scalar_file, True, True)
        if scalars.shape:
            folds, name = read_scalars(folds_file)
            labels, name = read_scalars(labels_file)
            indices_folds = [
                i for i, x in enumerate(folds) if x != background_value
            ]
            neighbor_lists = find_neighbors_from_file(labels_file)

            # Find all label border pairs within the folds:
            indices_label_pairs, label_pairs, unique_pairs = extract_borders(
                indices_folds,
                labels,
                neighbor_lists,
                ignore_values=[-1],
                return_label_pairs=True)
            indices_label_pairs = np.array(indices_label_pairs)

            # Find vertices with label pairs in the sulcus labeling protocol:
            Ipairs_in_protocol = [
                i for i, x in enumerate(label_pairs)
                if x in protocol_label_pairs
            ]
            indices_label_pairs = indices_label_pairs[Ipairs_in_protocol]
            indices_outside_pairs = list(
                frozenset(indices_folds).difference(indices_label_pairs))

            # Store scalar values in folds along label border pairs:
            border_scalars.extend(scalars[indices_label_pairs].tolist())

            # Store scalar values in folds outside label border pairs:
            nonborder_scalars.extend(scalars[indices_outside_pairs].tolist())

    return border_scalars, nonborder_scalars
Exemplo n.º 4
0
def extract_fundi(folds, curv_file, depth_file, min_separation=10,
                  erode_ratio=0.1, erode_min_size=1, save_file=False,
                  output_file='', background_value=-1, verbose=False):
    """
    Extract fundi from folds.

    A fundus is a branching curve that runs along the deepest and most highly
    curved portions of a fold. This function extracts one fundus from each
    fold by finding the deepest vertices inside the fold, finding endpoints
    along the edge of the fold, and connecting the former to the latter with
    tracks that run along deep and curved paths (through vertices with high
    values of travel depth multiplied by curvature), and a final filtration
    step.

    The deepest vertices are those with values at least two median
    absolute deviations above the median (non-zero) value, with the higher
    value chosen if two of the vertices are within (a default of) 10 edges
    from each other (to reduce the number of possible fundus paths as well
    as computation time).

    To find the endpoints, the find_outer_endpoints function propagates
    multiple tracks from seed vertices at median depth in the fold through
    concentric rings toward the fold’s edge, selecting maximal values within
    each ring, and terminating at candidate endpoints. The final endpoints
    are those candidates at the end of tracks that have a high median value,
    with the higher value chosen if two candidate endpoints are within
    (a default of) 10 edges from each other (otherwise, the resulting fundi
    can have spurious branching at the fold’s edge).

    The connect_points_erosion function connects the deepest fold vertices
    to the endpoints with a skeleton of 1-vertex-thick curves by erosion.
    It erodes by iteratively removing simple topological points and endpoints
    in order of lowest to highest values, where a simple topological point
    is a vertex that when added to or removed from an object on a surface
    mesh (such as a fundus curve) does not alter the object's topology.

    Steps ::
        1. Find fundus endpoints (outer anchors) with find_outer_endpoints().
        2. Include inner anchor points.
        3. Connect anchor points using connect_points_erosion();
           inner anchors are removed if they result in endpoints.

    Note ::
        Follow this with segment_by_region() to segment fundi by sulci.

    Parameters
    ----------
    folds : numpy array or list of integers
        fold number for each vertex
    curv_file :  string
        surface mesh file in VTK format with mean curvature values
    depth_file :  string
        surface mesh file in VTK format with rescaled depth values
    likelihoods : list of integers
        fundus likelihood value for each vertex
    min_separation : integer
        minimum number of edges between inner/outer anchor points
    erode_ratio : float
        fraction of indices to test for removal at each iteration
        in connect_points_erosion()
    save_file : bool
        save output VTK file?
    output_file : string
        output VTK file
    background_value : integer or float
        background value
    verbose : bool
        print statements?

    Returns
    -------
    fundus_per_fold : list of integers
        fundus numbers for all vertices, labeled by fold
        (-1 for non-fundus vertices)
    n_fundi_in_folds :  integer
        number of fundi
    fundus_per_fold_file : string (if save_file)
        output VTK file with fundus numbers (-1 for non-fundus vertices)

    Examples
    --------
    >>> # Extract fundus from one or more folds:
    >>> import numpy as np
    >>> from mindboggle.mio.vtks import read_scalars
    >>> from mindboggle.features.fundi import extract_fundi
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> curv_file = fetch_data(urls['left_mean_curvature'], '', '.vtk')
    >>> depth_file = fetch_data(urls['left_travel_depth'], '', '.vtk')
    >>> folds_file = fetch_data(urls['left_folds'], '', '.vtk')
    >>> folds, name = read_scalars(folds_file, True, True)
    >>> # Limit number of folds to speed up the test:
    >>> limit_folds = True
    >>> if limit_folds:
    ...     fold_numbers = [4] #[4, 6]
    ...     i0 = [i for i,x in enumerate(folds) if x not in fold_numbers]
    ...     folds[i0] = -1
    >>> min_separation = 10
    >>> erode_ratio = 0.10
    >>> erode_min_size = 10
    >>> save_file = True
    >>> output_file = 'extract_fundi_fold4.vtk'
    >>> background_value = -1
    >>> verbose = False
    >>> o1, o2, fundus_per_fold_file = extract_fundi(folds, curv_file,
    ...     depth_file, min_separation, erode_ratio, erode_min_size,
    ...     save_file, output_file, background_value, verbose)
    >>> lens = [len([x for x in o1 if x == y])
    ...         for y in np.unique(o1) if y != background_value]
    >>> lens[0:10] # [66, 2914, 100, 363, 73, 331, 59, 30, 1, 14] # (if not limit_folds)
    [73]

    View result without background (skip test):

    >>> from mindboggle.mio.plots import plot_surfaces # doctest: +SKIP
    >>> from mindboggle.mio.vtks import rewrite_scalars # doctest: +SKIP
    >>> rewrite_scalars(fundus_per_fold_file,
    ...                 'extract_fundi_fold4_no_background.vtk', o1,
    ...                 'fundus_per_fold', folds) # doctest: +SKIP
    >>> plot_surfaces('extract_fundi_fold4_no_background.vtk') # doctest: +SKIP

    """

    # Extract a skeleton to connect endpoints in a fold:
    import os
    import numpy as np
    from time import time

    from mindboggle.mio.vtks import read_scalars, read_vtk, rewrite_scalars
    from mindboggle.guts.compute import median_abs_dev
    from mindboggle.guts.paths import find_max_values
    from mindboggle.guts.mesh import find_neighbors_from_file
    from mindboggle.guts.mesh import find_complete_faces
    from mindboggle.guts.paths import find_outer_endpoints
    from mindboggle.guts.paths import connect_points_erosion

    if isinstance(folds, list):
        folds = np.array(folds)

    # Load values, inner anchor threshold, and neighbors:
    if os.path.isfile(curv_file):
        points, indices, lines, faces, curvs, scalar_names, npoints, \
            input_vtk = read_vtk(curv_file, True, True)
    else:
        raise IOError("{0} doesn't exist!".format(curv_file))
    if os.path.isfile(curv_file):
        depths, name = read_scalars(depth_file, True, True)
    else:
        raise IOError("{0} doesn't exist!".format(depth_file))
    values = curvs * depths
    values0 = [x for x in values if x > 0]
    thr = np.median(values0) + 2 * median_abs_dev(values0)
    neighbor_lists = find_neighbors_from_file(curv_file)

    # ------------------------------------------------------------------------
    # Loop through folds:
    # ------------------------------------------------------------------------
    t1 = time()
    skeletons = []
    unique_fold_IDs = [x for x in np.unique(folds) if x != background_value]

    if verbose:
        if len(unique_fold_IDs) == 1:
            print("Extract a fundus from 1 fold...")
        else:
            print("Extract a fundus from each of {0} folds...".
                  format(len(unique_fold_IDs)))

    for fold_ID in unique_fold_IDs:
        indices_fold = [i for i,x in enumerate(folds) if x == fold_ID]
        if indices_fold:
            if verbose:
                print('  Fold {0}:'.format(int(fold_ID)))

            # ----------------------------------------------------------------
            # Find outer anchor points on the boundary of the surface region,
            # to serve as fundus endpoints:
            # ----------------------------------------------------------------
            outer_anchors, tracks = find_outer_endpoints(indices_fold,
                neighbor_lists, values, depths, min_separation,
                background_value, verbose)

            # ----------------------------------------------------------------
            # Find inner anchor points:
            # ----------------------------------------------------------------
            inner_anchors = find_max_values(points, values, min_separation,
                                            thr)

            # ----------------------------------------------------------------
            # Connect anchor points to create skeleton:
            # ----------------------------------------------------------------
            B = background_value * np.ones(npoints)
            B[indices_fold] = 1
            skeleton = connect_points_erosion(B, neighbor_lists,
                outer_anchors, inner_anchors, values, erode_ratio,
                erode_min_size, [], '', background_value, verbose)
            if skeleton:
                skeletons.extend(skeleton)

            ## ---------------------------------------------------------------
            ## Remove fundus vertices if they make complete triangle faces:
            ## ---------------------------------------------------------------
            #Iremove = find_complete_faces(skeletons, faces)
            #if Iremove:
            #    skeletons = list(frozenset(skeletons).difference(Iremove))

    indices_skel = [x for x in skeletons if folds[x] != background_value]
    fundus_per_fold = background_value * np.ones(npoints)
    fundus_per_fold[indices_skel] = folds[indices_skel]
    n_fundi_in_folds = len([x for x in np.unique(fundus_per_fold)
                             if x != background_value])
    if n_fundi_in_folds == 1:
        sdum = 'fold fundus'
    else:
        sdum = 'fold fundi'
    if verbose:
        print('  ...Extracted {0} {1}; {2} total ({3:.2f} seconds)'.
              format(n_fundi_in_folds, sdum, n_fundi_in_folds, time() - t1))

    # ------------------------------------------------------------------------
    # Return fundi, number of fundi, and file name:
    # ------------------------------------------------------------------------
    fundus_per_fold_file = None
    if n_fundi_in_folds > 0:
        fundus_per_fold = [int(x) for x in fundus_per_fold]
        if save_file:
            if output_file:
                fundus_per_fold_file = output_file
            else:
                fundus_per_fold_file = os.path.join(os.getcwd(),
                                                    'fundus_per_fold.vtk')
            rewrite_scalars(curv_file, fundus_per_fold_file, fundus_per_fold,
                            'fundi', [], background_value)
            if not os.path.exists(fundus_per_fold_file):
                raise IOError(fundus_per_fold_file + " not found")

    return fundus_per_fold,  n_fundi_in_folds, fundus_per_fold_file
Exemplo n.º 5
0
def concatenate_sulcus_scalars(scalar_files, fold_files, label_files):
    """
    Prepare data for estimating scalar distributions along and outside fundi.

    Extract (e.g., depth, curvature) scalar values in folds, along sulcus
    label boundaries as well as outside the sulcus label boundaries.
    Concatenate these scalar values across multiple files.

    Parameters
    ----------
    scalar_files : list of strings
        names of surface mesh VTK files with scalar values to concatenate
    fold_files : list of strings (corr. to each list in scalar_files)
        VTK files with fold numbers as scalars (-1 for non-fold vertices)
    label_files : list of strings (corr. to fold_files)
        VTK files with label numbers (-1 for unlabeled vertices)

    Returns
    -------
    border_scalars : list of floats
        concatenated scalar values within folds along sulcus label boundaries
    nonborder_scalars : list of floats
        concatenated scalar values within folds outside sulcus label boundaries

    Examples
    --------
    >>> # Concatenate (duplicate) depth scalars:
    >>> import os
    >>> from mindboggle.shapes.likelihood import concatenate_sulcus_scalars
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> depth_file = os.path.join(path, 'arno', 'shapes', 'depth_rescaled.vtk')
    >>> folds_file = os.path.join(path, 'arno', 'features', 'folds.vtk')
    >>> labels_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk')
    >>> scalar_files = [depth_file, depth_file]
    >>> fold_files = [folds_file, folds_file]
    >>> label_files = [labels_file, labels_file]
    >>> #
    >>> S = concatenate_sulcus_scalars(scalar_files, fold_files, label_files)

    """
    import numpy as np

    from mindboggle.mio.vtks import read_scalars
    from mindboggle.guts.mesh import find_neighbors_from_file
    from mindboggle.guts.segment import extract_borders
    from mindboggle.mio.labels import DKTprotocol

    dkt = DKTprotocol()

    # Prepare (non-unique) list of sulcus label pairs:
    protocol_label_pairs = [x for lst in dkt.sulcus_label_pair_lists
                            for x in lst]

    border_scalars = []
    nonborder_scalars = []

    # Loop through files with the scalar values:
    for ifile, scalar_file in enumerate(scalar_files):
        print(scalar_file)

        # Load scalars, folds, and labels:
        folds_file = fold_files[ifile]
        labels_file = label_files[ifile]
        scalars, name = read_scalars(scalar_file, True, True)
        if scalars.shape:
            folds, name = read_scalars(folds_file)
            labels, name = read_scalars(labels_file)
            indices_folds = [i for i,x in enumerate(folds) if x != -1]
            neighbor_lists = find_neighbors_from_file(labels_file)

            # Find all label border pairs within the folds:
            indices_label_pairs, label_pairs, unique_pairs = extract_borders(
                indices_folds, labels, neighbor_lists, ignore_values=[-1],
                return_label_pairs=True)
            indices_label_pairs = np.array(indices_label_pairs)

            # Find vertices with label pairs in the sulcus labeling protocol:
            Ipairs_in_protocol = [i for i,x in enumerate(label_pairs)
                                  if x in protocol_label_pairs]
            indices_label_pairs = indices_label_pairs[Ipairs_in_protocol]
            indices_outside_pairs = list(frozenset(indices_folds).difference(
                indices_label_pairs))

            # Store scalar values in folds along label border pairs:
            border_scalars.extend(scalars[indices_label_pairs].tolist())

            # Store scalar values in folds outside label border pairs:
            nonborder_scalars.extend(scalars[indices_outside_pairs].tolist())

    return border_scalars, nonborder_scalars
Exemplo n.º 6
0
def extract_fundi(folds,
                  curv_file,
                  depth_file,
                  min_separation=10,
                  erode_ratio=0.1,
                  erode_min_size=1,
                  save_file=False,
                  verbose=False):
    """
    Extract fundi from folds.

    A fundus is a branching curve that runs along the deepest and most
    highly curved portions of a fold.

    Steps ::
        1. Find fundus endpoints (outer anchors) with find_outer_anchors().
        2. Include inner anchor points.
        3. Connect anchor points using connect_points_erosion();
           inner anchors are removed if they result in endpoints.

    Parameters
    ----------
    folds : numpy array or list of integers
        fold number for each vertex
    curv_file :  string
        surface mesh file in VTK format with mean curvature values
    depth_file :  string
        surface mesh file in VTK format with rescaled depth values
    likelihoods : list of integers
        fundus likelihood value for each vertex
    min_separation : integer
        minimum number of edges between inner/outer anchor points
    erode_ratio : float
        fraction of indices to test for removal at each iteration
        in connect_points_erosion()
    save_file : bool
        save output VTK file?
    verbose : bool
        print statements?

    Returns
    -------
    fundus_per_fold : list of integers
        fundus numbers for all vertices, labeled by fold
        (-1 for non-fundus vertices)
    n_fundi_in_folds :  integer
        number of fundi
    fundus_per_fold_file : string (if save_file)
        output VTK file with fundus numbers (-1 for non-fundus vertices)

    Examples
    --------
    >>> # Extract fundus from one or more folds:
    >>> single_fold = True
    >>> from mindboggle.mio.vtks import read_scalars
    >>> from mindboggle.features.fundi import extract_fundi
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> curv_file = fetch_data(urls['left_mean_curvature'])
    >>> depth_file = fetch_data(urls['left_travel_depth'])
    >>> folds_file = fetch_data(urls['left_folds'])
    >>> folds, name = read_scalars(folds_file, True, True)
    >>> if single_fold:
    ...     fold_number = 2 #11
    ...     folds[folds != fold_number] = -1
    >>> min_separation = 10
    >>> erode_ratio = 0.10
    >>> erode_min_size = 10
    >>> save_file = True
    >>> verbose = False
    >>> o1, o2, fundus_per_fold_file = extract_fundi(folds, curv_file,
    ...     depth_file, min_separation, erode_ratio, erode_min_size,
    ...     save_file, verbose)
    >>> if single_fold:
    ...     lens = [len([x for x in o1 if x == 2])]
    ... else:
    ...     lens = [len([x for x in o1 if x == y]) for y in range(o2)]
    >>> lens[0:10]
    [115]

    View result (skip test):

    >>> from mindboggle.mio.plots import plot_surfaces
    >>> plot_surfaces(fundus_per_fold_file) # doctest: +SKIP

    """

    # Extract a skeleton to connect endpoints in a fold:
    import os
    import numpy as np
    from time import time

    from mindboggle.mio.vtks import read_scalars, read_vtk, rewrite_scalars
    from mindboggle.guts.compute import median_abs_dev
    from mindboggle.guts.paths import find_max_values
    from mindboggle.guts.mesh import find_neighbors_from_file
    from mindboggle.guts.mesh import find_complete_faces
    from mindboggle.guts.paths import find_outer_anchors
    from mindboggle.guts.paths import connect_points_erosion

    if isinstance(folds, list):
        folds = np.array(folds)

    # Load values, inner anchor threshold, and neighbors:
    points, indices, lines, faces, curvs, scalar_names, npoints, \
        input_vtk = read_vtk(curv_file, True, True)
    depths, name = read_scalars(depth_file, True, True)
    values = curvs * depths
    values0 = [x for x in values if x > 0]
    thr = np.median(values0) + 2 * median_abs_dev(values0)
    neighbor_lists = find_neighbors_from_file(curv_file)

    #-------------------------------------------------------------------------
    # Loop through folds:
    #-------------------------------------------------------------------------
    t1 = time()
    skeletons = []
    unique_fold_IDs = [x for x in np.unique(folds) if x != -1]

    if verbose:
        if len(unique_fold_IDs) == 1:
            print("Extract a fundus from 1 fold...")
        else:
            print("Extract a fundus from each of {0} folds...".format(
                len(unique_fold_IDs)))

    for fold_ID in unique_fold_IDs:
        indices_fold = [i for i, x in enumerate(folds) if x == fold_ID]
        if indices_fold:
            if verbose:
                print('  Fold {0}:'.format(int(fold_ID)))

            #-----------------------------------------------------------------
            # Find outer anchor points on the boundary of the surface region,
            # to serve as fundus endpoints:
            #-----------------------------------------------------------------
            verbose = False
            outer_anchors, tracks = find_outer_anchors(indices_fold,
                                                       neighbor_lists, values,
                                                       depths, min_separation,
                                                       verbose)

            #-----------------------------------------------------------------
            # Find inner anchor points:
            #-----------------------------------------------------------------
            inner_anchors = find_max_values(points, values, min_separation,
                                            thr)

            #-----------------------------------------------------------------
            # Connect anchor points to create skeleton:
            #-----------------------------------------------------------------
            B = -1 * np.ones(npoints)
            B[indices_fold] = 1
            skeleton = connect_points_erosion(B,
                                              neighbor_lists,
                                              outer_anchors,
                                              inner_anchors,
                                              values,
                                              erode_ratio,
                                              erode_min_size,
                                              save_steps=[],
                                              save_vtk='',
                                              verbose=False)
            if skeleton:
                skeletons.extend(skeleton)

            #-----------------------------------------------------------------
            # Remove fundus vertices if they complete triangle faces:
            #-----------------------------------------------------------------
            Iremove = find_complete_faces(skeletons, faces)
            if Iremove:
                skeletons = list(frozenset(skeletons).difference(Iremove))

    indices_skel = [x for x in skeletons if folds[x] != -1]
    fundus_per_fold = -1 * np.ones(npoints)
    fundus_per_fold[indices_skel] = folds[indices_skel]
    n_fundi_in_folds = len([x for x in np.unique(fundus_per_fold) if x != -1])
    if n_fundi_in_folds == 1:
        sdum = 'fold fundus'
    else:
        sdum = 'fold fundi'
    if verbose:
        print('  ...Extracted {0} {1}; {2} total ({3:.2f} seconds)'.format(
            n_fundi_in_folds, sdum, n_fundi_in_folds,
            time() - t1))

    #-------------------------------------------------------------------------
    # Return fundi, number of fundi, and file name:
    #-------------------------------------------------------------------------
    if n_fundi_in_folds > 0:
        fundus_per_fold = [int(x) for x in fundus_per_fold]
        if save_file:
            fundus_per_fold_file = os.path.join(os.getcwd(),
                                                'fundus_per_fold.vtk')
            rewrite_scalars(curv_file, fundus_per_fold_file, fundus_per_fold,
                            'fundi', folds)
            if not os.path.exists(fundus_per_fold_file):
                raise IOError(fundus_per_fold_file + " not found")
        else:
            fundus_per_fold_file = None

    return fundus_per_fold, n_fundi_in_folds, fundus_per_fold_file
Exemplo n.º 7
0
def extract_fundi(folds,
                  curv_file,
                  depth_file,
                  min_separation=10,
                  erode_ratio=0.1,
                  erode_min_size=1,
                  save_file=False,
                  output_file='',
                  background_value=-1,
                  verbose=False):
    """
    Extract fundi from folds.

    A fundus is a branching curve that runs along the deepest and most highly
    curved portions of a fold. This function extracts one fundus from each
    fold by finding the deepest vertices inside the fold, finding endpoints
    along the edge of the fold, and connecting the former to the latter with
    tracks that run along deep and curved paths (through vertices with high
    values of travel depth multiplied by curvature), and a final filtration
    step.

    The deepest vertices are those with values at least two median
    absolute deviations above the median (non-zero) value, with the higher
    value chosen if two of the vertices are within (a default of) 10 edges
    from each other (to reduce the number of possible fundus paths as well
    as computation time).

    To find the endpoints, the find_outer_endpoints function propagates
    multiple tracks from seed vertices at median depth in the fold through
    concentric rings toward the fold’s edge, selecting maximal values within
    each ring, and terminating at candidate endpoints. The final endpoints
    are those candidates at the end of tracks that have a high median value,
    with the higher value chosen if two candidate endpoints are within
    (a default of) 10 edges from each other (otherwise, the resulting fundi
    can have spurious branching at the fold’s edge).

    The connect_points_erosion function connects the deepest fold vertices
    to the endpoints with a skeleton of 1-vertex-thick curves by erosion.
    It erodes by iteratively removing simple topological points and endpoints
    in order of lowest to highest values, where a simple topological point
    is a vertex that when added to or removed from an object on a surface
    mesh (such as a fundus curve) does not alter the object's topology.

    Steps ::
        1. Find fundus endpoints (outer anchors) with find_outer_endpoints().
        2. Include inner anchor points.
        3. Connect anchor points using connect_points_erosion();
           inner anchors are removed if they result in endpoints.

    Note ::
        Follow this with segment_by_region() to segment fundi by sulci.

    Parameters
    ----------
    folds : numpy array or list of integers
        fold number for each vertex
    curv_file :  string
        surface mesh file in VTK format with mean curvature values
    depth_file :  string
        surface mesh file in VTK format with rescaled depth values
    likelihoods : list of integers
        fundus likelihood value for each vertex
    min_separation : integer
        minimum number of edges between inner/outer anchor points
    erode_ratio : float
        fraction of indices to test for removal at each iteration
        in connect_points_erosion()
    save_file : bool
        save output VTK file?
    output_file : string
        output VTK file
    background_value : integer or float
        background value
    verbose : bool
        print statements?

    Returns
    -------
    fundus_per_fold : list of integers
        fundus numbers for all vertices, labeled by fold
        (-1 for non-fundus vertices)
    n_fundi_in_folds :  integer
        number of fundi
    fundus_per_fold_file : string (if save_file)
        output VTK file with fundus numbers (-1 for non-fundus vertices)

    Examples
    --------
    >>> # Extract fundus from one or more folds:
    >>> import numpy as np
    >>> from mindboggle.mio.vtks import read_scalars
    >>> from mindboggle.features.fundi import extract_fundi
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> curv_file = fetch_data(urls['left_mean_curvature'], '', '.vtk')
    >>> depth_file = fetch_data(urls['left_travel_depth'], '', '.vtk')
    >>> folds_file = fetch_data(urls['left_folds'], '', '.vtk')
    >>> folds, name = read_scalars(folds_file, True, True)
    >>> # Limit number of folds to speed up the test:
    >>> limit_folds = True
    >>> if limit_folds:
    ...     fold_numbers = [4] #[4, 6]
    ...     i0 = [i for i,x in enumerate(folds) if x not in fold_numbers]
    ...     folds[i0] = -1
    >>> min_separation = 10
    >>> erode_ratio = 0.10
    >>> erode_min_size = 10
    >>> save_file = True
    >>> output_file = 'extract_fundi_fold4.vtk'
    >>> background_value = -1
    >>> verbose = False
    >>> o1, o2, fundus_per_fold_file = extract_fundi(folds, curv_file,
    ...     depth_file, min_separation, erode_ratio, erode_min_size,
    ...     save_file, output_file, background_value, verbose)
    >>> lens = [len([x for x in o1 if x == y])
    ...         for y in np.unique(o1) if y != background_value]
    >>> lens[0:10] # [66, 2914, 100, 363, 73, 331, 59, 30, 1, 14] # (if not limit_folds)
    [73]

    View result without background (skip test):

    >>> from mindboggle.mio.plots import plot_surfaces # doctest: +SKIP
    >>> from mindboggle.mio.vtks import rewrite_scalars # doctest: +SKIP
    >>> rewrite_scalars(fundus_per_fold_file,
    ...                 'extract_fundi_fold4_no_background.vtk', o1,
    ...                 'fundus_per_fold', folds) # doctest: +SKIP
    >>> plot_surfaces('extract_fundi_fold4_no_background.vtk') # doctest: +SKIP

    """

    # Extract a skeleton to connect endpoints in a fold:
    import os
    import numpy as np
    from time import time

    from mindboggle.mio.vtks import read_scalars, read_vtk, rewrite_scalars
    from mindboggle.guts.compute import median_abs_dev
    from mindboggle.guts.paths import find_max_values
    from mindboggle.guts.mesh import find_neighbors_from_file
    #from mindboggle.guts.mesh import find_complete_faces
    from mindboggle.guts.paths import find_outer_endpoints
    from mindboggle.guts.paths import connect_points_erosion

    if isinstance(folds, list):
        folds = np.array(folds)

    # Load values, inner anchor threshold, and neighbors:
    if os.path.isfile(curv_file):
        points, indices, lines, faces, curvs, scalar_names, npoints, \
            input_vtk = read_vtk(curv_file, True, True)
    else:
        raise IOError("{0} doesn't exist!".format(curv_file))
    if os.path.isfile(curv_file):
        depths, name = read_scalars(depth_file, True, True)
    else:
        raise IOError("{0} doesn't exist!".format(depth_file))
    values = curvs * depths
    values0 = [x for x in values if x > 0]
    thr = np.median(values0) + 2 * median_abs_dev(values0)
    neighbor_lists = find_neighbors_from_file(curv_file)

    # ------------------------------------------------------------------------
    # Loop through folds:
    # ------------------------------------------------------------------------
    t1 = time()
    skeletons = []
    unique_fold_IDs = [x for x in np.unique(folds) if x != background_value]

    if verbose:
        if len(unique_fold_IDs) == 1:
            print("Extract a fundus from 1 fold...")
        else:
            print("Extract a fundus from each of {0} folds...".format(
                len(unique_fold_IDs)))

    for fold_ID in unique_fold_IDs:
        indices_fold = [i for i, x in enumerate(folds) if x == fold_ID]
        if indices_fold:
            if verbose:
                print('  Fold {0}:'.format(int(fold_ID)))

            # ----------------------------------------------------------------
            # Find outer anchor points on the boundary of the surface region,
            # to serve as fundus endpoints:
            # ----------------------------------------------------------------
            outer_anchors, tracks = find_outer_endpoints(
                indices_fold, neighbor_lists, values, depths, min_separation,
                background_value, verbose)

            # ----------------------------------------------------------------
            # Find inner anchor points:
            # ----------------------------------------------------------------
            inner_anchors = find_max_values(points, values, min_separation,
                                            thr)

            # ----------------------------------------------------------------
            # Connect anchor points to create skeleton:
            # ----------------------------------------------------------------
            B = background_value * np.ones(npoints)
            B[indices_fold] = 1
            skeleton = connect_points_erosion(B, neighbor_lists, outer_anchors,
                                              inner_anchors, values,
                                              erode_ratio, erode_min_size, [],
                                              '', background_value, verbose)
            if skeleton:
                skeletons.extend(skeleton)

            ## ---------------------------------------------------------------
            ## Remove fundus vertices if they make complete triangle faces:
            ## ---------------------------------------------------------------
            #Iremove = find_complete_faces(skeletons, faces)
            #if Iremove:
            #    skeletons = list(frozenset(skeletons).difference(Iremove))

    indices_skel = [x for x in skeletons if folds[x] != background_value]
    fundus_per_fold = background_value * np.ones(npoints)
    fundus_per_fold[indices_skel] = folds[indices_skel]
    n_fundi_in_folds = len(
        [x for x in np.unique(fundus_per_fold) if x != background_value])
    if n_fundi_in_folds == 1:
        sdum = 'fold fundus'
    else:
        sdum = 'fold fundi'
    if verbose:
        print('  ...Extracted {0} {1}; {2} total ({3:.2f} seconds)'.format(
            n_fundi_in_folds, sdum, n_fundi_in_folds,
            time() - t1))

    # ------------------------------------------------------------------------
    # Return fundi, number of fundi, and file name:
    # ------------------------------------------------------------------------
    fundus_per_fold_file = None
    if n_fundi_in_folds > 0:
        fundus_per_fold = [int(x) for x in fundus_per_fold]
        if save_file:
            if output_file:
                fundus_per_fold_file = output_file
            else:
                fundus_per_fold_file = os.path.join(os.getcwd(),
                                                    'fundus_per_fold.vtk')
            rewrite_scalars(curv_file, fundus_per_fold_file, fundus_per_fold,
                            'fundi', [], background_value)
            if not os.path.exists(fundus_per_fold_file):
                raise IOError(fundus_per_fold_file + " not found")

    return fundus_per_fold, n_fundi_in_folds, fundus_per_fold_file
Exemplo n.º 8
0
def extract_fundi(folds, curv_file, depth_file, min_separation=10,
                  erode_ratio=0.1, erode_min_size=1, save_file=False):
    """
    Extract fundi from folds.

    A fundus is a branching curve that runs along the deepest and most
    highly curved portions of a fold.

    Steps ::
        1. Find fundus endpoints (outer anchors) with find_outer_anchors().
        2. Include inner anchor points.
        3. Connect anchor points using connect_points_erosion();
           inner anchors are removed if they result in endpoints.

    Parameters
    ----------
    folds : numpy array or list of integers
        fold number for each vertex
    curv_file :  string
        surface mesh file in VTK format with mean curvature values
    depth_file :  string
        surface mesh file in VTK format with rescaled depth values
    likelihoods : list of integers
        fundus likelihood value for each vertex
    min_separation : integer
        minimum number of edges between inner/outer anchor points
    erode_ratio : float
        fraction of indices to test for removal at each iteration
        in connect_points_erosion()
    save_file : Boolean
        save output VTK file?

    Returns
    -------
    fundus_per_fold : list of integers
        fundus numbers for all vertices, labeled by fold
        (-1 for non-fundus vertices)
    n_fundi_in_folds :  integer
        number of fundi
    fundus_per_fold_file : string (if save_file)
        output VTK file with fundus numbers (-1 for non-fundus vertices)

    Examples
    --------
    >>> # Extract fundus from one or more folds:
    >>> single_fold = True
    >>> import os
    >>> from mindboggle.mio.vtks import read_scalars
    >>> from mindboggle.features.fundi import extract_fundi
    >>> from mindboggle.mio.plots import plot_surfaces
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> curv_file = os.path.join(path, 'arno', 'shapes', 'lh.pial.mean_curvature.vtk')
    >>> depth_file = os.path.join(path, 'arno', 'shapes', 'travel_depth_rescaled.vtk')
    >>> folds_file = os.path.join(path, 'arno', 'features', 'folds.vtk')
    >>> folds, name = read_scalars(folds_file, True, True)
    >>> if single_fold:
    >>>     fold_number = 2 #11
    >>>     folds[folds != fold_number] = -1
    >>> min_separation = 10
    >>> erode_ratio = 0.10
    >>> erode_min_size = 10
    >>> save_file = True
    >>> o1, o2, fundus_per_fold_file = extract_fundi(folds, curv_file,
    ...     depth_file, min_separation, erode_ratio, erode_min_size, save_file)
    >>> #
    >>> # View:
    >>> plot_surfaces(fundi_file)

    """

    # Extract a skeleton to connect endpoints in a fold:
    import os
    import numpy as np
    from time import time

    from mindboggle.mio.vtks import read_scalars, read_vtk, rewrite_scalars
    from mindboggle.guts.compute import median_abs_dev
    from mindboggle.guts.paths import find_max_values
    from mindboggle.guts.mesh import find_neighbors_from_file, find_complete_faces
    from mindboggle.guts.paths import find_outer_anchors, connect_points_erosion

    if isinstance(folds, list):
        folds = np.array(folds)

    # Load values, inner anchor threshold, and neighbors:
    points, indices, lines, faces, curvs, scalar_names, npoints, \
        input_vtk = read_vtk(curv_file, True, True)
    depths, name = read_scalars(depth_file, True, True)
    values = curvs * depths
    values0 = [x for x in values if x > 0]
    thr = np.median(values0) + 2 * median_abs_dev(values0)
    neighbor_lists = find_neighbors_from_file(curv_file)

    #-------------------------------------------------------------------------
    # Loop through folds:
    #-------------------------------------------------------------------------
    t1 = time()
    skeletons = []
    unique_fold_IDs = [x for x in np.unique(folds) if x != -1]

    if len(unique_fold_IDs) == 1:
        print("Extract a fundus from 1 fold...")
    else:
        print("Extract a fundus from each of {0} folds...".
              format(len(unique_fold_IDs)))

    for fold_ID in unique_fold_IDs:
        indices_fold = [i for i,x in enumerate(folds) if x == fold_ID]
        if indices_fold:
            print('  Fold {0}:'.format(int(fold_ID)))

            #-----------------------------------------------------------------
            # Find outer anchor points on the boundary of the surface region,
            # to serve as fundus endpoints:
            #-----------------------------------------------------------------
            outer_anchors, tracks = find_outer_anchors(indices_fold,
                neighbor_lists, values, depths, min_separation)

            #-----------------------------------------------------------------
            # Find inner anchor points:
            #-----------------------------------------------------------------
            inner_anchors = find_max_values(points, values, min_separation, thr)

            #-----------------------------------------------------------------
            # Connect anchor points to create skeleton:
            #-----------------------------------------------------------------
            B = -1 * np.ones(npoints)
            B[indices_fold] = 1
            skeleton = connect_points_erosion(B, neighbor_lists,
                outer_anchors, inner_anchors, values,
                erode_ratio, erode_min_size, save_steps=[], save_vtk='')
            if skeleton:
                skeletons.extend(skeleton)

            #-----------------------------------------------------------------
            # Remove fundus vertices if they complete triangle faces:
            #-----------------------------------------------------------------
            Iremove = find_complete_faces(skeletons, faces)
            if Iremove:
                skeletons = list(frozenset(skeletons).difference(Iremove))

    indices_skel = [x for x in skeletons if folds[x] != -1]
    fundus_per_fold = -1 * np.ones(npoints)
    fundus_per_fold[indices_skel] = folds[indices_skel]
    n_fundi_in_folds = len([x for x in np.unique(fundus_per_fold)
                             if x != -1])
    if n_fundi_in_folds == 1:
        sdum = 'fold fundus'
    else:
        sdum = 'fold fundi'
    print('  ...Extracted {0} {1}; {2} total ({3:.2f} seconds)'.
          format(n_fundi_in_folds, sdum, n_fundi_in_folds, time() - t1))

    #-------------------------------------------------------------------------
    # Return fundi, number of fundi, and file name:
    #-------------------------------------------------------------------------
    if n_fundi_in_folds > 0:
        fundus_per_fold = [int(x) for x in fundus_per_fold]
        if save_file:
            fundus_per_fold_file = os.path.join(os.getcwd(),
                                                'fundus_per_fold.vtk')
            rewrite_scalars(curv_file, fundus_per_fold_file, fundus_per_fold,
                            'fundi', folds)
            if not os.path.exists(fundus_per_fold_file):
                raise(IOError(fundus_per_fold_file + " not found"))
        else:
            fundus_per_fold_file = None

    return fundus_per_fold,  n_fundi_in_folds, fundus_per_fold_file
Exemplo n.º 9
0
def rescale_by_neighborhood(input_vtk, indices=[], nedges=10, p=99,
    set_max_to_1=True, save_file=False, output_filestring='rescaled_scalars',
    background_value=-1):
    """
    Rescale the scalar values of a VTK file by a percentile value
    in each vertex's surface mesh neighborhood.

    Parameters
    ----------
    input_vtk : string
        name of VTK file with a scalar value for each vertex
    indices : list of integers (optional)
        indices of scalars to normalize
    nedges : integer
        number or edges from vertex, defining the size of its neighborhood
    p : float in range of [0,100]
        percentile used to normalize each scalar
    set_max_to_1 : Boolean
        set all rescaled values greater than 1 to 1.0?
    save_file : Boolean
        save output VTK file?
    output_filestring : string (if save_file)
        name of output file
    background_value : integer
        background value

    Returns
    -------
    rescaled_scalars : list of floats
        rescaled scalar values
    rescaled_scalars_file : string (if save_file)
        name of output VTK file with rescaled scalar values

    Examples
    --------
    >>> import os
    >>> from mindboggle.guts.mesh import rescale_by_neighborhood
    >>> from mindboggle.mio.vtks import read_scalars, rewrite_scalars
    >>> from mindboggle.mio.plots import plot_surfaces
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> input_vtk = os.path.join(path, 'arno', 'shapes', 'lh.pial.travel_depth.vtk')
    >>> indices = []
    >>> nedges = 10
    >>> p = 99
    >>> set_max_to_1 = True
    >>> save_file = True
    >>> output_filestring = 'rescaled_scalars'
    >>> background_value = -1
    >>> #
    >>> rescaled_scalars, rescaled_scalars_file = rescale_by_neighborhood(input_vtk,
    >>>     indices, nedges, p, set_max_to_1, save_file, output_filestring, background_value)
    >>> #
    >>> # View rescaled scalar values per fold:
    >>> folds_file = os.path.join(path, 'arno', 'features', 'folds.vtk')
    >>> folds, name = read_scalars(folds_file)
    >>> #
    >>> rewrite_scalars(rescaled_scalars_file, rescaled_scalars_file,
    >>>                 rescaled_scalars, 'rescaled_depths', folds)
    >>> plot_surfaces(rescaled_scalars_file)

    """
    import os
    import numpy as np
    from mindboggle.mio.vtks import read_scalars, rewrite_scalars
    from mindboggle.guts.mesh import find_neighbors_from_file, find_neighborhood

    # Load scalars and vertex neighbor lists:
    scalars, name = read_scalars(input_vtk, True, True)
    if not indices:
        indices = [i for i,x in enumerate(scalars) if x != background_value]
    print("  Rescaling {0} scalar values by neighborhood...".format(len(indices)))
    neighbor_lists = find_neighbors_from_file(input_vtk)

    # Loop through vertices:
    rescaled_scalars = scalars.copy()
    for index in indices:

        # Determine the scalars in the vertex's neighborhood:
        neighborhood = find_neighborhood(neighbor_lists, [index], nedges)

        # Compute a high neighborhood percentile to normalize vertex's value:
        normalization_factor = np.percentile(scalars[neighborhood], p)
        rescaled_scalar = scalars[index] / normalization_factor
        rescaled_scalars[index] = rescaled_scalar

    # Make any rescaled value greater than 1 equal to 1:
    if set_max_to_1:
        rescaled_scalars[[x for x in indices if rescaled_scalars[x] > 1.0]] = 1

    rescaled_scalars = rescaled_scalars.tolist()

    #-------------------------------------------------------------------------
    # Return rescaled scalars and file name
    #-------------------------------------------------------------------------
    if save_file:

        rescaled_scalars_file = os.path.join(os.getcwd(), output_filestring + '.vtk')
        rewrite_scalars(input_vtk, rescaled_scalars_file,
                        rescaled_scalars, 'rescaled_scalars')
        if not os.path.exists(rescaled_scalars_file):
            raise(IOError(rescaled_scalars_file + " not found"))

    else:
        rescaled_scalars_file = None

    return rescaled_scalars, rescaled_scalars_file
Exemplo n.º 10
0
def concatenate_sulcus_scalars(scalar_files, fold_files, label_files):
    """
    Prepare data for estimating scalar distributions along and outside fundi.

    Extract (e.g., depth, curvature) scalar values in folds, along sulcus
    label boundaries as well as outside the sulcus label boundaries.
    Concatenate these scalar values across multiple files.

    Parameters
    ----------
    scalar_files : list of strings
        names of surface mesh VTK files with scalar values to concatenate
    fold_files : list of strings (corr. to each list in scalar_files)
        VTK files with fold numbers as scalars (-1 for non-fold vertices)
    label_files : list of strings (corr. to fold_files)
        VTK files with label numbers (-1 for unlabeled vertices)

    Returns
    -------
    border_scalars : list of floats
        concatenated scalar values within folds along sulcus label boundaries
    nonborder_scalars : list of floats
        concatenated scalar values within folds outside sulcus label boundaries

    Examples
    --------
    >>> # Concatenate (duplicate) depth scalars:
    >>> import os
    >>> from mindboggle.shapes.likelihood import concatenate_sulcus_scalars
    >>> path = os.environ['MINDBOGGLE_DATA']
    >>> depth_file = os.path.join(path, 'arno', 'shapes', 'depth_rescaled.vtk')
    >>> folds_file = os.path.join(path, 'arno', 'features', 'folds.vtk')
    >>> labels_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT25.manual.vtk')
    >>> scalar_files = [depth_file, depth_file]
    >>> fold_files = [folds_file, folds_file]
    >>> label_files = [labels_file, labels_file]
    >>> #
    >>> S = concatenate_sulcus_scalars(scalar_files, fold_files, label_files)

    """
    import numpy as np

    from mindboggle.mio.vtks import read_scalars
    from mindboggle.guts.mesh import find_neighbors_from_file
    from mindboggle.guts.segment import extract_borders
    from mindboggle.mio.labels import DKTprotocol

    dkt = DKTprotocol()

    # Prepare (non-unique) list of sulcus label pairs:
    protocol_label_pairs = [
        x for lst in dkt.sulcus_label_pair_lists for x in lst
    ]

    border_scalars = []
    nonborder_scalars = []

    # Loop through files with the scalar values:
    for ifile, scalar_file in enumerate(scalar_files):
        print(scalar_file)

        # Load scalars, folds, and labels:
        folds_file = fold_files[ifile]
        labels_file = label_files[ifile]
        scalars, name = read_scalars(scalar_file, True, True)
        if scalars.shape:
            folds, name = read_scalars(folds_file)
            labels, name = read_scalars(labels_file)
            indices_folds = [i for i, x in enumerate(folds) if x != -1]
            neighbor_lists = find_neighbors_from_file(labels_file)

            # Find all label border pairs within the folds:
            indices_label_pairs, label_pairs, unique_pairs = extract_borders(
                indices_folds,
                labels,
                neighbor_lists,
                ignore_values=[-1],
                return_label_pairs=True)
            indices_label_pairs = np.array(indices_label_pairs)

            # Find vertices with label pairs in the sulcus labeling protocol:
            Ipairs_in_protocol = [
                i for i, x in enumerate(label_pairs)
                if x in protocol_label_pairs
            ]
            indices_label_pairs = indices_label_pairs[Ipairs_in_protocol]
            indices_outside_pairs = list(
                frozenset(indices_folds).difference(indices_label_pairs))

            # Store scalar values in folds along label border pairs:
            border_scalars.extend(scalars[indices_label_pairs].tolist())

            # Store scalar values in folds outside label border pairs:
            nonborder_scalars.extend(scalars[indices_outside_pairs].tolist())

    return border_scalars, nonborder_scalars
Exemplo n.º 11
0
def rescale_by_neighborhood(input_vtk,
                            indices=[],
                            nedges=10,
                            p=99,
                            set_max_to_1=True,
                            save_file=False,
                            output_filestring='rescaled_scalars',
                            background_value=-1):
    """
    Rescale the scalar values of a VTK file by a percentile value
    in each vertex's surface mesh neighborhood.

    Parameters
    ----------
    input_vtk : string
        name of VTK file with a scalar value for each vertex
    indices : list of integers (optional)
        indices of scalars to normalize
    nedges : integer
        number or edges from vertex, defining the size of its neighborhood
    p : float in range of [0,100]
        percentile used to normalize each scalar
    set_max_to_1 : bool
        set all rescaled values greater than 1 to 1.0?
    save_file : bool
        save output VTK file?
    output_filestring : string (if save_file)
        name of output file
    background_value : integer
        background value

    Returns
    -------
    rescaled_scalars : list of floats
        rescaled scalar values
    rescaled_scalars_file : string (if save_file)
        name of output VTK file with rescaled scalar values

    Examples
    --------
    >>> import numpy as np
    >>> from mindboggle.guts.mesh import rescale_by_neighborhood
    >>> from mindboggle.mio.vtks import read_scalars
    >>> from mindboggle.mio.plots import plot_surfaces
    >>> from mindboggle.mio.fetch_data import prep_tests
    >>> urls, fetch_data = prep_tests()
    >>> input_vtk = fetch_data(urls['left_travel_depth'])
    >>> indices = []
    >>> nedges = 10
    >>> p = 99
    >>> set_max_to_1 = True
    >>> save_file = True
    >>> output_filestring = 'rescaled_scalars'
    >>> background_value = -1
    >>> rescaled, rescaled_file = rescale_by_neighborhood(input_vtk,
    ...     indices, nedges, p, set_max_to_1, save_file, output_filestring,
    ...     background_value)
    >>> scalars1, name = read_scalars(input_vtk)
    >>> print('{0:0.5f}, {1:0.5f}'.format(max(scalars1), max(rescaled)))
    34.95560, 1.00000
    >>> print('{0:0.5f}, {1:0.5f}'.format(np.mean(scalars1), np.mean(rescaled)))
    7.43822, 0.44950

    View rescaled scalar values on surface (skip test):

    >>> from mindboggle.mio.plots import plot_surfaces # doctest: +SKIP
    >>> plot_surfaces(rescaled_file) # doctest: +SKIP

    """
    import os
    import numpy as np
    from mindboggle.mio.vtks import read_scalars, rewrite_scalars
    from mindboggle.guts.mesh import find_neighbors_from_file, find_neighborhood

    # Load scalars and vertex neighbor lists:
    scalars, name = read_scalars(input_vtk, True, True)
    if not indices:
        indices = [i for i, x in enumerate(scalars) if x != background_value]
    #print("  Rescaling {0} scalar values by neighborhood...".format(len(indices)))
    neighbor_lists = find_neighbors_from_file(input_vtk)

    # Loop through vertices:
    rescaled_scalars = scalars.copy()
    for index in indices:

        # Determine the scalars in the vertex's neighborhood:
        neighborhood = find_neighborhood(neighbor_lists, [index], nedges)

        # Compute a high neighborhood percentile to normalize vertex's value:
        normalization_factor = np.percentile(scalars[neighborhood], p)
        rescaled_scalar = scalars[index] / normalization_factor
        rescaled_scalars[index] = rescaled_scalar

    # Make any rescaled value greater than 1 equal to 1:
    if set_max_to_1:
        rescaled_scalars[[x for x in indices if rescaled_scalars[x] > 1.0]] = 1

    rescaled_scalars = rescaled_scalars.tolist()

    #-------------------------------------------------------------------------
    # Return rescaled scalars and file name
    #-------------------------------------------------------------------------
    if save_file:

        rescaled_scalars_file = os.path.join(os.getcwd(),
                                             output_filestring + '.vtk')
        rewrite_scalars(input_vtk, rescaled_scalars_file, rescaled_scalars,
                        'rescaled_scalars')
        if not os.path.exists(rescaled_scalars_file):
            raise IOError(rescaled_scalars_file + " not found")

    else:
        rescaled_scalars_file = None

    return rescaled_scalars, rescaled_scalars_file