Skip to content, Skip to search

Changes

AnalyzeSkeleton

3,979 bytes added, 24 January
Use HTTPS links where feasible
{{Infobox| software = Fiji| name = AnalyzeSkeleton| author = [[User:Iarganda | Ignacio Arganda-Carreras]]| maintainer = [[UserComponentStats:Iarganda | Ignacio Arganda-Carreras]]| filename = {{Maven | g=sc.fiji | a=:AnalyzeSkeleton_}}| source = {{GitHub|org=fiji|repo=AnalyzeSkeleton}}| released = November 14<sup>th</sup>, 2008| latest version = 2.0.4, March 10<sup>th</sup>, 2015| status = stable, active| category = [[:Category:Skeleton|Skeleton]], [[:Category:Analysis|Analysis]]}}Analysis of 2D and 3D skeleton images. For the ImageJ 1.x plugin, visit see [http://imagejdocu.tudor.lu/doku.php?id=plugin:analysis:analyzeskeleton:start AnalyzeSkeleton at ImageJ wikithis page].
{|
== General Description ==
[[Image:Tagging_example.png|thumb|292px|Example of voxel classification]]
This plugin tags all pixel/voxels in a skeleton image and then counts all its junctions, triple and quadruple points and branches, and measures their average and maximum length. The tags are shown in a new window displaying every tag in a different color. You can find it under ''Plugins {{arrow}} bc | Analyze | Skeleton {{arrow}} | Analyze Skeleton (2D/3D)''}}. See [[Skeletonize3D]] for an example of how to produce skeleton images.
The voxels are classified into three different categories depending on their 26 neighbors:
* '''Prune any branch that ends in an end-point''' (by checking "Prune ends"), as implemented by [http://doube.org/ Michael Doube] in [http://bonej.org/ BoneJ].
**In this case, if a ROI was selected in the input image, another option is enabled: ''Exclude ROI from pruning''. If selected, pruning will not be applied to end-points contained by the ROI. An application of this feature is described in [[Strahler#Root_Detection|Strahler Analysis]].
* '''Calculate the largest shortest path''' of each skeleton using the [http[wikipedia://en.wikipedia.org/wiki/Floyd-Warshall_algorithm Warshall algorithm|APSP (all pairs shortest path)]]. In this case, the shortest path will be displayed in a new window containing the skeleton in white and the shortest path in '''magenta'''. Implemented by Huub Hovens.
* '''Show detailed info''' about the branches of each skeleton in the image.
* '''Display labeled skeletons'''. An extra output image will be displayed containing each skeleton labeled with its corresponding skeleton ID.
* '''lowest intensity branch''': the darkest (in average) branch among the loop branches will be cut in its darkest voxel.
For the two last methods, another dialog will pop up asking the user to select the original (gray-scale) image among the open images in order to perform the intensity calculations.
The cycle detection is based on a classical [http[wikipedia://en.wikipedia.org/wiki/Depth-first_search first search|'''Depth-First Search''']] (DFS) in the skeleton. The skeleton is treated as an [http[wikipedia://en.wikipedia.org/wiki/Undirected_graphUndirected graph#Undirected_graph |undirected graph]], where the end-points and junctions are the nodes and the slab-branches are the edges. While traversing the graph in the DFS fashion, the edges/branches pointing to unvisited nodes are marked as '''TREE''' edges, while the edges to visited nodes are marked as '''BACK''' edges, which involves the presence of a loop. After the edge classification, the BACK edges are backtracked following their predecessors in order to calculate all the edges belonging to each cycle and proceed with the pruning.
The only known limitation of this approach is shown in the presence of nested loops. In those cases, a second call to the plugin is usually enough to eliminate all the remaining loops.
* calibrated branch length,
* 3D coordinates of the extremes of the branch (the so-called V1 and V2 vertices),
* and the Euclidean distance between those extreme points. This value has proven to be a good indicator of the [http[wikipedia://en.wikipedia.org/wiki/Tortuosity |tortuosity]] of the 3D object.
The branches are sorted by decreasing length.
|}
== Scripting AnalyzeSkeleton ==AnalyzeSkeleton functionalities can also be called from scripts, making use of its library methods or performing the whole analysis in silent mode. === Using silent mode from scripts ===
You can use AnalyzeSkeleton from scripts without displaying any of the results. That's useful if you want to use the results within the script without the user being annoyed by a lot of results tables popping up.
<source lang="javascript">
importPackage(Packages.ij);
importPackage(Packages.skeleton_analysissc.fiji.analyzeSkeleton);
// Takes a binary image as input
IJ.log(totalLength);
IJ.log(cumulativeLengthOfShortestPaths);
</source>
 
=== Pruning branches by length ===
The following [[Beanshell]] script prunes the branches of an input skeleton if they are under a certain length:
 
<source lang=java>
// @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" );
</source>
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 remove all unwanted branches.
 
=== Visualizing the skeleton in the 3D viewer ===
The following [[Beanshell]] script shows the voxel classification of the skeleton in the 3D viewer:
 
<source lang=java>
// @ImagePlus(label="Skeleton image", description="Binary image skeletonized with Skeletonize3D") image
import sc.fiji.analyzeSkeleton.AnalyzeSkeleton_;
import sc.fiji.analyzeSkeleton.Edge;
import sc.fiji.analyzeSkeleton.Point;
import ij.IJ;
import ij3d.Image3DUniverse;
import org.scijava.vecmath.Point3f;
import org.scijava.vecmath.Color3f;
// analyze skeleton
skel = new AnalyzeSkeleton_();
skel.setup("", image);
skelResult = skel.run(AnalyzeSkeleton_.NONE, false, false, null, true, false);
// get calibration
pixelWidth = image.getCalibration().pixelWidth;
pixelHeight = image.getCalibration().pixelHeight;
pixelDepth = image.getCalibration().pixelDepth;
// get graphs (one per skeleton in the image)
graph = skelResult.getGraph();
 
// create 3d universe
univ = new Image3DUniverse();
univ.show();
 
// list of end-points
endPoints = skelResult.getListOfEndPoints();
// store their positions in a list
endPointList = new ArrayList();
for( Point p : endPoints )
endPointList.add( new Point3f(
(float)( p.x * pixelDepth ),
(float)( p.y * pixelHeight ),
(float)( p.z * pixelDepth ) ) );
// add end-points to the universe as blue spheres
univ.addIcospheres( endPointList, new Color3f( Color.BLUE ), 2, 1f, "End-points");
 
// list of junction voxels
junctions = skelResult.getListOfJunctionVoxels();
// store their positions in a list
junctionList = new ArrayList();
for( Point p : junctions )
junctionList.add( new Point3f(
(float)( p.x * pixelDepth ),
(float)( p.y * pixelHeight ),
(float)( p.z * pixelDepth ) ) );
// add junction voxels to the universe as magenta spheres
univ.addIcospheres( junctionList, new Color3f( Color.MAGENTA ), 2, 1f, "Junctions");
 
for( i = 0 ; i < graph.length; i++ )
{
listEdges = graph[i].getEdges();
// go through all branches and add slab voxels
// as orange lines in the 3D universe
j=0;
for( Edge e : listEdges )
{
branchPointList = new ArrayList();
for( Point p : e.getSlabs() )
branchPointList.add( new Point3f(
(float)( p.x * pixelDepth ),
(float)( p.y * pixelHeight ),
(float)( p.z * pixelDepth ) ) );
// add slab voxels to the universe as orange lines
univ.addLineMesh( branchPointList, new Color3f( Color.ORANGE ), "Branch-"+i+"-"+j, true );
j++;
}
}
</source>
The latest documentation of the code can be found here:
[http://fijijavadoc.imagej.net/Fiji/sc/javadocfiji/skeleton_analysisanalyzeSkeleton/package-summary.html http://fijijavadoc.imagej.net/Fiji/sc/javadocfiji/skeleton_analysisanalyzeSkeleton/package-summary.html]
== Changelog ==
All changes can be seen in the [httphttps://fijigithub.sccom/cgi-binfiji/gitweb.cgi?p=fiji.git;a=history;f=src-pluginsAnalyzeSkeleton/AnalyzeSkeleton_commits/skeleton_analysis;hb=HEAD Fiji master GitHub source repository].
'''2010/12/28''': Jan Eglinger added code to call the plugin from script in silent mode.
* G. Polder, H.L.E Hovens and A.J Zweers, Measuring shoot length of submerged aquatic plants using graph analysis (2010), In: Proceedings of the ImageJ User and Developer Conference, Centre de Recherche Public Henri Tudor, Luxembourg, 27-29 October, pp 172-177.
[[AnalyzeSkeleton]] makes also part of [http://bonej.org/ BoneJ], a plugin for bone image analysis in [httphttps://imagej.net/ ImageJ]:
* Michael Doube, Michal M. Klosowski, Ignacio Arganda-Carreras, Fabrice P. Cordelieres, Robert P. Dougherty, Jonathan S. Jackson, Benjamin Schmid, John R. Hutchinson, Sandra J. Shefelbine, [http://dx.doi.org/10.1016/j.bone.2010.08.023 BoneJ: Free and extensible bone image analysis in ImageJ], Bone, Volume 47, Issue 6, December 2010, Pages 1076-1079.
[[Category:Skeleton]]
[[Category:Analysis]]
[[Category:Neuroanatomy]]
[[Category:Citable]]
Bureaucrat, emailconfirmed, incoming, administrator, uploaders
12,247
edits