Esempio n. 1
0
def naxes_connectivity(I):

    # Get the pixels we want to check (exclude edge pixels)
    Ir = np.ravel(I)
    edgeidcs = iu.edge_coords(I.shape, dtype='flat')

    allpix = set(np.where(Ir == 1)[0])

    dopix = allpix - edgeidcs
    savepix = list(dopix)

    naxes = []
    while dopix:
        pix = dopix.pop()
        count = 0
        if Ir[pix + 1] == 1 or Ir[pix - 1] == 1:
            count = count + 1
        if Ir[pix + I.shape[1]] == 1 or Ir[pix - I.shape[1]] == 1:
            count = count + 1
        if Ir[pix + 1 + I.shape[1]] == 1 or Ir[pix - 1 - I.shape[1]] == 1:
            count = count + 1
        if Ir[pix - 1 + I.shape[1]] == 1 or Ir[pix + 1 - I.shape[1]] == 1:
            count = count + 1
        naxes.append(count)

    Inax = np.zeros_like(Ir, dtype=np.uint8)
    Inax[savepix] = naxes
    Inax = np.reshape(Inax, I.shape)

    return Inax
Esempio n. 2
0
def test_edge_coords():
    """Test edge_coords() function."""
    I = np.zeros((3, 3))
    sizeI = np.shape(I)
    edgepts = im_utils.edge_coords(sizeI, dtype='xy')
    # make assertions to known edge coordinates in x and y
    assert np.all(edgepts[0] == [0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 0])
    assert np.all(edgepts[1] == [0, 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0])
Esempio n. 3
0
def isbp_walk_for_bps(I, bpi):

    bpi = set(bpi)

    # Use raveled image
    Ir = np.ravel(I)

    # Get edge pixels
    edgeidcs = iu.edge_coords(I.shape, dtype='flat')

    # Get emanators from first bp
    do_first = set()  # These are the 4-connected emanators
    emanators = set()
    for bp in bpi:
        emanators = emanators | set(iu.neighbors_flat(bp, Ir, I.shape[1])[0])
        do_first.update(iu.four_conn([bp], I)[0])

    # Create set containing pixels that have already been visited
    walked = bpi | emanators

    while emanators:

        if do_first:
            idx = do_first.pop()
            emanators.remove(idx)
        else:
            idx = emanators.pop()

        walking = 1
        while walking:

            walked.add(idx)
            neighs = set(iu.neighbors_flat(idx, Ir, I.shape[1])[0])
            neighs = neighs - walked

            if len(neighs) == 0:
                walking = 0

            elif len(neighs) == 1:
                idx = neighs.pop()
                if idx in edgeidcs:
                    walking = 0
            else:
                bpi.add(idx)
                fourconn = iu.four_conn([idx], I)[0]
                fourconn = [f for f in fourconn if f in neighs]
                do_first.update(fourconn)
                emanators = emanators | neighs
                walked.add(idx)
                walked.update(neighs)

    return bpi
Esempio n. 4
0
def naxes_connectivity(I):
    """
    Compute number of axes of connectivity.

    Computes the number of axes of connectivity for each pixel in an input
    skeleton. The maximum is four; horizontal, vertical, and two diagonals.

    The number of axes of pixel connectivity is used to determine where to
    place branchpoints.

    Parameters
    ----------
    I : np.ndarray
        Binary image of a skeleton. In RivGraph, the skeleton is a reduced and
        padded version of Iskel.

    Returns
    -------
    Inax : np.ndarray
        Same shape as I; values correspond to the number of axes represented
        by each pixel's connectivity.

    """
    # Get the pixels we want to check (exclude edge pixels)
    Ir = np.ravel(I)
    edgeidcs = iu.edge_coords(I.shape, dtype='flat')

    allpix = set(np.where(Ir == 1)[0])

    dopix = allpix - edgeidcs
    savepix = list(dopix)

    naxes = []
    while dopix:
        pix = dopix.pop()
        count = 0
        if Ir[pix + 1] == 1 or Ir[pix - 1] == 1:
            count = count + 1
        if Ir[pix + I.shape[1]] == 1 or Ir[pix - I.shape[1]] == 1:
            count = count + 1
        if Ir[pix + 1 + I.shape[1]] == 1 or Ir[pix - 1 - I.shape[1]] == 1:
            count = count + 1
        if Ir[pix - 1 + I.shape[1]] == 1 or Ir[pix + 1 - I.shape[1]] == 1:
            count = count + 1
        naxes.append(count)

    Inax = np.zeros_like(Ir, dtype=np.uint8)
    Inax[savepix] = naxes
    Inax = np.reshape(Inax, I.shape)

    return Inax
