Class SkeletonPixelClassifier
- Direct Known Subclasses:
ApertureBasedSkeletonPixelClassifier
Classifier of pixels of skeletons (bit matrices, generated by skeletonization algorithms),
separating them into "nodes", "branch pixels" and other groups.
This class can be used together with SkeletonScanner
class,
providing a full solution of analysing the structure of a skeleton.
Note, that every type of skeletonization algorithm, generally speaking, requires a specific
pixel classifier, which "knows" all pixel configuration, that can appear in the results of that algorithm.
The class BasicSkeletonPixelClassifier2D
offers ready pixel classifiers for
OctupleThinningSkeleton2D
, Quadruple3x5ThinningSkeleton2D
and
StrongQuadruple3x5ThinningSkeleton2D
algorithms.
Pixel types
The main purpose of this class is detecting the type of each skeleton pixel: is it a node, a branch pixel, an isolated pixel, or, maybe, an "illegal" pixel which cannot appear in a correct skeleton. More precisely:
- we call a pixel (a unit element of the skeleton matrix)
usual branch pixel
, if this element of the skeleton has strictly 2 unit neighbour elements; - we call a pixel
free branch end
, if this element of the skeleton has strictly 1 unit neighbour element; - we call a pixel
isolated
, if this element of the skeleton has no neighbour elements; - we call a pixel "
illegal
", if analysis of some close neighbourhood of this pixel (usually 3x3 or 5x5) allows to conclude, that this pixel cannot belong to a skeleton of the concrete analysed kind; - in other cases, i.e. if a unit pixel has k≥3 neighbours
and is not "illegal", we call it either
node
, or anattachable branch end
. The concrete implementation of this abstract class defines, which of such pixels are considered to be nodes, and which are considered to be attachable branch ends. For each attachable branch end E, this class also detects two from its k neighbours with special roles:- the 1st of them, A, is always
node
and is called "attached node" (so there is a guarantee that an attachable branch end is always have a node among neighbours), - the 2nd, B, is called "an element of attaching branch" and it is:
— either really a branch pixel:usual
,free end
orattachable
(that means: this branch is "extended" with this attachable pixel E to achieve the node A),
— or anothernode
(that means: we have 1-pixel branch A–E–B, connecting nodes A and B).
- the 1st of them, A, is always
- the last possible case is trivial:
zero
element of the skeleton matrix.
Nodes, branches, degenerated branches
As a result of detecting pixel types, this class separates all unit pixels of the correct skeleton,
generated by some skeletonization algorithm (and, so, not containing "illegal
" pixels),
into the following categories:
nodes
, detected in the 5th group above,- branches, consisting of
usual branch pixels
,free branch ends
andattachable branch ends
, - and also
isolated pixels
: a special case, that can be considered as a special kind of nodes without incident branches.
If two nodes
or free branch ends
are neighbours
(in straight-and-diagonal connectivity terms, see below),
then they may be considered to be connected with a degenerated branch, consisting of 0 pixels.
If at least one of them is a free branch end
,
then we always consider them to be connected with a degenerated branch.
If both are nodes
, then the decision, whether these neighbouring nodes
are connected with a degenerated branch, is made by
markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[])
method;
it is used in SkeletonScanner.adjacentBranches()
method.
About the nonoriented graph, formed by the skeleton
This class guarantees that if the skeleton is correct (contains no "illegal" pixels),
then the nodes and branches form a correct skeleton nonoriented graph,
with skeleton nodes
, free branch ends
and
isolated pixels
in a role of graph nodes,
and skeleton branches (excluding free branch ends) in a role of graph edges.
"Correct" graph means that:
- each connected component of the skeleton (bit matrix) corresponds to a connected component of this graph;
- any branch is a connected series of 0, 1 or more unit pixels, connecting strictly 2 different
nodes
orfree branch ends
(playing the role of graph nodes: ends of the corresponding graph edge). For nondegenerate branches (containing at least 1 pixel between ending nodes or free branch ends), all their pixels belong to "usual branch pixels
" type (strictly 2 unit neighbours) or "attachable branch end
" type (having 3 or more unit neighbours), and only the first and the last among them can be attachable ends. If the first or the last pixel, really, is an attachable end, then it is considered that the attached node A, defined above in the description of group 5 of pixel types, plays the role of the corresponding graph node, incident with the given branch/edge. The pixel B (see the description of group 5) plays the role of the second graph node, incident with the given branch/edge, if it is anode
or afree branch end
: it means that we have 1-pixel branch; - there is the only possible exception from the rules I and II: if a skeleton contains cyclic branches,
i.e. connected components consisting of usual branch pixels only (thin 1-pixel closed lines, where every pixel
has strictly 2 unit neighbours), then such branches do not connect any nodes and
do not form any elements of the graph (
SkeletonScanner
class recognizes such branches separately); - nodes of the graph have 0, 1 or ≥3 incident edges, but never have 2 incident edges.
See more detailed and formal definition of the nonoriented graph, formed by the skeleton, in the comments
to SkeletonScanner
class.
Base functions of this class
One instance of this class can process different skeletons (bit matrices), but all they
must have the fixed number of dimensions, returned by dimCount()
method.
The main method of this class is
asPixelTypes(Matrix, SkeletonPixelClassifier.AttachmentInformation)
,
which performs classification of pixels of the given skeleton matrix. The second important method of this class is
markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[])
,
which allows to decide, whether two neighbouring nodes should be considered as connected with a degenerated
0-pixel branch. (It is the only situation, when the results of asPixelTypes
are
not enough to recognize, whether two nodes of skeleton nonoriented graph should be connected with an edge.)
This class also provides neighbourOffset(int)
method, which specifies
some order of the dimCount()
,
of each matrix element and is necessary for interpretation of non-negative values, returned by
asPixelTypes
method.
Connectivity model (straight-and-diagonal) and "neighbour" term
Note that this class, as well as SkeletonScanner
, supposes
the straight-and-diagonal connectivity kind: see
ConnectivityType.STRAIGHT_AND_DIAGONAL
. It means, that all skeletons
are supposed to be connected in terms of this connectivity: every connected component of the skeleton matrix
is a "carcass" or "skeleton" of some connected component of the original matrix, for which this skeleton
was built.
So, the term "neighbour" of some pixel (matrix element) in this class
and in SkeletonScanner
always means another pixel (matrix element), so that
max (|ik−jk|)=1
where
Example of results
Below is a simple example of 2-dimensional skeleton, the pixels of which are classified by this class into nodes (N), usual branch pixels (b), free branch ends (E), attachable branch ends (a) and isolated pixels (I):
. . . . . . . . . . . . . . . . . . . . . . . E . . . . . . . . . . . . E . . . b . . E . . I . E E . . . . b a N . . b . . . . . . . . . . . . . a . . a . b E . . . I . . . . . . . b a N N . . . . . . . . . . . . . . . a . . . . E . . . . . b b . . . . b . . . . b . . . . b . . b . . E . . . . . E . . . . b . . . b . . . . . . . . . E . . b . . . b . . . . . . . b b . . . . b b b . . . . E b b b . . . . . . . . . . . . . . . . . . . . .
In the left bottom part you can see an example of a cyclic branch, consisting only of usual branch pixels (b).
Creating instances of this class
This class is designed for a case of any number of dimensions, though, of course, the most popular case is 2-dimensional. This package provides the following 2-dimensional full implementation of this class:
You can also extend the skeletal implementation of this class:
ApertureBasedSkeletonPixelClassifier
.
Pseudo-cyclic continuation
This class supposes that the processed matrix is infinitely pseudo-cyclically continued, as well
Matrices.asShifted
method supposes it.
You can change this behavior by appending the source matrix with zero elements
by calling Matrix.subMatrix(long[], long[], Matrix.ContinuationMode)
Matrix.ContinuationMode.ZERO_CONSTANT
.
Multithread compatibility
This class and its inheritors from this package are immutable and thread-safe: there are no ways to modify settings of the created instance.
- Author:
- Daniel Alievsky
- See Also:
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic enum
Style of interpretation of non-negative results while detecting pixel types of the skeleton. -
Field Summary
Modifier and TypeFieldDescriptionprotected final int
The number of dimensions, returned bydimCount()
method.protected final int
The number of neighbours of each matrix element, returned bynumberOfNeighbours()
method.static final int
Maximal from 2 adjacent valuesTYPE_FREE_BRANCH_END
,TYPE_USUAL_BRANCH
.static final int
Minimal from 2 adjacent valuesTYPE_FREE_BRANCH_END
,TYPE_USUAL_BRANCH
.static final int
Free branch end pixel type for a skeleton matrix.static final int
"Illegal" pixel type for a skeleton matrix.static final int
Isolated pixel type for a skeleton matrix.static final int
static final int
static final int
Usual branch pixel type for a skeleton matrix.static final int
Node pixel type for a skeleton matrix.static final int
Zero element type for a skeleton matrix. -
Constructor Summary
ModifierConstructorDescriptionprotected
SkeletonPixelClassifier
(int dimCount) Creates new instance of this class, allowing to process skeletons with the given number of dimensions. -
Method Summary
Modifier and TypeMethodDescriptionabstract Matrix<? extends PIntegerArray>
asPixelTypes
(Matrix<? extends BitArray> skeleton, SkeletonPixelClassifier.AttachmentInformation attachmentInformation) Returns an immutable view of the passed skeleton matrix, where each element is an integer, specifying the type of the corresponding pixel of the skeleton.final int
dimCount()
Returns the number of dimensions of the matrices, which can be processed by this object.static boolean
isAttachableBranchEndPixelType
(int pixelType) Returns true if this pixel type indicates an attachable branch end, i.e. a unit pixel having 3 or more unit neighbours, which this class considers to be not a node, but an ending pixel of some branch.static boolean
isBranchPixelType
(int pixelType) Returns true if this pixel type is indicates a branch element: usual (whereisUsualBranchPixelType
(pixelType) returns true), free branch end (whereisFreeBranchEndPixelType
(pixelType) returns true) or attachable branch end (whereisAttachablePixelType
(pixelType) returns true).static boolean
isFreeBranchEndPixelType
(int pixelType) Returns true if this pixel type indicates a free branch end, i.e. a unit pixel having exactly 1 unit neighbour.static boolean
isIllegalPixelType
(int pixelType) Returns true if this pixel type indicates that the pixel is a center of an impossible configuration for a correct result of the given skeletonization algorithm.static boolean
isNodeOrFreeBranchEndPixelType
(int pixelType) Returns true if this pixel type is indicates a node (isNodePixelType
(pixelType) returns true) or a free branch end (isFreeBranchEndPixelType
(pixelType) returns true).static boolean
isNodePixelType
(int pixelType) Returns true if this pixel type is indicates a node, i.e. a unit element where 3 or more thin connected 1-pixel branches meet or, as a degenerated case, an isolated pixel: a unit element having no unit neighbours.static boolean
isUsualBranchPixelType
(int pixelType) Returns true if this pixel type indicates a usual branch pixel, i.e. a unit pixel having exactly 2 unit neighbours.abstract void
markNeighbouringNodesNotConnectedViaDegeneratedBranches
(int[] pixelTypesOfAllNeighbours) final long[]
neighbourOffset
(int neighbourIndex) Returns the differences of all coordinates of the neighbour of some (central) element with the given index and the coordinates of this central element.abstract void
neighbourOffset
(long[] coordinateIncrements, int neighbourIndex) More efficient version ofneighbourOffset(int)
method, which stores the results in the passed Java array instead of creating new Java array.final int
Returns the number of neighbours of each element of a skeleton matrix, in terms of straight-and-diagonal connectivity kind.abstract int
reverseNeighbourIndex
(int neighbourIndex) Returns an index of such neighbour B of some element A of a skeleton matrix, so that the element A is the neighbour with the specified index neighbourIndex of its neighbour B.
-
Field Details
-
TYPE_USUAL_NODE
public static final int TYPE_USUAL_NODENode pixel type for a skeleton matrix. (This value can appear in the result ofasPixelTypes
method.)Such matrix element is always unit and also has ≥3 unit neighbours, but these conditions are not enough: unit element with ≥3 unit neighbours may be not only a node, but also an
attachable branch end
. Strict definition of node pixels may depend on the implementation ofasPixelTypes
method, — but it is chosen in such a way, that the nodes and branches form a correct skeleton nonoriented graph, as written in thecomments to this class
. Informally, this pixel type indicates the situation when 3 or more thin connected 1-pixel branches meet.In the nonoriented graph, formed by the skeleton, such pixel is treated as a node of the graph, where 3 or more edges meet.
Below are typical examples for 2D case:
. . . . 1 . . 1 . . 1 1 . 1 . . . 1 . . . . 1 . . or 1 1 1 1 1 . . 1 . . . . 1 . . . . 1 . . . . 1 . .
This constant is -1.
- See Also:
-
TYPE_ISOLATED
public static final int TYPE_ISOLATEDIsolated pixel type for a skeleton matrix. (This value can appear in the result ofasPixelTypes
method.)Formal definition: a matrix element is an isolated pixel if and only if this element is unit and has no unit neighbours.
In the nonoriented graph, formed by the skeleton, such pixel is treated as a special degenerated case of a node.
This situation is shown below for 2D case:
. . . . . . . . . . . . 1 . . . . . . . . . . . .
This constant is -2.
- See Also:
-
TYPE_FREE_BRANCH_END
public static final int TYPE_FREE_BRANCH_ENDFree branch end pixel type for a skeleton matrix. (This value can appear in the result ofasPixelTypes
method.)Formal definition: a matrix element is a free branch end if and only if this element is unit and has exactly 1 unit neighbour.
In the nonoriented graph, formed by the skeleton, such pixel is treated as a node of the graph, having 1 incident edge.
Below is a typical example for 2D case:
. . . . . 1 1 . . . . . 1 . . . . . . . . . . . .
This constant is -3.
- See Also:
-
TYPE_USUAL_BRANCH
public static final int TYPE_USUAL_BRANCHUsual branch pixel type for a skeleton matrix. (This value can appear in the result ofasPixelTypes
method.)Formal definition: a matrix element is a usual branch pixel if and only if this element is unit and has exactly 2 unit neighbours.
In the nonoriented graph, formed by the skeleton, such pixel is treated as an internal pixel of an edge of the graph.
Below is a typical example for 2D case:
. . . . . 1 1 . . . . . 1 1 . . . . . 1 . . . . .
This constant is -4.
- See Also:
-
TYPE_ILLEGAL
public static final int TYPE_ILLEGAL"Illegal" pixel type for a skeleton matrix. (This value can appear in the result ofasPixelTypes
method.)Strict definition of "illegal" pixels may depend on the implementation of
asPixelTypes
method, — but it is chosen in such a way, that the unit elements of a correct skeleton, built by the corresponding skeletonization algorithm (on which this implementation of this class is oriented), cannot be "illegal". Informally, this pixel type indicates an impossible configuration for a correct result of the given skeletonization algorithm, where it is impossible to decide, is it a node or an element of a branch.Below is a possible example for 2D case:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 . . . . . . . . . .
(in most skeletonization algorithms, the bottom row of unit pixels should be removed here).
This value is negative; the concrete value is undocumented and can be changed in future versions.
- See Also:
-
TYPE_ZERO
public static final int TYPE_ZEROZero element type for a skeleton matrix. (This value can appear in the result ofasPixelTypes
method.)Formal definition: any zero matrix element.
Obviously, such pixels are not used while forming the skeleton nonoriented graph.
This value is negative; the concrete value is undocumented and can be changed in future versions.
- See Also:
-
TYPE_NODE_OR_BRANCH_END_MIN
public static final int TYPE_NODE_OR_BRANCH_END_MINMinimal from 3 adjacent valuesTYPE_USUAL_NODE
,TYPE_ISOLATED
andTYPE_FREE_BRANCH_END
. This constant is -3.- See Also:
-
TYPE_NODE_OR_BRANCH_END_MAX
public static final int TYPE_NODE_OR_BRANCH_END_MAXMaximal from 3 adjacent valuesTYPE_USUAL_NODE
,TYPE_ISOLATED
andTYPE_FREE_BRANCH_END
. This constant is -1.- See Also:
-
TYPE_BRANCH_MIN
public static final int TYPE_BRANCH_MINMinimal from 2 adjacent valuesTYPE_FREE_BRANCH_END
,TYPE_USUAL_BRANCH
. This constant is -4.- See Also:
-
TYPE_BRANCH_MAX
public static final int TYPE_BRANCH_MAXMaximal from 2 adjacent valuesTYPE_FREE_BRANCH_END
,TYPE_USUAL_BRANCH
. This constant is -3.- See Also:
-
dimCount
protected final int dimCountThe number of dimensions, returned bydimCount()
method. -
numberOfNeighbours
protected final int numberOfNeighboursThe number of neighbours of each matrix element, returned bynumberOfNeighbours()
method. Equal to 3n−1, n=dimCount
(the number of elements of 3x3x...x3 hypercube without the central element).
-
-
Constructor Details
-
SkeletonPixelClassifier
protected SkeletonPixelClassifier(int dimCount) Creates new instance of this class, allowing to process skeletons with the given number of dimensions. The number of dimensions must not be greater than(int)log3(231−1)=19 : this condition provides a guarantee that the number of neighbours, returned bynumberOfNeighbours()
method, can be represented by int Java type.- Parameters:
dimCount
- the number of dimensions, which will be returned bydimCount()
method.- Throws:
IllegalArgumentException
- if dimCount ≤ 0 or if 3dimCount > Integer.MAX_VALUE=231−1.
-
-
Method Details
-
isNodePixelType
public static boolean isNodePixelType(int pixelType) Returns true if this pixel type is indicates a node, i.e. a unit element where 3 or more thin connected 1-pixel branches meet or, as a degenerated case, an isolated pixel: a unit element having no unit neighbours. Equivalent topixelType == .TYPE_USUAL_NODE
|| pixelType ==TYPE_ISOLATED
Note that all unit pixels in the skeleton, excepting
"illegal"
, are separated into 2 groups: nodes (including isolated pixels as a degenerated case), for which this method returns true, and branch pixels, for whichisBranchPixelType(int)
returns true.- Parameters:
pixelType
- pixel type: possible element of the result ofasPixelTypes
method.- Returns:
- true if this type indicates a node, including the degenerated case of an isolated pixel.
-
isUsualBranchPixelType
public static boolean isUsualBranchPixelType(int pixelType) Returns true if this pixel type indicates a usual branch pixel, i.e. a unit pixel having exactly 2 unit neighbours. Equivalent topixelType == .TYPE_USUAL_BRANCH
- Parameters:
pixelType
- pixel type: possible element of the result ofasPixelTypes
method.- Returns:
- true if this type indicates a usual (non-ending) branch pixel.
-
isFreeBranchEndPixelType
public static boolean isFreeBranchEndPixelType(int pixelType) Returns true if this pixel type indicates a free branch end, i.e. a unit pixel having exactly 1 unit neighbour. Equivalent topixelType == .TYPE_FREE_BRANCH_END
- Parameters:
pixelType
- pixel type: possible element of the result ofasPixelTypes
method.- Returns:
- true if this type indicates a free branch end.
-
isAttachableBranchEndPixelType
public static boolean isAttachableBranchEndPixelType(int pixelType) Returns true if this pixel type indicates an attachable branch end, i.e. a unit pixel having 3 or more unit neighbours, which this class considers to be not a node, but an ending pixel of some branch. Equivalent topixelType >= 0 . (The value of pixelType argument can appear in the result ofasPixelTypes
method.)Such matrix element is always unit and also has ≥3 unit neighbours, as
nodes
, but it is not considered to be a node. Strict definition of attachable branch ends may depend on the implementation ofasPixelTypes
method, — but it is chosen in such a way, that the nodes and branches form a correct skeleton nonoriented graph, as written in thecomments to this class
. Informally, this pixel type indicates an ending pixel of a thin connected 1-pixel branch, which approaches a node, when the number of neighbours of this pixel is greater than 2.In the nonoriented graph, formed by the skeleton, such pixel is treated as an internal pixel of an edge of the graph, as well as
usual branch pixels
.Below is a typical example for 2D case:
. . 1 . . . . 1 . . 1 1 1 1 1 . . 1 . . . . 1 . .
4 unit pixels near the center can be considered as attachable branch ends. All they have 4 unit neighbours, but it is clear that there is no sense to consider them as nodes — unlike the center, which also has 4 unit neighbours and is an obvious node.
Another example:
1 1 . . . 1 1 . . 1 . 1 . . . . . 1 1 . . . . . . . 1 . . . . . . . 1
The central unit pixel and its right diagonal neighbour (marked out by bold font) can be considered as attachable branch ends. They have 3 unit neighbours, but it is clear that they may be treated as end elements of the corresponding branches — unlike the true node to the right from the center (marked out by italic font).
- Parameters:
pixelType
- pixel type: possible element of the result ofasPixelTypes
method.- Returns:
- true if this type indicates an attachable branch end, i.e. if it is non-negative.
-
isNodeOrFreeBranchEndPixelType
public static boolean isNodeOrFreeBranchEndPixelType(int pixelType) Returns true if this pixel type is indicates a node (isNodePixelType
(pixelType) returns true) or a free branch end (isFreeBranchEndPixelType
(pixelType) returns true). Equivalent to
pixelType >= .TYPE_NODE_OR_BRANCH_END_MIN
&& pixelType <=TYPE_NODE_OR_BRANCH_END_MAX
Note that all such pixels (nodes and free branch ends) corresponds to nodes of a graph, describing the geometric structure of the skeleton (branches correspond to edges in that graph).
- Parameters:
pixelType
- pixel type: possible element of the result ofasPixelTypes
method.- Returns:
- true if this type indicates a node or a free branch end.
-
isBranchPixelType
public static boolean isBranchPixelType(int pixelType) Returns true if this pixel type is indicates a branch element: usual (whereisUsualBranchPixelType
(pixelType) returns true), free branch end (whereisFreeBranchEndPixelType
(pixelType) returns true) or attachable branch end (whereisAttachablePixelType
(pixelType) returns true). Equivalent to
pixelType >= 0 || (pixelType >= .TYPE_BRANCH_MIN
&& pixelType <=TYPE_BRANCH_MAX
)Note that all unit pixels in the skeleton, excepting
"illegal"
, are separated into 2 groups: nodes (including isolated pixels as a degenerated case), for whichisNodePixelType(int)
returns true, and branch pixels, for which this method returns true.- Parameters:
pixelType
- pixel type: possible element of the result ofasPixelTypes
method.- Returns:
- true if this type indicates some element of a branch.
-
isIllegalPixelType
public static boolean isIllegalPixelType(int pixelType) Returns true if this pixel type indicates that the pixel is a center of an impossible configuration for a correct result of the given skeletonization algorithm. Equivalent topixelType == .TYPE_ILLEGAL
- Parameters:
pixelType
- pixel type: possible element of the result ofasPixelTypes
method.- Returns:
- true if this type indicates an incorrect configuration of the pixel's neighbours.
-
dimCount
public final int dimCount()Returns the number of dimensions of the matrices, which can be processed by this object. InSkeletonScanner
, equivalent to .skeleton()
.dimCount()
- Returns:
- the number of dimensions of the matrices, which can be processed by this object.
-
numberOfNeighbours
public final int numberOfNeighbours()Returns the number of neighbours of each element of a skeleton matrix, in terms of straight-and-diagonal connectivity kind. Equal to 3n−1, n=dimCount()
(the number of elements of 3x3x...x3 hypercube without the central element). In particular, in 2-dimensional case this method returns 32-1=8, and in 3-dimensional case this method returns 33-1=26.- Returns:
- the number of neighbours of every element.
-
neighbourOffset
public final long[] neighbourOffset(int neighbourIndex) Returns the differences of all coordinates of the neighbour of some (central) element with the given index and the coordinates of this central element. In other words, ifi0, i1, ..., in-1 are coordinates of the some element of a skeleton matrix (n=dimCount()
), and we need to find the coordinatesj0, j1, ..., jn-1 of its neighbour #k, 0≤k<numberOfNeighbours()
, we should use the following formula:ji = ii + offset[i],
where offset is the result of calling this method with neighbourIndex=k.
The returned array is always a newly allocated Java array. Its length is always equal to
dimCount()
. Its elements will be always same while different calls of this method for the same object (implementing this class) with the same neighbourIndex argument. The elements of the returned array are always equal to -1, 0 or +1, and all they cannot be 0 simultaneously.This method defines some order of enumerating neighbours. This order can be different in different implementations. In
BasicSkeletonPixelClassifier2D
implementation, the order of neighbours is described by the following diagram:0 1 2 7 C 3 6 5 4
(the x-axis is directed rightward, the y-axis is directed downward). It means that the results of this method in
BasicSkeletonPixelClassifier2D
are the following: for neighbourIndex=0 it returns two-element array{-1,-1} , for neighbourIndex=1 it returns two-element array{0,-1} , for neighbourIndex=2 it returns two-element array{1,-1} , for neighbourIndex=3 it returns two-element array{1,0} , for neighbourIndex=4 it returns two-element array{1,1} , for neighbourIndex=5 it returns two-element array{0,1} , for neighbourIndex=6 it returns two-element array{-1,1} , for neighbourIndex=7 it returns two-element array{-1,0} . In other words,BasicSkeletonPixelClassifier2D
class enumerates the neighbours along the perimeter of 3x3 square.This method is completely implemented via
neighbourOffset(long[], int)
method.- Parameters:
neighbourIndex
- an index if the neighbour of some central element of a matrix.- Returns:
- shifts along all coordinates from the central element to this neighbour.
- Throws:
IndexOutOfBoundsException
- if neighbourIndex is out of range 0..numberOfNeighbours()
-1.- See Also:
-
neighbourOffset
public abstract void neighbourOffset(long[] coordinateIncrements, int neighbourIndex) More efficient version ofneighbourOffset(int)
method, which stores the results in the passed Java array instead of creating new Java array. This method is equivalent to calling that method and copying its result into coordinateIncrements argument, but does not allocate any arrays. It is a better solution if we need to calculate neighbour offsets in a long loop, because allows to avoid allocating a lot of short arrays.The length of the passed array must be equal to
the number of dimensions
of processed matrices.- Parameters:
coordinateIncrements
- Java array for storing the differences of all coordinates of the neighbour #neighbourIndex of some (central) element and the coordinates of this central element.neighbourIndex
- an index if the neighbour of some central element of the matrix.- Throws:
NullPointerException
- if coordinateIncrements argument is null.IllegalArgumentException
- if coordinateIncrements.length!=dimCount()
.IndexOutOfBoundsException
- if neighbourIndex is out of range 0..numberOfNeighbours()
-1.- See Also:
-
reverseNeighbourIndex
public abstract int reverseNeighbourIndex(int neighbourIndex) Returns an index of such neighbour B of some element A of a skeleton matrix, so that the element A is the neighbour with the specified index neighbourIndex of its neighbour B. Both neighbour indexes are considered in terms ofneighbourOffset(int)
method. It means, that if k1 is the argument of this method and k2 is the result of this method,offset1= andneighbourOffset
(k1)offset2= , thenneighbourOffset
(k2)offset2[i] = -offset1[i] for all i.
For example, in
BasicSkeletonPixelClassifier2D
class (which enumerates 8 neighbours along the perimeter of 3x3 square) this method returns (neighbourIndex+4)%8.- Parameters:
neighbourIndex
- an index of some neighbour B of some central element A.- Returns:
- an index of the central element A as a neighbour of the element B.
- Throws:
IndexOutOfBoundsException
- if neighbourIndex is out of range 0..numberOfNeighbours()
-1.
-
asPixelTypes
public abstract Matrix<? extends PIntegerArray> asPixelTypes(Matrix<? extends BitArray> skeleton, SkeletonPixelClassifier.AttachmentInformation attachmentInformation) Returns an immutable view of the passed skeleton matrix, where each element is an integer, specifying the type of the corresponding pixel of the skeleton. The number of dimensions of the passed matrix must be equal todimCount()
.More precisely, let's consider that skeleton matrix is the result of some skeletonization algorithm (chosen while creating an instance of this class). The resulting matrix will contain the following values:
TYPE_ZERO
, if the corresponding element of the skeleton is zero (no pixel);TYPE_ILLEGAL
, if here is an impossible configuration for a correct result of the given skeletonization algorithm (probable case, if the passed matrix is really not a skeleton);TYPE_USUAL_NODE
, if the corresponding element of the skeleton is a node, where 3 or more branches meet;TYPE_ISOLATED
, if the corresponding element of the skeleton is an isolated unit pixel, having no unit neighbour elements;TYPE_FREE_BRANCH_END
, if the corresponding element of the skeleton is an end of some branch, having 1 unit neighbour elements;TYPE_USUAL_BRANCH
, if the corresponding element of the skeleton has 2 unit neighbour elements;- some non-negative value in 0..
numberOfNeighbours()
-1 range, if the corresponding element of the skeleton has ≥3 unit neighbour elements, but this class recommends to consider this pixel not a node, but an additional"attached" element
of some branch. In this case, this value means the following:- if attachmentInformation argument is
SkeletonPixelClassifier.AttachmentInformation.NEIGHBOUR_INDEX_OF_ATTACHED_NODE
, this value specifies the direction (neighbour index) towards the neighbouring node, which is one of the ends of this branch; there is a guarantee that this neighbour is either reallynode
or, maybe,TYPE_ILLEGAL
; - if attachmentInformation argument is
SkeletonPixelClassifier.AttachmentInformation.NEIGHBOUR_INDEX_OF_ATTACHING_BRANCH
, this value specifies the direction (neighbour index) towards the branch, to which this pixel should be attached as its ending element; there is no guarantee that this neighbour is really a branch element, but it cannot bezero
orisolated
, and if it is anode
, it is supposed that we have a short branch to it, consisting of 1 pixel.
comments to SkeletonPixelClassifier
, section "Pixel types", group 5.
The direction is specified in terms ofneighbourOffset(int)
method. InBasicSkeletonPixelClassifier2D
, it can be 0,1,2,3,4,5,6,7, corresponding to the following diagram:0 1 2 7 C 3 6 5 4
(the x-axis is directed rightward, the y-axis is directed downward). Namely, if the current element has coordinates
(x,y) , then "0" value means attaching of the node with coordinates(x−1,y−1) (the case A) or attaching of the node to the branch containing the pixel(x−1,y−1) (the case B), "1" value means attaching of the node / to the branch(x,y−1) , "2" value means attaching of the node / to the branch(x+1,y−1) , "3" value means attaching of the node / to the branch(x+1,y) , "4" value means attaching of the node / to the branch(x+1,y+1) , "5" value means attaching of the node / to the branch(x,y+1) , "6" value means attaching of the node / to the branch(x−1,y+1) , "7" value means attaching of the node / to the branch(x−1,y) . - if attachmentInformation argument is
Note, that the situation, when some neighbouring elements are out of ranges of the matrix coordinates, is processed according to the model of infinite pseudo-cyclical continuation — see the end of the
comments to SkeletonPixelClassifier
.Note, that all values, specified by constants of this class (all cases 1-6 above, excepting the last case 7), are different negative integers. Then, note that
TYPE_USUAL_NODE
,TYPE_ISOLATED
andTYPE_FREE_BRANCH_END
are adjacent integers -3..-1. Then, note that two constants, corresponding to branches and their ends —TYPE_FREE_BRANCH_END
andTYPE_USUAL_BRANCH
— are also adjacent integers -4..-3. Then, note that two constants, corresponding to nodes and isolated pixels —TYPE_USUAL_NODE
andTYPE_ISOLATED
— are also adjacent integers -2..-1. This can be useful for extracting special kinds of skeleton pixels into bit matrices.- Parameters:
skeleton
- the skeleton matrix that should be processed.attachmentInformation
- what should this method return for attachable pixels.- Returns:
- the matrix of integer codes with the same sizes, describing the types of all skeleton pixels.
- Throws:
NullPointerException
- if skeleton or attachmentInformation is null.IllegalArgumentException
- if skeleton.dimCount()!=dimCount()
.
-
markNeighbouringNodesNotConnectedViaDegeneratedBranches
public abstract void markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[] pixelTypesOfAllNeighbours) Finds and marks, by assigning Integer.MIN_VALUE to corresponding elements of the passed Java array, all neighbours of somenode
, which are alsonodes
and are considered to be not connected with this node via a degenerated 0-pixel branch. Neighbouring nodes, which are considered to be connected with the central node via 0-pixel branch, stay unchanged.More precisely, this method analyses the Java array pixelTypesOfAllNeighbours, which contains the pixel types of all neighbours of some "central" pixel, which is supposed to be a
node
, in the order, defined byneighbourOffset(int)
method. This method finds among them all values, equal toTYPE_USUAL_NODE
, and, if this class considers that they should not be connected with the central node via degenerated branches, such values are replaced with Integer.MIN_VALUE (which means "removing" these neighbours from candidates to connection with the central node). So, if some elements of the passed array areTYPE_USUAL_NODE
after calling this method as before, it means that such neighbouring nodes should be considered as connected with the central node via degenerated branches.This method is used in
SkeletonScanner.adjacentBranches()
to correctly find all degenerated branches, originating in the current node.The passed array must contain at least
numberOfNeighbours()
elements. If it contains more elements, this method processes only firstnumberOfNeighbours()
elements and ignores others.In
ApertureBasedSkeletonPixelClassifier
for 2-dimensional case and, in particular, inBasicSkeletonPixelClassifier2D
, the neighbouring node Q of the central node P is not marked for removing (not replaced with Integer.MIN_VALUE), if the segment PQ is not diagonal (4-connected neighbour) or if it is diagonal, but the two adjacent pixels, which are 4-connected neighbours of both P and Q, are notnodes
:. . * . . . . . . * . . . . * . . . . . . * . . * * . * * * . . . Q * * . . P Q . . or * * P . . . . . * . * . . . * . . . . . * . . * . . * . . .
In other situations, a diagonal degenerated branch between P and Q would be extra, because they are connected via two horizontal and vertical degenerated 0-pixel branches. (InApertureBasedSkeletonPixelClassifier
class for the number of dimensions, other than 2, the implementation of this method does nothing.)- Parameters:
pixelTypesOfAllNeighbours
- an array of the pixel types of all neighbours of some given element, supposed to be anode
; this method will replace someTYPE_USUAL_NODE
values in this array with Integer.MIN_VALUE.- Throws:
NullPointerException
- if the argument is null.IllegalArgumentException
- if the length of the passed array is less thannumberOfNeighbours()
.
-