Beispiel #1
0
def remove_ticks(skeleton, threshold):
    """
  Simple merging of individual TESAR cubes results in lots of little 
  ticks due to the edge effect. We can remove them by thresholding
  the path length from a given branch to the "main body" of the neurite. 
  We successively remove paths from shortest to longest until no branches
  below threshold remain.

  If TEASAR parameters were chosen such that they allowed for spines to
  be traced, this is also an opportunity to correct for that.

  This algorithm is O(N^2) in the number of terminal nodes.

  Parameters:
    threshold: The maximum length in nanometers that may be culled.

  Returns: tick free skeleton
  """
    if skeleton.empty() or threshold == 0:
        return skeleton

    skels = []
    for component in skeleton.components():
        skels.append(_remove_ticks(component, threshold))

    return Skeleton.simple_merge(skels).consolidate(
        remove_disconnected_vertices=False)
Beispiel #2
0
def remove_loops(skeleton):
  if skeleton.empty():
    return skeleton

  skels = []
  for component in skeleton.components():
    skels.append(_remove_loops(component))

  return Skeleton.simple_merge(skels).consolidate(remove_disconnected_vertices=False)
Beispiel #3
0
def remove_dust(skeleton, dust_threshold):
    """Dust threshold in physical cable length."""

    if skeleton.empty() or dust_threshold == 0:
        return skeleton

    skels = []
    for skel in skeleton.components():
        if skel.cable_length() > dust_threshold:
            skels.append(skel)

    return Skeleton.simple_merge(skels)
def test_simple_merge():
    skel1 = Skeleton(
        [
            (0, 0, 0),
            (1, 0, 0),
            (2, 0, 0),
        ],
        edges=[
            (0, 1),
            (1, 2),
        ],
        segid=1,
    )

    skel2 = Skeleton(
        [
            (0, 0, 1),
            (1, 0, 2),
            (2, 0, 3),
        ],
        edges=[
            (0, 1),
            (1, 2),
        ],
        segid=1,
    )

    result = Skeleton.simple_merge([skel1, skel2])

    expected = Skeleton(
        [
            (0, 0, 0),
            (1, 0, 0),
            (2, 0, 0),
            (0, 0, 1),
            (1, 0, 2),
            (2, 0, 3),
        ],
        edges=[(0, 1), (1, 2), (3, 4), (4, 5)],
        segid=1,
    )

    assert result == expected

    skel1.extra_attributes = [{
        "id": "wow",
        "data_type": "uint8",
        "components": 1,
    }]
    skel1.wow = np.array([1, 2, 3], dtype=np.uint8)

    skel2.extra_attributes = [{
        "id": "wow",
        "data_type": "uint8",
        "components": 1,
    }]
    skel2.wow = np.array([4, 5, 6], dtype=np.uint8)

    result = Skeleton.simple_merge([skel1, skel2])
    expected.wow = np.array([1, 2, 3, 4, 5, 6], dtype=np.uint8)

    assert result == expected

    skel2.extra_attributes[0]['data_type'] = np.uint8

    try:
        Skeleton.simple_merge([skel1, skel2])
        assert False
    except SkeletonAttributeMixingError:
        pass

    skel2.extra_attributes[0]['data_type'] = 'uint8'
    skel2.extra_attributes.append({
        "id": "amaze",
        "data_type": "float32",
        "components": 2,
    })

    try:
        Skeleton.simple_merge([skel1, skel2])
        assert False
    except SkeletonAttributeMixingError:
        pass
Beispiel #5
0
def join_close_components(skeletons, radius=None):
    """
  Given a set of skeletons which may contain multiple connected components,
  attempt to connect each component to the nearest other component via the
  nearest two vertices. Repeat until no components remain or no points closer
  than `radius` are available.

  radius: float in same units as skeletons

  Returns: Skeleton
  """
    if radius is not None and radius <= 0:
        raise ValueError("radius must be greater than zero: " + str(radius))

    if isinstance(skeletons, Skeleton):
        skeletons = [skeletons]

    skels = []
    for skeleton in skeletons:
        skels += skeleton.components()

    skels = [skl.consolidate() for skl in skels if not skl.empty()]

    if len(skels) == 1:
        return skels[0]
    elif len(skels) == 0:
        return Skeleton()

    while len(skels) > 1:
        N = len(skels)

        radii_matrix = np.zeros((N, N), dtype=np.float32) + np.inf
        index_matrix = np.zeros((N, N, 2), dtype=np.uint32) + -1

        for i in range(len(skels)):
            for j in range(len(skels)):
                if i == j:
                    continue
                elif radii_matrix[i, j] != np.inf:
                    continue

                s1, s2 = skels[i], skels[j]
                dist_matrix = scipy.spatial.distance.cdist(
                    s1.vertices, s2.vertices)
                radii_matrix[i, j] = np.min(dist_matrix)
                radii_matrix[j, i] = radii_matrix[i, j]

                index_matrix[i, j] = np.unravel_index(np.argmin(dist_matrix),
                                                      dist_matrix.shape)
                index_matrix[j, i] = index_matrix[i, j]

        if np.all(radii_matrix) == np.inf:
            break

        min_radius = np.min(radii_matrix)
        if radius is not None and min_radius > radius:
            break

        i, j = np.unravel_index(np.argmin(radii_matrix), radii_matrix.shape)
        s1, s2 = skels[i], skels[j]
        fused = Skeleton.simple_merge([s1, s2])

        fused.edges = np.concatenate([
            fused.edges,
            [[
                index_matrix[i, j, 0],
                index_matrix[i, j, 1] + s1.vertices.shape[0]
            ]]
        ])
        skels[i] = None
        skels[j] = None
        skels = [_ for _ in skels if _ is not None] + [fused]

    return Skeleton.simple_merge(skels).consolidate()