Esempio n. 5
0
def isbp_walk_for_bps(I, bpi):
    """
    Find branchpoints by walking from a pixel.

    Finds branchpoints by ensuring that all pixels in the sub-skeleton can be
    walked to from the set of already-found branchpoints, without visiting
    the same pixel more than once.

    Parameters
    ----------
    I : np.ndarray
        Binary image of a skeleton. In RivGraph, the skeleton is a reduced and
        padded version of Iskel.
    bpi : list
        Indices within I of the branchpoint to begin walk.

    Returns
    -------
    bpi : list
        Branchpoint indices in I.

    """
    bpi = set(bpi)

    # Use raveled image
    Ir = np.ravel(I)

    # Get edge pixels
    edgeidcs = iu.edge_coords(I.shape, dtype='flat')

    # Get emanators from first bp
    do_first = set()  # These are the 4-connected emanators
    emanators = set()
    for bp in bpi:
        emanators = emanators | set(iu.neighbors_flat(bp, Ir, I.shape[1])[0])
        do_first.update(iu.four_conn([bp], I)[0])

    # Create set containing pixels that have already been visited
    walked = bpi | emanators

    while emanators:

        if do_first:
            idx = do_first.pop()
            emanators.remove(idx)
        else:
            idx = emanators.pop()

        walking = 1
        while walking:

            walked.add(idx)
            neighs = set(iu.neighbors_flat(idx, Ir, I.shape[1])[0])
            neighs = neighs - walked

            if len(neighs) == 0:
                walking = 0

            elif len(neighs) == 1:
                idx = neighs.pop()
                if idx in edgeidcs:
                    walking = 0
            else:
                bpi.add(idx)
                fourconn = iu.four_conn([idx], I)[0]
                fourconn = [f for f in fourconn if f in neighs]
                do_first.update(fourconn)
                emanators = emanators | neighs
                walked.add(idx)
                walked.update(neighs)

    return bpi
Esempio n. 6
0
def isbp_parsimonious(Ic, Icr, Inar, Infr):
    """
    Computes parsimonious set of branchpoints.

    Parameters
    ----------
    Ic : np.ndarray
        Image of possible branchpoints; values correspond to number of
        neighbors.
    Icr : np.ndarray
        Raveled (np.ravel) version of Ic.
    Inar : np.ndarray
        Raveled version of image returned by naxes_connectivity.
    Infr : np.ndarray
        Raveled version of image returned by nfour_connectivity.

    Returns
    -------
    bps : list
        All branchpoint indices within Ic.

    """
    # Find all possible branchpoints by considerng those with conn>2
    bp_poss = np.where(Ic > 2)
    bp_poss_i = np.ravel_multi_index(bp_poss, Ic.shape)
    bp_poss_i = list(set(bp_poss_i) - iu.edge_coords(Ic.shape))

    # Find all possible branchpoint combinations by walking from each
    # possible initial branchpoint
    bpsave = []
    for bpi in bp_poss_i:
        bptemp = isbp_walk_for_bps(np.array(Ic, dtype=np.bool), [bpi])
        bpsave.append(bptemp)

    # Number of branchpoints for each possible initial branchpoint
    bpcounts = [len(b) for b in bpsave]
    bpsolo = [bpsave[i].pop() for i, c in enumerate(bpcounts) if c == 1]

    # If only one branchpoint is required, use it. However, there could be
    # multiple branchpoints that can serve as the single; use the one with
    # highest naxes-connectivity; if there are still multiple choices, take the
    # highest 4-connectivity. If there are still no unique choices, choose the
    # highest 4-connected among the highest naxes-connected.
    if len(bpsolo) > 0:
        naxconn = Inar[bpsolo]
        maxnax = [
            bps for bps, nl in zip(bpsolo, naxconn) if nl == max(naxconn)
        ]
        if len(maxnax) == 1:
            return [maxnax]
        else:
            fourconn = Infr[bpsolo]
            maxfour = [
                bpsolo[i] for i, fc in enumerate(fourconn)
                if fc == max(fourconn)
            ]
            if len(maxfour) == 1:
                return [maxfour]
        # Now see if there's a max 4-conn within the max naxes-conn
        fourconn = Infr[maxnax]
        maxfour = [
            maxnax[i] for i, fc in enumerate(fourconn) if fc == max(fourconn)
        ]
        return [min(maxfour)]

    # Set bp_must according to conn, naxes, nfour
    keepvals = [[6, 4, 2], [5, 3, 1], [5, 3, 4], [3, 3, 2], [3, 3, 1],
                [4, 2, 4]]
    bp_must = []
    for kv in keepvals:
        keeps = np.ndarray.tolist(
            np.where(
                np.logical_and(np.logical_and(Icr == kv[0], Inar == kv[1]),
                               Infr == kv[2]) == 1)[0])
        bp_must = bp_must + keeps

    # Special cases - 4,4,2 - choose one
    keepvals = [[4, 4, 2]]
    for kv in keepvals:
        keeps = np.ndarray.tolist(
            np.where(
                np.logical_and(np.logical_and(Icr == kv[0], Inar == kv[1]),
                               Infr == kv[2]) == 1)[0])
        if len(keeps) == 2:
            bp_must = bp_must + [keeps[0]]

    # Only consider combinations that have branchpoints where they must be placed
    if len(bp_must) > 0:
        bps = isbp_walk_for_bps(np.array(Ic, dtype=np.bool), bp_must)
        return bps

    # If there are no branchpoints that must exist based on patterns,
    # use the set with the smallest number of branchpoints. If there are multiple
    # sets, we move on...
    mincount = min(bpcounts)
    minidcs = [i for i, bpi in enumerate(bpcounts) if bpi == mincount]
    if len(minidcs) == 1:
        return bpsave[minidcs[0]]

    # Finally, choose branchpoints based on the most common branchpoints created
    # when walking from all possible branchpoints
    mode = stats.mode([p for b in bpsave for p in b])
    bp_init = np.ndarray.tolist(mode.mode)
    bps = isbp_walk_for_bps(np.array(Ic, dtype=np.bool), bp_init)

    return bps