Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Image - Finding largest branch from image skeleton

I have a skeletonized image in the following shape: enter image description here

And I want to extract the "largest branch" from the skeleton: enter image description here

I know that maybe I need to extract the junction point and divide de lines from that point(?), but I have no clue how to do that.

Is there any way to do that with Python Scikit Image or OpenCV?

like image 246
Rodrigo Ce Moretto Avatar asked Nov 26 '25 23:11

Rodrigo Ce Moretto


2 Answers

There is an awesome python package for analyzing skeletons with python called FilFinder ($pip install fil_finder) which solves this problem elegantly. Below is a code adopted from their tutorial.

Generate the skeleton:

import numpy as np
import cv2
import matplotlib.pyplot as plt
from fil_finder import FilFinder2D
import astropy.units as u

skeleton = cv2.imread("./data/XmviQ.png", 0) #in numpy array format

fil = FilFinder2D(skeleton, distance=250 * u.pc, mask=skeleton)
fil.preprocess_image(flatten_percent=85)
fil.create_mask(border_masking=True, verbose=False,
use_existing_mask=True)
fil.medskel(verbose=False)
fil.analyze_skeletons(branch_thresh=40* u.pix, skel_thresh=10 * u.pix, prune_criteria='length')

# Show the longest path
plt.imshow(fil.skeleton, cmap='gray')
plt.contour(fil.skeleton_longpath, colors='r')
plt.axis('off')
plt.show()

Output:

Longest path

In your problem, you're not interested in the longest path along the graph corresponding to the skeleton, but the path of the longest branch. Continuing from the above code block, the below script would do the trick. I added the dataframes to visualize that FilFinder automatically generates a lot of interesting information about the skeleton.

import pandas as pd
plt.imshow(fil.skeleton, cmap='gray')

# this also works for multiple filaments/skeletons in the image: here only one
for idx, filament in enumerate(fil.filaments): 

    data = filament.branch_properties.copy()
    data_df = pd.DataFrame(data)
    data_df['offset_pixels'] = data_df['pixels'].apply(lambda x: x+filament.pixel_extents[0])

    print(f"Filament: {idx}")
    display(data_df.head())

    longest_branch_idx = data_df.length.idxmax()
    longest_branch_pix = data_df.offset_pixels.iloc[longest_branch_idx]

    y,x = longest_branch_pix[:,0],longest_branch_pix[:,1]

    plt.scatter(x,y , color='r')

plt.axis('off')
plt.show()

Output:

Longest branch

like image 115
mjkvaak Avatar answered Nov 28 '25 14:11

mjkvaak


I believe you can use OpenCV to do the following:

  1. Use HarrisCorner to detect all corners in the image. This will get you the shown three green points (I drew a whole circle to highlight the location).

enter image description here

  1. Add a black pixel at all corners

  2. Get all branches in the picture using findContours. Then check the length of each contour using arcLength and get the longest.

like image 25
Sameh Yassin Avatar answered Nov 28 '25 16:11

Sameh Yassin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!