def skeleton_cleaning(skeleton, begin): """ Clean the skeleton :param skeleton: (numpy 2D array of binary uint8) representing the skeleton of side view image of maize plant :param begin: bottm of stem :return: (numpy 2D array of binary uint8) representing cleaned skeleton """ cleaned_skeleton = np.array(skeleton) skeleton_inverted = np.array(skeleton, 'float') skeleton_inverted[skeleton_inverted == 0] = np.Inf mcp = graph.MCP(skeleton_inverted) cc, t = mcp.find_costs([begin]) s = np.where(skeleton) cross = list() ends = list() for i in range(len(s[0])): pattern = skeleton[s[0][i] - 1:s[0][i] + 2, s[1][i] - 1:s[1][i] + 2] if len(np.where(pattern > 0)[0]) > 3: cross.append([s[0][i], s[1][i]]) elif len(np.where(pattern > 0)[0]) < 3: ends.append([s[0][i], s[1][i]]) for end in ends: temp = list() current = end prec_in_cross = 0 loop_again = 1 while loop_again: direction = t[current[0], current[1]] if direction == -1: break temp.append(current) a = np.zeros([8]) a[direction] = 1 a = np.insert(a, 4, 0) a = a[::-1] a = a.reshape([3, 3]) next_one = np.where(a == 1) current = [ current[0] + next_one[0][0] - 1, current[1] + next_one[1][0] - 1 ] if current in cross: prec_in_cross = 1 else: if prec_in_cross: temp.pop() loop_again = 0 if len(temp) < 100: for pixel in temp: cleaned_skeleton[pixel[0], pixel[1]] = 0 return cleaned_skeleton
def find_centerline(skeleton): '''Find the centerline of the worm from the skeleton Outputs both the centerline values (traceback and image to view) and the spline interpretation of the traceback Parameters: ------------ skeleton: array_like (cast to booleans) shape (n,m) Binary image of the skeleton of the worm mask Returns: ----------- center: array_like shape (n,m) Binary image that indicates where the centerline is (1.0 = centerline, 0.0 = not centerline) traceback: list of 2-d tuples List of indices associated with the centerline, starting with one of the endpoints of the centerline and ending with the ending index of the centerline. endpoints: array_like (cast to booleans) shape (n,m) Binary image of the endpoints determined by the hit_or_miss transform ''' #find enpoints endpoints = find_enpoints(skeleton) ep_index = list(zip(*np.where(endpoints))) #need to change the skeleton to have all zeros be inf #to keep the minimal cost function from stepping off the skeleton skeleton = skeleton.astype(float) skeleton[skeleton == 0] = np.inf #create mcp object mcp = skg.MCP(skeleton) #keep track of the longest path/index pair traceback = [] index = (0, 0) #compute costs for every endpoint pair for i in range(0, len(ep_index) - 1): costs, _ = mcp.find_costs([ep_index[i]], ep_index[0:]) dist = costs[np.where(endpoints)] tb = mcp.traceback(ep_index[dist.argmax()]) #if you find a longer path, then update the longest values if len(tb) > len(traceback): traceback = tb index = (i, dist.argmax()) print(index) print("length: " + str(len(traceback))) #center=[] center = generate_centerline(traceback, skeleton.shape) #tck = generate_spline(traceback, 15) return center, traceback, endpoints
def generate_centerline_from_points(points, skeleton): '''Generate a traceback of the centerline from a list of points along the skeleton that you want the centerline to go through Parameters: ------------ points: list of 2-d tuples List of indices that the centerline will go through. Indices must be given in the order that the centerline should encounter each point skeleton: array_like (cast to booleans) shape (n,m) Binary image of the skeleton of the worm mask Returns: ----------- traceback: list of 2-d tuples List of indices associated with the centerline, starting with one of the endpoints of the centerline and ending with the ending index of the centerline. ''' skel_path = np.transpose(np.where(skeleton)) skeleton = skeleton.astype(float) skeleton[skeleton == 0] = np.inf #create mcp object mcp = skg.MCP(skeleton) traceback = [] for i in range(0, len(points) - 1): start = points[i] end = points[i + 1] print("start: ", start, " end: ", end) #print(skeleton[start]) print(skeleton[end]) if np.all(np.isinf(skeleton[points[i]])): #print("start not in skeleton") start = geometry.closest_point(start, skel_path)[1] if np.all(np.isinf(skeleton[end])): #print("end: ", end) end = geometry.closest_point(end, skel_path)[1] costs = mcp.find_costs([start], [end]) tb = mcp.traceback(end) traceback.extend(tb[:-1]) return traceback
def shortest_path_cluster(array, seed, geometric=True): """ cluster array cells around seeds such that the connecting path has minimum cost The cost of a path is the sum of the array cells value on the path *** This function require the skimage (scikits image) module *** :Input: array: float array containing the cost of each pixels seed: integer array where 0 are background cells, to cluster around seeds and positive value are clustering seed (the value is the label) geometric: if True, weight diagonal edges by 1/sqrt(2) - see skimage.graph.MCP and MCP_geometric for details - :Output: labeled array, i.e. an integer array where each cell has the value of the closest seed """ import skimage.graph as graph # create graph object if geometric: g = graph.MCP_Geometric(array) else: g = graph.MCP(array) c, t = g.find_costs(zip(*seed.nonzero())) # compute minimum path # convert skimage.graph trace to parenting index-map (with flat indices) offsets = _np.concatenate( (-g.offsets, [[0] * seed.ndim])) # add null shift at end of offsets p = _np.arange(seed.size) + _ravel( offsets[t.ravel()], array.shape) #_np.dot(offsets[t.ravel()],[array.shape[1],1]) # find tree roots (top ancestor of all array elements) # iteratively replace parent indices by grand parent, until there is no change gp = p[p] # grand-parent ggp = p[gp] # grand-grand-parent while _np.any(gp != ggp): gp = ggp ggp = p[gp] gp.shape = seed.shape return seed.ravel()[gp]
def longest_path(skeleton): endpoints = get_endpoints(skeleton) ep_indices = numpy.transpose(endpoints.nonzero()) skeleton = skeleton.astype(float) skeleton[skeleton == 0] = numpy.inf mcp = graph.MCP(skeleton) longest_traceback = [] # compute costs for every endpoint pair for i, endpoint in enumerate(ep_indices[:-1]): remaining_indices = ep_indices[i+1:] costs = mcp.find_costs([endpoint], remaining_indices)[0] path_lengths = costs[tuple(remaining_indices.T)] most_distant = remaining_indices[path_lengths.argmax()] traceback = mcp.traceback(most_distant) if len(traceback) > len(longest_traceback): longest_traceback = traceback return numpy.asarray(longest_traceback)