Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignoring looped filaments #64

Open
researcherys opened this issue Feb 8, 2021 · 1 comment
Open

Ignoring looped filaments #64

researcherys opened this issue Feb 8, 2021 · 1 comment

Comments

@researcherys
Copy link

researcherys commented Feb 8, 2021

There are 2 kinds of problems with looped filaments introduced in filfinder2D:

  1. Looped filament without any end gives: UnboundLocalError: local variable 'max_path_length' referenced before assignment;
  2. Looped filament with any end attached, even insignificant by length(at figure), is ignored, when providing longest path: the longest path of the insignificant branch is provided instead of longer looped filbranch.
    Prob2

How to avoid losing information contained with loops when, e.g., extracting longest paths?

OS: Linux, Ubuntu 18.04
Environment: Pycharm 2020.3.3
PlantCV Version 3.11.0]

@gt8mar
Copy link

gt8mar commented Aug 28, 2023

I'm working on this currently. To deal with the first max_path_length error resulting from looped filaments, I added a check before running "analyze_skeletons":

# define two functions to identify junctions and endpoints:

def find_junctions(skel):
    """Finds pixels with exactly three neighbors."""
    kernel = np.array([
        [1, 1, 1],
        [1, 10, 1],
        [1, 1, 1]
    ])

    neighbors_count = convolve(skel.astype(int), kernel, mode='constant', cval=0)
    return (neighbors_count - 10 == 3) & skel

def find_endpoints(skel):
    # Define a kernel that counts the number of neighbors
    kernel = np.array([
        [1, 1, 1],
        [1, 10, 1],
        [1, 1, 1]
    ])

    neighbors_count = convolve(skel.astype(int), kernel, mode='constant', cval=0)
    # Endpoints are skeleton points with only one neighbor
    return (neighbors_count == 11) & skel

def make_skeletons(binary_image):
    """
    This function uses the FilFinder package to find and prune skeletons of images.
    Args:
        image: 2D numpy array or list of points that make up polygon mask
    Returns:
        skeleton: 2D numpy array with skeletons
        skeleton_longpath: 2D numpy array with skeletons that have been pruned to a single line
    """
   
    # Load in skeleton class for skeleton pruning
    fil = FilFinder2D(binary_image, beamwidth=0 * u.pix, mask=binary_image)
    
    # This is a necessary step for the fil object. It does nothing.
    fil.preprocess_image(skip_flatten=True)

    # This makes the skeleton
    fil.medskel(verbose=False)

    # find junctions and endpoints
    junctions = np.asarray(np.nonzero(find_junctions(fil.skeleton))).shape[1]
    endpoints = np.asarray(np.nonzero(find_endpoints(fil.skeleton))).shape[1]
    print(f'Number of junctions is {junctions}')
    print(f'Number of endpoints is {endpoints}')
    print('-----------------------------------------------')

    if junctions == 0 and endpoints == 0:
        return fil.skeleton, fil.skeleton
    else:    
        # This prunes the skeleton
        fil.analyze_skeletons(branch_thresh=BRANCH_THRESH * u.pix, prune_criteria='length',
                            skel_thresh=MIN_CAP_LEN * u.pix)    
        return fil.skeleton, fil.skeleton_longpath

A circle with have zero endpoints and zero junctions, so if I don't find them then I don't run the pruning algorithm and just return the circle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants