Exemplo n.º 1
0
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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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]
Exemplo n.º 5
0
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)