Getting line selection from longest skeleton path

line-profile
skeleton-analysis
roi
Tags: #<Tag:0x00007fb87a158968> #<Tag:0x00007fb87a158800> #<Tag:0x00007fb87a158530>

#1

I was trying to plot a profile (or, alternatively, get a straightened image) of the longest shortest path of a skeleton, but I’m having difficulties getting a poly-line selection from the skeleton.

@iarganda Is there a way to get the polygon of the longest path from AnalyzeSkeleton_ via scripting the API? I was quickly browsing the source, but didn’t find a good entry point.


I tried to get the ROI of the longest path by

  • thresholding the Longest shortest paths and the Tagged skeleton images,

  • combining the longest-path segments with the neighboring junction voxels to create a pixel line of the path, and then

  • using something like the following script to transform the area selection to a polyline selection:

    // @ImagePlus imp
    
    import ij.gui.PolygonRoi
    import java.awt.Polygon
    
    roi = imp.getRoi()
    points = roi.getContainedPoints()
    
    poly = new Polygon()
    for (p in points) {
        poly.addPoint((int)p.x, (int)p.y)    
    }
    pRoi = new PolygonRoi(poly, PolygonRoi.POLYLINE)
    
    imp.setRoi(pRoi)
    

… but this of course horribly fails because the Point array returned by getContainedPoints is ordered pixel row-wise and not by nearest distance.


I also tried Edit > Selection > Area to Line, but this gives a closed polygon surrounding the pixel line, resulting in a wrong profile of double the length (you can also see how this is wrong by doing Edit > Selection > Fit Spline).


Or maybe there is a solution to do that in Ops already? I’d be grateful for any hints.


Analyzing cell layer thickness
Re-using ImageJ scripts in KNIME
Analyzing cell layer thickness
Analyzing cell layer thickness
#2

What about getting the points using getShortestPathPoints() and then plotting their intensity values?


#3

Hm, yes, I must have somehow overlooked this. Thanks a lot! :slight_smile:


#4

Unfortunately, this doesn’t work well for plotting a profile along the whole length of the path, because the path segments don’t seem to be ordered in way that allows a continuous sampling of the path. This Groovy script illustrates the issue with a little animation:

import ij.IJ
import ij.gui.PolygonRoi
import java.awt.Polygon
import sc.fiji.analyzeSkeleton.AnalyzeSkeleton_

// Load Sample image, skeletonize, and zoom for illustration purposes
imp = IJ.openImage("http://imagej.nih.gov/ij/images/bat-cochlea-volume.zip")
IJ.run(imp, "Skeletonize (2D/3D)", "")
imp.show()
IJ.run("Set... ", "zoom=400 x=60 y=77")
imp.setSlice(50)

// Initialize AnalyzeSkeleton_
skel = new AnalyzeSkeleton_()
skel.calculateShortestPath = true
skel.setup("", imp)
 
// Perform analysis in silent mode
skelResult = skel.run(AnalyzeSkeleton_.NONE, false, true, null, true, false)

// Read the results
shortestPaths = skelResult.getShortestPathList().toArray()
sppoints = skel.getShortestPathPoints()

poly = new Polygon()
for (p in sppoints[0]) {
    poly.addPoint((int)p.x, (int)p.y)
    imp.setRoi(new PolygonRoi(poly, PolygonRoi.POLYLINE))
    IJ.wait(20)    
}

pRoi = new PolygonRoi(poly, PolygonRoi.POLYLINE)
imp.setRoi(pRoi)

Any idea how to get the segments into the correct order to avoid any “jumps”?


Edit: here’s a simpler, 2D example animation illustrating the issue:

(created using this script)


#5

I see. That part of the code was written by Huub Hovens but I’ll dig into it to see if I find a solution. So far you can simply start from the first point and check iteratively the neighbor that is in the list, so you visit the path in order. I can actually add that as a post-processing of the shortest path method…

Nice animation by the way :wink:


#6

OK, I think I have fixed it with this commit.

@imagejan can you please test it? If you are happy with it, I’ll make a new release.


#7

Wow, you’re fast! I just built (mvn -Djavadoc.skip because maven-javadoc-plugin complains) and tested it, and it works great:

Thank you so much, @iarganda!