public abstract class SkeletonPixelClassifier
extends java.lang.Object
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.
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:
usual branch pixel
, if this element
of the skeleton has strictly 2 unit neighbour elements;free branch end
,
if this element of the skeleton has strictly 1 unit neighbour element;isolated
, if this element
of the skeleton has no neighbour elements;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;node
, or an
attachable 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:
node
and is called "attached node"
(so there is a guarantee that an attachable branch end is always have a node among neighbours),usual
,
free end
or attachable
(that means: this branch is "extended" with this attachable pixel E to achieve the node A),node
(that means:
we have 1pixel branch A–E–B, connecting nodes A and B).zero
element of the skeleton matrix.
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,usual branch pixels
,
free branch ends
and
attachable branch ends
,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 straightanddiagonal 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.
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:
nodes
or free 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 a node
or
a free branch end
: it means that we have 1pixel branch;SkeletonScanner
class recognizes
such branches separately);See more detailed and formal definition of the nonoriented graph, formed by the skeleton, in the comments
to SkeletonScanner
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
0pixel 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 nonnegative values, returned by
asPixelTypes
method.
Note that this class, as well as SkeletonScanner
, supposes
the straightanddiagonal 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 (i_{k}−j_{k})=1
where
Below is a simple example of 2dimensional 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).
This class is designed for a case of any number of dimensions, though, of course, the most popular case is 2dimensional. This package provides the following 2dimensional full implementation of this class:
You can also extend the skeletal implementation of this class:
ApertureBasedSkeletonPixelClassifier
.
This class supposes that the processed matrix is infinitely pseudocyclically 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
.
This class and its inheritors from this package are immutable and threadsafe: there are no ways to modify settings of the created instance.
AlgART Laboratory 2007–2014
SkeletonScanner
Modifier and Type  Class and Description 

static class 
SkeletonPixelClassifier.AttachmentInformation
Style of interpretation of nonnegative results while detecting pixel types of the skeleton.

Modifier and Type  Field and Description 

protected int 
dimCount
The number of dimensions, returned by
dimCount() method. 
protected int 
numberOfNeighbours
The number of neighbours of each matrix element, returned by
numberOfNeighbours() method. 
static int 
TYPE_BRANCH_MAX
Maximal from 2 adjacent values
TYPE_FREE_BRANCH_END , TYPE_USUAL_BRANCH . 
static int 
TYPE_BRANCH_MIN
Minimal from 2 adjacent values
TYPE_FREE_BRANCH_END , TYPE_USUAL_BRANCH . 
static int 
TYPE_FREE_BRANCH_END
Free branch end pixel type for a skeleton matrix.

static int 
TYPE_ILLEGAL
"Illegal" pixel type for a skeleton matrix.

static int 
TYPE_ISOLATED
Isolated pixel type for a skeleton matrix.

static int 
TYPE_NODE_OR_BRANCH_END_MAX

static int 
TYPE_NODE_OR_BRANCH_END_MIN

static int 
TYPE_USUAL_BRANCH
Usual branch pixel type for a skeleton matrix.

static int 
TYPE_USUAL_NODE
Node pixel type for a skeleton matrix.

static int 
TYPE_ZERO
Zero element type for a skeleton matrix.

Modifier  Constructor and Description 

protected 
SkeletonPixelClassifier(int dimCount)
Creates new instance of this class, allowing to process skeletons with the given number of dimensions.

