def skeletoniseSkimg(maskFilePath): image = io.imread(maskFilePath) image = rgb2gray(image) binary = image > 0 # perform skeletonization skeleton = skeletonize(binary) summary = summarize(Skeleton(skeleton, spacing=1)) # starting coordinate in y, x startCoord = [ summary.iloc[0]['image-coord-src-0'], summary.iloc[0]['image-coord-src-1'] ] endCoord = [ summary.iloc[0]['image-coord-dst-0'], summary.iloc[0]['image-coord-dst-1'] ] # c0 contains information of all points on the skeleton # g0 is the adjacency list g0, c0, _ = skeleton_to_csgraph(skeleton, spacing=1) all_pts = c0[1:] # get points along skeleton in the correct sequence pts = traverseSkeleton(startCoord, endCoord, g0.toarray(), all_pts) return pts.astype(int)
def get_no_of_forks(self, plot=False): # get the degree for every cell pixel (no. of neighbouring pixels) pixel_graph, coordinates, degrees = skeleton_to_csgraph( self.cell_skeleton) # array of all pixel locations with degree more than 2 fork_image = np.where(degrees > [2], 1, 0) s = scipy.ndimage.generate_binary_structure(2, 2) labeled_array, num_forks = scipy.ndimage.label(fork_image, structure=s) if plot == True: fork_indices = np.where(degrees > [2]) fork_coordinates = zip(fork_indices[0], fork_indices[1]) fig, ax = plt.subplots(figsize=(4, 4)) ax.set_title('path') ax.imshow(self.cell_skeleton, interpolation='nearest') for i in fork_coordinates: c = plt.Circle((i[1], i[0]), 0.6, color='green') ax.add_patch(c) ax.set_axis_off() plt.tight_layout() plt.show() return num_forks
def refresh_seeds(self, n_trees=1) -> np.ndarray: """Fetch a new set of tip seeds from the current canvas.""" new_seeds = list() logging.info("TipTracerSeedPolicy skeletonizing and extracting seeds") # Transform logits to probabilities, apply threshold, and skeletonize to # extract the locations of leaf nodes ("tips") c_t = expit(np.squeeze(self.canvas.seed)) c_t = np.nan_to_num(c_t) c_t = (c_t >= self.skeletonization_threshold).astype(np.uint8) s_t = morphology.skeletonize(c_t) self._check_save_skeleton(s_t) g_t, c_t, _ = skeleton_to_csgraph(s_t) g_t = nx.from_scipy_sparse_matrix(g_t) # Get connected components and extract leaf nodes, sorting from large to small. subgraphs = sorted(nx.connected_components(g_t), key=len, reverse=True) for subgraph_nodes in subgraphs[:n_trees]: leaf_node_ids = [ node_id for node_id, node_degree in g_t.degree(subgraph_nodes) if node_degree == 1 ] # Produce a nested list of [y, x] coordinates of leaf nodes in this subgraph. leaf_node_yx = c_t[leaf_node_ids, :].astype(int).tolist() new_seeds.extend(leaf_node_yx) # Add z-coordinate to new_seeds and append to list of seed coords. new_seeds = np.hstack((np.zeros((len(new_seeds), 1), dtype=int), new_seeds, np.full((len(new_seeds), 1), self.idx, dtype=int))) # Compute the unique union of existing coords and new seeds (do not re-seed in # locations which have already been seeded. coord_update = np.vstack((self.coords, new_seeds)) coord_update = np.unique(coord_update, axis=0) coord_update = coord_update[np.argsort(coord_update[:, 3])] self.coords = coord_update
def bw_skel_and_analyze(bw): if bw.ndim == 3: skeleton = skeletonize_3d(bw) elif bw.ndim == 2: skeleton = skeletonize(bw) skeleton[skeleton > 0] = 1 if skeleton.any() and np.count_nonzero(skeleton) > 1: try: pixel_graph, coordinates, degrees = skeleton_to_csgraph(skeleton) coordinates = coordinates[0::] ### get rid of zero at beginning except: pixel_graph = np.zeros(np.shape(skeleton)) coordinates = [] degrees = np.zeros(np.shape(skeleton)) print('error, could not skeletonize') else: pixel_graph = np.zeros(np.shape(skeleton)) coordinates = [] degrees = np.zeros(np.shape(skeleton)) return pixel_graph, degrees, coordinates
import pandas as pd pd.set_option('display.max_columns', 10) pd.set_option('display.width', 1000) path = "C:/Users/Christian/Desktop/Third_CV/Complete_images/MitoSegNet/170412 MD4046 w1 next to vulva FL200.tif" #path = "skeletonize_examples/5.tif" # reads the image, converts from rgb to grayscale, converts to boolean array image = img_as_bool(color.rgb2gray(io.imread(path))) out = skeletonize(image).astype("uint8") #print(type(out)) #io.imsave("test2.tif", out) pixel_graph, coordinates, degrees = skeleton_to_csgraph(out) branch_data = summarise(out) print(branch_data) grouped_branch_data_mean = branch_data.groupby(["skeleton-id"], as_index=False).mean() grouped_branch_data_sum = branch_data.groupby(["skeleton-id"], as_index=False).sum() sum_table = pd.DataFrame(columns=[ "Number of branches", "Average branch length", "Total object length", "Average curvature index" ])
def classify_branching_structure(self, plot=False): def get_soma_node(): near = [] for i in range(skan.csr.Skeleton(self.cell_skeleton).n_paths): path_coords = skan.csr.Skeleton( self.cell_skeleton).path_coordinates(i) nearest = min( path_coords, key=lambda x: self.distance(self.soma_on_skeleton, x)) near.append(nearest) soma_on_path = min( near, key=lambda x: self.distance(self.soma_on_skeleton, x)) for i, j in enumerate( skan.csr.Skeleton(self.cell_skeleton).coordinates): if all(soma_on_path == j): soma_node = [i] break return soma_node def get_soma_branches(soma_node, paths_list): soma_branches = [] for path in paths_list: # print(path) if soma_node in path: soma_branches.append(path) return soma_branches pixel_graph, coordinates, degrees = skeleton_to_csgraph( self.cell_skeleton) branch_statistics = skan.csr.branch_statistics(pixel_graph) paths_list = skan.csr.Skeleton(self.cell_skeleton).paths_list() terminal_branches = [] branching_structure_array = [] # get branches containing soma node soma_node = get_soma_node() soma_branches = get_soma_branches(soma_node, paths_list) if len(soma_branches) > 2: junctions = soma_node delete_soma_branch = False else: # collect first level/primary branches junctions = [soma_branches[0][0], soma_branches[0][-1]] delete_soma_branch = True # eliminate loops in branches and path lists branch_statistics, paths_list = self.eliminate_loops( branch_statistics, paths_list) while True: junctions, branches, terminal_branch, branch_statistics = self.branch_structure( junctions, branch_statistics, paths_list) branching_structure_array.append(branches) terminal_branches.extend(terminal_branch) if len(junctions) == 0: break if delete_soma_branch == True: branching_structure_array[0].remove(soma_branches[0]) if plot == True: # store same level branch nodes in single array color_branches_coords = [] for branch_level in branching_structure_array: single_branch_level = [] for path in branch_level: path_coords = [] for node in path: path_coords.append(coordinates[node]) single_branch_level.extend(path_coords) color_branches_coords.append(single_branch_level) fig, ax = plt.subplots(figsize=(4, 4)) ax.set_title('path') ax.imshow(self.cell_skeleton, interpolation='nearest') color_codes = ['red', 'blue', 'magenta', 'green', 'cyan'] for j, color_branch in enumerate(color_branches_coords): if j > 4: j = 4 for k in color_branch: c = plt.Circle((k[1], k[0]), 0.5, color=color_codes[j]) ax.add_patch(c) ax.set_axis_off() plt.tight_layout() plt.show() self.branching_structure_array = branching_structure_array self.terminal_branches = terminal_branches
def detect_peduncle(peduncle_img, settings=None, px_per_mm=None, bg_img=None, save=False, name="", pwd=""): if settings is None: settings = settings.detect_peduncle() if (bg_img is not None) and save: fig = plt.figure() plot_image(bg_img) save_fig(fig, pwd, name + "_00") if bg_img is None: bg_img = peduncle_img if px_per_mm: branch_length_min_px = px_per_mm * settings['branch_length_min_mm'] else: branch_length_min_px = settings['branch_length_min_px'] skeleton_img = skeletonize_img(peduncle_img) junc_coords, end_coords = get_node_coord(skeleton_img) if save: visualize_skeleton(bg_img, skeleton_img, coord_junc=junc_coords, coord_end=end_coords, name=name + "_01", pwd=pwd) if save: fit_ransac(peduncle_img, bg_img=bg_img.copy(), save=True, name=name + "_ransac", pwd=pwd) # update_image = True # while update_image: skeleton_img, b_remove = threshold_branch_length(skeleton_img, branch_length_min_px) # update_image = b_remove.any() junc_coords, end_coords = get_node_coord(skeleton_img) if save: visualize_skeleton(bg_img.copy(), skeleton_img, coord_junc=junc_coords, coord_end=end_coords, name=name + "_02", pwd=pwd) graph, pixel_coordinates, degree_image = skan.skeleton_to_csgraph( skeleton_img, unique_junctions=True) dist, pred = csgraph.shortest_path(graph, directed=False, return_predecessors=True) end_nodes = coords_to_nodes(pixel_coordinates, end_coords[:, [1, 0]]) junc_nodes = coords_to_nodes(pixel_coordinates, junc_coords[:, [1, 0]]) path, path_length_px, branch_data = find_path(dist, pred, junc_nodes, end_nodes, pixel_coordinates, bg_image=bg_img.copy(), do_animate=False) branch_data = get_branch_center(branch_data, dist, pixel_coordinates, skeleton_img) path_img = path_mask(path, pixel_coordinates, skeleton_img.shape) junc_coords = pixel_coordinates[get_ids_on_path(path, pixel_coordinates, junc_nodes)][:, [1, 0]] end_coords = pixel_coordinates[get_ids_on_path(path, pixel_coordinates, end_nodes)][:, [1, 0]] end_coords = np.array([ pixel_coordinates[path[0]][[1, 0]], pixel_coordinates[path[-1]][[1, 0]] ]) # make sure that end nodes are not labeled as junctions if junc_coords.shape[0] != 0: for end_coord in end_coords: dst = distance(junc_coords, end_coord) mask = dst > 0.1 junc_coords = junc_coords[mask] if save: visualize_skeleton( bg_img, path_img, coord_junc= junc_coords, # junc_nodes=junc_nodes, end_nodes=end_nodes, coord_end=end_coords, name=name + "_03", pwd=pwd) if save: visualize_skeleton(bg_img, path_img, coord_junc=junc_coords, branch_data=branch_data, coord_end=end_coords, name=name + "_04", pwd=pwd) return path_img, branch_data, junc_coords, end_coords
#h, w = imgb.shape[:2] #imgb = cv2.resize(imgb,(h,h), interpolation=cv2.INTER_CUBIC) pbef = Process(imgb) pbef.lowp = np.array([150, 60, 100]) pbef.highp = np.array([170, 255, 255]) pbef.loww = np.array([90, 15, 150]) pbef.highw = np.array([115, 255, 255]) maskb = pbef.mask(kernel) resb = pbef.res(maskb) maskb = cv2.blur(maskb, (5, 5)) binaryb = maskb > filters.threshold_otsu(maskb) skeletonb = morphology.skeletonize(binaryb) fig, ax = plt.subplots() draw.overlay_skeleton_2d(maskb, skeletonb, dilate=1, axes=ax) #graphb = csgraph_from_masked(binaryb) #plt.imshow(graphb) gb, cb, db = skeleton_to_csgraph(skeletonb) draw.overlay_skeleton_networkx(gb, cb, image=maskb) branch_datab = summarize(Skeleton(skeletonb)) dfb = branch_datab.loc[branch_datab['branch-type'] == 1] #dfb.to_csv(r'./before.csv') draw.overlay_euclidean_skeleton_2d(maskb, branch_datab, skeleton_color_source='branch-type') plt.show() cv2.waitKey(0) cv2.destroyAllWindows()
path = fileRoot + '/box/Sites/DeepVess/data/20200228/20200228__0001_z_dvSkel.tif' dvSkel = tifffile.imread(path) print(' dvSkel:', dvSkel.shape) # convert the deepvess mask to a skeleton (same as deepves postprocess) print(' making skeleton from binary stack dvMask ...') # todo: fix this, older version need to use max_pool3d #skeleton0 = morphology.skeletonize(dvMask) startSeconds = time.time() skeleton0 = morphology.skeletonize_3d(dvMask) print(' skeleton0:', type(skeleton0), skeleton0.dtype, skeleton0.shape, np.min(skeleton0), np.max(skeleton0)) print(' took:', round(time.time() - startSeconds, 2), 'seconds') # # analysis of skeleton pixel_graph, coordinates, degrees = skan.skeleton_to_csgraph(skeleton0) print(' pixel_graph:', type(pixel_graph)) print(' coordinates:', type(coordinates), coordinates.shape) # (n,3) each row is a point in skel print(' degrees:', type(degrees), degrees.shape) # make a list of coordinate[i] that are segment endpoints_src nCoordinates = coordinates.shape[0] slabs = coordinates.copy() #np.full((nCoordinates,3), np.nan) nodes = np.full((nCoordinates), np.nan) nodeEdgeList = [[] for tmp in range(nCoordinates)] edges = np.full((nCoordinates), np.nan) print('degrees==0:', degrees[degrees == 0].shape) print('degrees==1:', degrees[degrees == 1].shape) print('degrees==2:', degrees[degrees == 2].shape)