AnalyzeSkeleton GUI prune by length

plugin
Tags: #<Tag:0x00007fa30b0fbd28>

#1

Hello All,

In reading through various threads about this plugin (v 3.1.1 installed with FIJI) it looks like there is a way to prune short branches using a length threshold via scripting that doesn’t appear in the GUI. If this is correct, is there a straightforward way to implement this for someone (like me) who doesn’t know much programming? As an aside, it also seems that when Elimination of end-points is selected, the pruned branches are still included in the summary stats (except the number of triple and quadruple points… these change) but are removed from the detailed information (the number of rows per skeleton ID is much less than the # branches listed in the summary). I’m not sure if that is a bug but it threw me off a bit at first.

Thanks for the great plugin and assistance!


#2

Hello @NCramer and welcome to the ImageJ forum!

Not really straightforward. You would have to write a script that takes the result from AnalyzeSkeleton and re-visits the skeletons from the end-points to eliminate the branches under that length. I can try to find time the next few weeks to write such a script if you can’t.

That is somehow intended. The first analysis is performed over the unpruned skeleton to detect end-points, which are then eliminated and then the second analysis is performed.

PS: I have just found this toolkit that might be doing already what you want. But I haven’t tried it.


#3

OK, that was faster than I thought. Here you are the script in Beanshell:

// @ImagePlus(label="Skeleton image", description="Binary image skeletonized with Skeletonize3D") image
// @double(label="Length threshold", description="Minimum branch length to keep") threshold
// @OUTPUT ImagePlus prunedImage

import sc.fiji.analyzeSkeleton.AnalyzeSkeleton_;
import sc.fiji.analyzeSkeleton.Edge;
import sc.fiji.analyzeSkeleton.Point;
import ij.IJ;

// analyze skeleton
skel = new AnalyzeSkeleton_();
skel.setup("", image);
skelResult = skel.run(AnalyzeSkeleton_.NONE, false, false, null, true, false);

// create copy of input image
prunedImage = image.duplicate();
outStack = prunedImage.getStack();

// get graphs (one per skeleton in the image)
graph = skelResult.getGraph();

// list of end-points
endPoints = skelResult.getListOfEndPoints();

for( i = 0 ; i < graph.length; i++ )
{
	listEdges = graph[i].getEdges();

	// go through all branches and remove branches under threshold
	// in duplicate image
	for( Edge e : listEdges )
	{
		p = e.getV1().getPoints();
		v1End = endPoints.contains( p.get(0) );
		p2 = e.getV2().getPoints();
		v2End = endPoints.contains( p2.get(0) );
		// if any of the vertices is end-point 
		if( v1End || v2End )
		{
			if( e.getLength() < threshold )
			{
				if( v1End )
					outStack.setVoxel( p.get(0).x, p.get(0).y, p.get(0).z, 0 );
				if( v2End )
					outStack.setVoxel( p2.get(0).x, p2.get(0).y, p2.get(0).z, 0 );
				for( Point p : e.getSlabs() )
					outStack.setVoxel( p.x, p.y, p.z, 0 );
			}
		}
	}
}

prunedImage.setTitle( image.getShortTitle() + "-pruned" );

Be aware that small branches might be created due to the elimination of end-points and slabs but not junctions (to prevent breaking branches above the threshold). So you might need to run the script a couple of times to get the result you want.


Skeletonize Remove or Prune short end segments
#4

Thank you, iarganda! I’ve been wrestling with very large 3D skeletons which has made things complicated. I tried running the script you wrote (opening a new script editor window, pasting the code, toggling the language selection to JavaScript and running the script with my 3D skeleton stack selected). The window to select the cut off opens and the script seems to run but no results appear at completion (the script window says “busy” for awhile then stops). In the error window I get the following message:

jdk.nashorn.internal.runtime.ParserException: New_.js:6:0 Expected an operand but found import
import sc.fiji.analyzeSkeleton.AnalyzeSkeleton_;

I am running FIJI (recently reinstalled within the past month) that shows ImageJ 1.51i and Java 1.8.0_66 (64-bit).

I see in other threads (particularly on BoneJ) that different Java versions can cause difficulties… Am I running into a similar problem?

Thanks again!


#5

Sorry, I forgot to mention this is a Beanshell script, not Javascript. Just change the language definition to Beanshell and it should work. I will edit my previous post.


#6

That did it! Thank you again… I really appreciate your help!


#7

Hi,
I have created a skeleton from an image I am analyzing, but I need to be able to prune the extra “hair like” structures hanging off of my skeleton. I have tried using Analyze Skeleton(2D/3D), but it does not prune enough. I really need to be able to prune up to a certain length.

I have also tried running the above code made by @iarganda , but I can’t seem to figure it out.

Please Help!

Also, I am using ImageJ not FIJI.


#8

Do you mean how to run the script? Open it in the Script Editor and click on run :wink:


#9

In imageJ (Not FIJI) I am pulling up a macro record tool and pasting the code there. I will then attempt to create the macro, and an error message pops up saying there are unidentified arguments. I was able to make it work in FIJI, but I really need it to work in regular imageJ because that is what my lab uses.

@iarganda


#10

You need to use the Script Editor, which is included in the latest distribution of ImageJ as well if you download it from imagej.net. If your lab uses the ImageJ version downloaded from NIH, you might need to install the Beanshell Interpreter.


#11

Hi
(sorry for my english, i speak french)
I use that script and I want to saveAs and selected the window (-pruned) for %area mesure but it show me an error.

run(“Pruning “, “threshold=5.0”);
selectWindow(“3-pruned”);
saveAs(“PNG”, dir+title+”_SQLT.png”);

the code bloc at selectwindow and at saveAs if i remove selectwindow.
I check the name of the result image and it was the same.
I pass by the recorder and copy the sequence and the same error occure again…
Please help me

Thanks!


#12

Hello @Melissa_Roy_Tremblay,

Can you post here the error you get, please?


#13

its working now, i dont know why but i have to “make Binary” after runing the script, and now the macro see the window.

Here is the code (sorry for the comments in french):

run(“Robust Automatic Threshold Selection”, “noise=10 lambda=3 min=302”); //sépare les fissures du fond
run(“Remove Outliers…”, “radius=1 threshold=50 which=Bright”); //enlève les picots blancs
setOption(“BlackBackground”, false);
run(“Make Binary”);
run(“Dilate”); run(“Dilate”); run(“Erode”);
run(“Dilate”); run(“Erode”); run(“Dilate”);
run(“Skeletonize”);//ramene les fissures à 1 pxl d’épaisseur
run(“Particle Remover”, “size=0.00-1.00 circularity=0.09-1.00 add”); //retire les particules non circulaire de 0 à 6 mm
run(“Pruning “, “threshold=1.0”);//ébarbule les branches du skelette
run(“Make Binary”);
run(“Particle Remover”, “size=0-0.50 circularity=0.09-1.00 add”);//retire les poussières restantes
run(“Invert”);
run(“Invert LUT”);
run(“Morphological Filters”, “operation=Erosion element=Disk radius=1”);
showText(“Processing”, “Please wait…\nThe cracks will be traced with \nthe Ridge Detection plugins”);
run(“Ridge Detection”, “line_width=3.5 high_contrast=255 low_contrast=87 darkline correct_position extend_line displayresults make_binary method_for_overlap_resolution=NONE sigma=1.51 lower_threshold=0.85 upper_threshold=5.78 minimum_line_length=3 maximum=0”);
selectWindow(“Processing”);
run(“Close”);
selectWindow(“3-mask2_pruned-Erosion”);
run(“Flatten”);
saveAs(“PNG”, dir+title+”_RD3.png”);


#14

Hello @Melissa_Roy_Tremblay,

Wasn’t the input image already binary? The input to the skeletonization plugins must be binary.


#15

Yeah, the input image is binary and the output looks like it but no erosion-dilation work if i dont make the image binary again, i dunno why


#16

Do you mean MorphoLibJ’s erosion and dilation filters? Those should work even with grayscale images.