Modifier and Type  Method and Description 

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.

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
(where
isUsualBranchPixelType (pixelType)
returns true), free branch end
(where isFreeBranchEndPixelType (pixelType)
returns true) or attachable branch end
(where isAttachablePixelType (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 1pixel 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)

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 of
neighbourOffset(int) method,
which stores the results in the passed Java array instead of creating new Java array. 
int 
numberOfNeighbours()
Returns the number of neighbours of each element of a skeleton matrix, in terms
of straightanddiagonal 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.

public static final int TYPE_USUAL_NODE
asPixelTypes
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 of asPixelTypes
method,
— but it is chosen in such a way, that the nodes and branches form a correct skeleton nonoriented graph,
as written in the comments to this class
.
Informally, this pixel type indicates the situation
when 3 or more thin connected 1pixel 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.
public static final int TYPE_ISOLATED
asPixelTypes
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.
public static final int TYPE_FREE_BRANCH_END
asPixelTypes
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.
public static final int TYPE_USUAL_BRANCH
asPixelTypes
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.
public static final int TYPE_ILLEGAL
asPixelTypes
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.
public static final int TYPE_ZERO
asPixelTypes
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.
public static final int TYPE_NODE_OR_BRANCH_END_MIN
TYPE_USUAL_NODE
, TYPE_ISOLATED
and TYPE_FREE_BRANCH_END
.
This constant is 3.public static final int TYPE_NODE_OR_BRANCH_END_MAX
TYPE_USUAL_NODE
, TYPE_ISOLATED
and TYPE_FREE_BRANCH_END
.
This constant is 1.public static final int TYPE_BRANCH_MIN
TYPE_FREE_BRANCH_END
, TYPE_USUAL_BRANCH
.
This constant is 4.public static final int TYPE_BRANCH_MAX
TYPE_FREE_BRANCH_END
, TYPE_USUAL_BRANCH
.
This constant is 3.protected final int dimCount
dimCount()
method.protected final int numberOfNeighbours
numberOfNeighbours()
method.
Equal to 3^{n}−1, n=dimCount
(the number of elements of 3x3x...x3 hypercube without the central element).protected SkeletonPixelClassifier(int dimCount)
numberOfNeighbours()
method, can be represented by int Java type.dimCount
 the number of dimensions, which will be returned by dimCount()
method.java.lang.IllegalArgumentException
 if dimCount ≤ 0 or
if 3^{dimCount} >
Integer.MAX_VALUE=2^{31}−1.public static boolean isNodePixelType(int pixelType)
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 which isBranchPixelType(int)
returns true.
pixelType
 pixel type: possible element of the result of asPixelTypes
method.public static boolean isUsualBranchPixelType(int pixelType)
TYPE_USUAL_BRANCH
pixelType
 pixel type: possible element of the result of asPixelTypes
method.public static boolean isFreeBranchEndPixelType(int pixelType)
TYPE_FREE_BRANCH_END
pixelType
 pixel type: possible element of the result of asPixelTypes
method.public static boolean isAttachableBranchEndPixelType(int pixelType)
asPixelTypes
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 of
asPixelTypes
method,
— but it is chosen in such a way, that the nodes and branches form a correct skeleton nonoriented graph,
as written in the comments to this class
.
Informally, this pixel type indicates an ending pixel of
a thin connected 1pixel 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).
pixelType
 pixel type: possible element of the result of asPixelTypes
method.public static boolean isNodeOrFreeBranchEndPixelType(int pixelType)
isNodePixelType
(pixelType) returns true)
or a free branch end
(isFreeBranchEndPixelType
(pixelType) returns true).
Equivalent toTYPE_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).
pixelType
 pixel type: possible element of the result of asPixelTypes
method.public static boolean isBranchPixelType(int pixelType)
isUsualBranchPixelType
(pixelType)
returns true), free branch end
(where isFreeBranchEndPixelType
(pixelType)
returns true) or attachable branch end
(where isAttachablePixelType
(pixelType)
returns true).
Equivalent toTYPE_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 which isNodePixelType(int)
returns true,
and branch pixels, for which this method returns true.
pixelType
 pixel type: possible element of the result of asPixelTypes
method.public static boolean isIllegalPixelType(int pixelType)
TYPE_ILLEGAL
pixelType
 pixel type: possible element of the result of asPixelTypes
method.public final int dimCount()
SkeletonScanner
, equivalent to
skeleton()
.dimCount()
public final int numberOfNeighbours()
dimCount()
(the number of elements of 3x3x...x3 hypercube without the central element).
In particular, in 2dimensional case this method returns 3^{2}1=8,
and in 3dimensional case this method returns 3^{3}1=26.public final long[] neighbourOffset(int neighbourIndex)
dimCount()
),
and we need to find the coordinates
numberOfNeighbours()
,
we should use the following formula:
j_{i} = i_{i} + 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 xaxis is directed rightward, the yaxis is directed downward).
It means that the results of this method in BasicSkeletonPixelClassifier2D
are the following:
for neighbourIndex=0 it returns twoelement array BasicSkeletonPixelClassifier2D
class enumerates
the neighbours along the perimeter of 3x3 square.
This method is completely implemented via neighbourOffset(long[], int)
method.
neighbourIndex
 an index if the neighbour of some central element of a matrix.java.lang.IndexOutOfBoundsException
 if neighbourIndex is out of range
