def get_neighbors(idx, Iskel): """ Get a flattened array of neighboring pixel indices. Returns a flattened array of the neighboring pixel indices within Iskel that are True. Only looks at 8-connected neighbors (i.e. a 3x3 kernel with centered on idx). Parameters ---------- idx : np.int Index within Iskel to get neighbors. Iskel : np.ndarray Image of the skeletonized mask, but can be any image array. Returns ------- neighbor_idcs_gloal : list Indices within Iskel of True pixels bordering idx. """ size = (3, 3) cent_idx = 4 # OR int((size[0]*size[1] - 1) / 2) # Pull square with idx at center I, row_offset, col_offset = iu.get_array(idx, Iskel, size) I_flat = np.ravel(I) # Find its neighbors (next possible steps) neighbor_idcs, _ = iu.neighbors_flat(cent_idx, I_flat, size[1]) neighbor_idcs_gloal = iu.reglobalize_flat_idx(neighbor_idcs, size, row_offset, col_offset, Iskel.shape) return neighbor_idcs_gloal
def get_neighbors(idx, Iskel): size = (3, 3) cent_idx = 4 # OR int((size[0]*size[1] - 1) / 2) # Pull square with idx at center I, row_offset, col_offset = iu.get_array(idx, Iskel, size) I_flat = np.ravel(I) # Find its neighbors (next possible steps) neighbor_idcs, _ = iu.neighbors_flat(cent_idx, I_flat, size[1]) neighbor_idcs_gloal = iu.reglobalize_flat_idx(neighbor_idcs, size, row_offset, col_offset, Iskel.shape) return neighbor_idcs_gloal
def is_bp(idx, Iskel): """ Determine if an index is a branchpoint. Determines if the index given by idx is a branchpoint. Branchpoints are not simply pixels in the skeleton with more than two neighbors; they are pruned through a somewhat complicated procedure that minimizes the number of required branchpoints to preserve the skeleton topology. Parameters ---------- idx : np.int Index within Iskel to determine if it is a branchpoint. Iskel : np.ndarray Image of the skeletonized mask, but can be any image array. Returns ------- isbp : int 1 if idx is a branchpoint, else 0. """ # TODO: change to return True/False rather than 1/0. # Trivial case, only one or two neighbors is not bp neighs = get_neighbors(idx, Iskel) if len(neighs) < 3: return 0 # Pull out the neighborhood big_enough = 0 size = (7, 7) # Loop to ensure the domain is large enough to capture all connected # nconn>2 pixels while big_enough == 0: centidx = (int((size[0] - 1) / 2), int((size[1] - 1) / 2)) I, roffset, coffset = iu.get_array(idx, Iskel, size) # Find 4-connected pixels with connectivity > 2 Ic = iu.im_connectivity(I) Ict = np.zeros_like(I) Ict[Ic > 2] = 1 Ilab = measure.label(Ict, background=0, connectivity=1) cpy, cpx = np.where(Ilab == Ilab[centidx]) big_enough = 1 if 1 in cpx or size[0] - 2 in cpx: size = (size[0] + 4, size[1]) big_enough = 0 if 1 in cpy or size[1] - 2 in cpy: size = (size[0], size[1] + 4) big_enough = 0 # Reduce image to subset of connected conn > 2 pixels with a 1 pixel # buffer by zeroing out values outside the domain I[:np.min(cpy) - 1, :] = 0 I[np.max(cpy) + 2:, :] = 0 I[:, :np.min(cpx) - 1] = 0 I[:, np.max(cpx) + 2:] = 0 # Take only the largest blob in case there are border stragglers I = iu.largest_blobs(I, 1, 'keep') # Zero out everything outside our region of interest Ic[np.bitwise_and( Ilab != Ilab[centidx], Ic > 2)] = 1 # set edge pixel connectivity to 1 (even if not true) Ic[I != 1] = 0 # Trivial case where idx is the only possible branchpoint if np.sum(Ic > 2) == 1: return 1 # Compute number of axes and four-connectivity Ina = naxes_connectivity(I) Inf = iu.nfour_connectivity(I) # Ravel everything Icr = np.ravel(Ic) Inar = np.ravel(Ina) Infr = np.ravel(Inf) bps = isbp_parsimonious(Ic, Icr, Inar, Infr) # Return branchpoints to global, flat coordinates bps = iu.reglobalize_flat_idx(bps, Ic.shape, roffset, coffset, Iskel.shape) # Check input idx for being a branchpoint if idx in bps: isbp = 1 else: isbp = 0 return isbp
def is_bp(idx, Iskel): """ Returns 1 if a pixel is a branchpoint in a skeleton given by vrtpath; else 0 """ # Trivial case, only one or two neighbors is not bp neighs = get_neighbors(idx, Iskel) if len(neighs) < 3: return 0 # Pull out the neighborhood big_enough = 0 size = (7, 7) # Loop to ensure our size is large enough to capture all connected nconn>2 pixels while big_enough == 0: centidx = (int((size[0] - 1) / 2), int((size[1] - 1) / 2)) I, roffset, coffset = iu.get_array(idx, Iskel, size) # Find 4-connected pixels with connectivity > 2 Ic = iu.im_connectivity(I) Ict = np.zeros_like(I) Ict[Ic > 2] = 1 Ilab = measure.label(Ict, background=0, connectivity=1) cpy, cpx = np.where(Ilab == Ilab[centidx]) big_enough = 1 if 1 in cpx or size[0] - 2 in cpx: size = (size[0] + 4, size[1]) big_enough = 0 if 1 in cpy or size[1] - 2 in cpy: size = (size[0], size[1] + 4) big_enough = 0 # Reduce image to subset of connected conn > 2 pixels with a 1 pixel buffer by zeroing out values outside the domain I[:np.min(cpy) - 1, :] = 0 I[np.max(cpy) + 2:, :] = 0 I[:, :np.min(cpx) - 1] = 0 I[:, np.max(cpx) + 2:] = 0 # Take only the largest blob in case there are border stragglers I = iu.largest_blobs(I, 1, 'keep') # Zero out everything outside our region of interest Ic[np.bitwise_and( Ilab != Ilab[centidx], Ic > 2)] = 1 # set edge pixel connectivity to 1 (even if not true) Ic[I != 1] = 0 # Trivial case where idx is the only possible branchpoint if np.sum(Ic > 2) == 1: return 1 # Compute number of axes and four-connectivity Ina = naxes_connectivity(I) Inf = iu.nfour_connectivity(I) # Ravel everything Icr = np.ravel(Ic) Inar = np.ravel(Ina) Infr = np.ravel(Inf) bps = isbp_parsimonious(Ic, Icr, Inar, Infr) # Return branchpoints to global, flat coordinates bps = iu.reglobalize_flat_idx(bps, Ic.shape, roffset, coffset, Iskel.shape) # Check input idx for being a branchpoint if idx in bps: return 1 else: return 0