0..numberOfNeighbours()
1.SkeletonScanner.neighbourOffsetInArray(int)
public abstract void neighbourOffset(long[] coordinateIncrements, int neighbourIndex)
neighbourOffset(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.
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.java.lang.NullPointerException
 if coordinateIncrements argument is null.java.lang.IllegalArgumentException
 if coordinateIncrements.length!=dimCount()
.java.lang.IndexOutOfBoundsException
 if neighbourIndex is out of range
0..numberOfNeighbours()
1.SkeletonScanner.neighbourOffsetInArray(int)
public abstract int reverseNeighbourIndex(int neighbourIndex)
neighbourOffset(int)
method.
It means, that if k1 is the argument of this method and k2 is the result of this method,
neighbourOffset
(k1)neighbourOffset
(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.
neighbourIndex
 an index of some neighbour B of some central element A.java.lang.IndexOutOfBoundsException
 if neighbourIndex is out of range
0..numberOfNeighbours()
1.public abstract Matrix<? extends PIntegerArray> asPixelTypes(Matrix<? extends BitArray> skeleton, SkeletonPixelClassifier.AttachmentInformation attachmentInformation)
dimCount()
.
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;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:
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 really node
or, maybe,
TYPE_ILLEGAL
;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 be
zero
or isolated
, and if it is a node
,
it is supposed that we have a short branch to it, consisting of 1 pixel.comments to SkeletonPixelClassifier
,
section "Pixel types", group 5.neighbourOffset(int)
method.
In BasicSkeletonPixelClassifier2D
, 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 xaxis is directed rightward, the yaxis is directed downward).
Namely, if the current element has coordinates
Note, that the situation, when some neighbouring elements are out of ranges of the matrix coordinates,
is processed according to the model of infinite pseudocyclical continuation —
see the end of the comments to SkeletonPixelClassifier
.
Note, that all values, specified by constants of this class
(all cases 16 above, excepting the last case 7), are different negative integers.
Then, note that TYPE_USUAL_NODE
, TYPE_ISOLATED
and TYPE_FREE_BRANCH_END
are adjacent integers 3..1.
Then, note that two constants, corresponding to branches and their ends —
TYPE_FREE_BRANCH_END
and TYPE_USUAL_BRANCH
—
are also adjacent integers 4..3.
Then, note that two constants, corresponding to nodes and isolated pixels —
TYPE_USUAL_NODE
and TYPE_ISOLATED
—
are also adjacent integers 2..1.
This can be useful for extracting special kinds of skeleton pixels into bit matrices.
skeleton
 the skeleton matrix that should be processed.attachmentInformation
 what should this method return for attachable pixels.java.lang.NullPointerException
 if skeleton or attachmentInformation is null.java.lang.IllegalArgumentException
 if skeleton.dimCount()!=dimCount()
.public abstract void markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[] pixelTypesOfAllNeighbours)
node
, which are also nodes
and are considered to be not connected with this node via a degenerated 0pixel branch.
Neighbouring nodes, which are considered to be connected with the central node
via 0pixel 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 by
neighbourOffset(int)
method.
This method finds among them all values, equal to TYPE_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 are
TYPE_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 first
numberOfNeighbours()
elements and ignores others.
In ApertureBasedSkeletonPixelClassifier
for 2dimensional case and,
in particular, in BasicSkeletonPixelClassifier2D
,
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 (4connected neighbour) or if it is diagonal,
but the two adjacent pixels, which are 4connected neighbours
of both P and Q, are not nodes
:
. . * . . . . . . * . . . . * . . . . . . * . . * * . * * * . . . 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 0pixel branches. (In
ApertureBasedSkeletonPixelClassifier
class for the number of dimensions, other than 2,
the implementation of this method does nothing.)pixelTypesOfAllNeighbours
 an array of the pixel types of all neighbours of some given element,
supposed to be a node
; this method will replace
some TYPE_USUAL_NODE
values in this array with
Integer.MIN_VALUE.java.lang.NullPointerException
 if the argument is null.java.lang.IllegalArgumentException
 if the length of the passed array is less than numberOfNeighbours()
.