public abstract class ApertureBasedSkeletonPixelClassifier extends SkeletonPixelClassifier
A skeletal implementation of the SkeletonPixelClassifier
abstract class,
minimizing the effort required to implement its abstract methods.
Namely, the main asPixelTypes
method is implemented in this class
via the following 2 abstract methods:
The methods neighbourOffset(long[], int)
and reverseNeighbourIndex(int)
are implemented on the base of the array of offsets of all neighbours of a random element.
This array should be passed to the constructor
.
The constructor analyses the passed array, checks that it really contains
offsets of all neighbours, copies this array into an internal field, which is used
by neighbourOffset(long[], int)
, and also automatically finds,
for every neighbour, the reverse neighbour index, which will be returned by reverseNeighbourIndex(int)
.
The method markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[])
is implemented here
in some reasonable way for 2dimensional case, as specified in comments to this method.
For other number of dimensions, this method does nothing.
It is a good solution for the degenerated case dimCount()
=1;
for 3dimensional case, this method probably should be overridden.
So, it is enough to implement pixelTypeOrAttachingBranch(int)
and pixelTypeOrAttachedNode(int)
methods and, maybe, override markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[])
method
to create a full implementation of the skeleton pixel classifier on the base of this class.
This class can be used in 1, 2 and 3dimensional cases only.
One of the reasons of this restriction is that the argument of pixelTypeOrAttachingBranch(int)
and pixelTypeOrAttachedNode(int)
(int type) can represent the values of, maximally, 32
neighbours. It is enough for 3dimensional case, where the number of neighbours is 3^{3}−1=26<32,
but not enough already for 4dimensional case, where the number of neighbours is 3^{4}−1=80
(and even 64bit long type would have been insufficient).
This class is immutable and threadsafe: there are no ways to modify settings of the created instance.
SkeletonPixelClassifier.AttachmentInformation
dimCount, numberOfNeighbours, TYPE_BRANCH_MAX, TYPE_BRANCH_MIN, TYPE_FREE_BRANCH_END, TYPE_ILLEGAL, TYPE_ISOLATED, TYPE_NODE_OR_BRANCH_END_MAX, TYPE_NODE_OR_BRANCH_END_MIN, TYPE_USUAL_BRANCH, TYPE_USUAL_NODE, TYPE_ZERO
Modifier  Constructor and Description 

protected 
ApertureBasedSkeletonPixelClassifier(int dimCount,
long[][] neighbourOffsets)
Creates new instance of this class, allowing to process skeletons with the given number of dimensions,
with the order of neighbours, specified in the second argument.

Modifier and Type  Method and Description 

Matrix<? extends PIntegerArray> 
asNeighbourhoodBitMaps(Matrix<? extends BitArray> skeleton)
Returns an immutable view of the passed skeleton matrix, where each element is an integer,
containing, in its low bits, the bit values of the corresponding element
C of the source skeleton and of all its neighbours (in terms of the
straightanddiagonal connectivity kind ). 
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.

void 
markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[] pixelTypesOfAllNeighbours)

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. 
protected abstract int 
pixelTypeOrAttachedNode(int apertureBits)
Calculates and returns the value of an element C'
in the resulting matrix, produced by
asPixelTypes method with
NEIGHBOUR_INDEX_OF_ATTACHED_NODE value of attachmentInformation argument,
on the base of bit values of all neighbours (in terms of the
straightanddiagonal connectivity kind )
of the corresponding unit element C in the source skeleton bit matrix. 
protected abstract int 
pixelTypeOrAttachingBranch(int apertureBits)
Calculates and returns the value of an element C'
in the resulting matrix, produced by
asPixelTypes method with
NEIGHBOUR_INDEX_OF_ATTACHING_BRANCH value of attachmentInformation argument,
on the base of bit values of all neighbours (in terms of the
straightanddiagonal connectivity kind )
of the corresponding unit element C in the source skeleton bit matrix. 
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.

dimCount, isAttachableBranchEndPixelType, isBranchPixelType, isFreeBranchEndPixelType, isIllegalPixelType, isNodeOrFreeBranchEndPixelType, isNodePixelType, isUsualBranchPixelType, neighbourOffset, numberOfNeighbours
protected ApertureBasedSkeletonPixelClassifier(int dimCount, long[][] neighbourOffsets)
The argument neighbourOffsets must contain offsets of all neighbours,
in terms of the straightanddiagonal connectivity kind
, of any matrix element, in some order.
More precisely, this array must contain
numberOfNeighbours()
=3^{dimCount}1neighbourOffset(k)
call.
The passed neighbourOffsets array is deeply cloned by the constructor: no references to it or its elements are maintained by the created object.
dimCount
 the number of dimensions, which will be returned by
dimCount()
method.neighbourOffsets
 offsets of all neighbours of any matrix element,
in terms of neighbourOffset(int)
method.java.lang.NullPointerException
 if neighbourOffsets or one of its elements is null.java.lang.IllegalArgumentException
 if dimCount is not in 1..3 range,
or if neighbourOffsets.length!=3^{dimCount}1,
or if neighbourOffsets[k].length!=dimCount for some k,
or if neighbourOffsets does not contain, in some order,
the offsets of all 3^{dimCount}1 neighbours
(in particular, if some elements neighbourOffsets[k][j] are
not in 1..+1 range or if offsets of some neighbours are equal).public void neighbourOffset(long[] coordinateIncrements, int neighbourIndex)
SkeletonPixelClassifier
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.
neighbourOffset
in class SkeletonPixelClassifier
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.SkeletonScanner.neighbourOffsetInArray(int)
public int reverseNeighbourIndex(int neighbourIndex)
SkeletonPixelClassifier
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.
reverseNeighbourIndex
in class SkeletonPixelClassifier
neighbourIndex
 an index of some neighbour B of some central element A.public Matrix<? extends PIntegerArray> asPixelTypes(Matrix<? extends BitArray> skeleton, SkeletonPixelClassifier.AttachmentInformation attachmentInformation)
SkeletonPixelClassifier
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:
SkeletonPixelClassifier.TYPE_ZERO
, if the corresponding element of the skeleton is zero (no pixel);SkeletonPixelClassifier.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);SkeletonPixelClassifier.TYPE_USUAL_NODE
, if the corresponding element of the skeleton is a node, where 3 or more
branches meet;SkeletonPixelClassifier.TYPE_ISOLATED
, if the corresponding element of the skeleton is an isolated unit pixel,
having no unit neighbour elements;SkeletonPixelClassifier.TYPE_FREE_BRANCH_END
, if the corresponding element of the skeleton is an end of some branch,
having 1 unit neighbour elements;SkeletonPixelClassifier.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,
SkeletonPixelClassifier.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 SkeletonPixelClassifier.TYPE_USUAL_NODE
, SkeletonPixelClassifier.TYPE_ISOLATED
and SkeletonPixelClassifier.TYPE_FREE_BRANCH_END
are adjacent integers 3..1.
Then, note that two constants, corresponding to branches and their ends —
SkeletonPixelClassifier.TYPE_FREE_BRANCH_END
and SkeletonPixelClassifier.TYPE_USUAL_BRANCH
—
are also adjacent integers 4..3.
Then, note that two constants, corresponding to nodes and isolated pixels —
SkeletonPixelClassifier.TYPE_USUAL_NODE
and SkeletonPixelClassifier.TYPE_ISOLATED
—
are also adjacent integers 2..1.
This can be useful for extracting special kinds of skeleton pixels into bit matrices.
asPixelTypes
in class SkeletonPixelClassifier
skeleton
 the skeleton matrix that should be processed.attachmentInformation
 what should this method return for attachable pixels.public void markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[] pixelTypesOfAllNeighbours)
SkeletonPixelClassifier
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 SkeletonPixelClassifier.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
SkeletonPixelClassifier.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.)markNeighbouringNodesNotConnectedViaDegeneratedBranches
in class SkeletonPixelClassifier
pixelTypesOfAllNeighbours
 an array of the pixel types of all neighbours of some given element,
supposed to be a node
; this method will replace
some SkeletonPixelClassifier.TYPE_USUAL_NODE
values in this array with
Integer.MIN_VALUE.public final Matrix<? extends PIntegerArray> asNeighbourhoodBitMaps(Matrix<? extends BitArray> skeleton)
straightanddiagonal connectivity kind
).
More precisely, each integer element w of the resulting matrix will contain:
numberOfNeighbours()
(in other words, neighbourOffset(int)
method;In particular, in BasicSkeletonPixelClassifier2D
implementation,
the lower 9 bits in the elements of the returned matrix correspond to elements of 3x3 aperture
of the source skeleton according the following diagram:
1 2 3 8 0 4 7 6 5
(the xaxis is directed rightward, the yaxis is directed downward).
The implementation of asPixelTypes
method in this class is based on
this method and pixelTypeOrAttachingBranch(int)
and pixelTypeOrAttachedNode(int)
methods:
the results w, returned by this method for unit central elements C
of the source skeleton, are shifted to the right and passed as
pixelTypeOrAttachingBranch(int)
or pixelTypeOrAttachedNode(int)
to form the elements
of the resulting matrix.
Note, that the situation, when the 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
.
skeleton
 the skeleton matrix that should be processed.java.lang.NullPointerException
 if skeleton is null.java.lang.IllegalArgumentException
 if skeleton.dimCount()!=SkeletonPixelClassifier.dimCount()
.protected abstract int pixelTypeOrAttachingBranch(int apertureBits)
asPixelTypes
method with
NEIGHBOUR_INDEX_OF_ATTACHING_BRANCH
value of attachmentInformation argument,
on the base of bit values of all neighbours (in terms of the
straightanddiagonal connectivity kind
)
of the corresponding unit element C in the source skeleton bit matrix.
More precisely, the bit values of the neighbours of this skeleton element C
are passed via the low
m=numberOfNeighbours()
bits of apertureBits argument.
The bit #k of this argument, 0≤k<m (its value is
neighbourOffset(int)
method.
In particular, in BasicSkeletonPixelClassifier2D
implementation,
the order of neighbours is described by the following diagram:
0 1 2 7 C 3 6 5 4
So, 8 low bits of apertureBits contain the values of the corresponding neighbouring elements in anticlockwise order (the xaxis is directed rightward, the yaxis is directed downward).
It is supposed that the central element (C) of the skeleton is unit
(for zero elements ot the skeleton matrix, asPixelTypes
method of
this class returns SkeletonPixelClassifier.TYPE_ZERO
without calling this method).
Note, that the situation, when the 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
.
apertureBits
 the values of all 8 neighbours of the current unit element of the source skeleton
bit matrix.protected abstract int pixelTypeOrAttachedNode(int apertureBits)
asPixelTypes
method with
NEIGHBOUR_INDEX_OF_ATTACHED_NODE
value of attachmentInformation argument,
on the base of bit values of all neighbours (in terms of the
straightanddiagonal connectivity kind
)
of the corresponding unit element C in the source skeleton bit matrix.
More precisely, the bit values of the neighbours of this skeleton element C
are passed via the low
m=numberOfNeighbours()
bits of apertureBits argument.
The bit #k of this argument, 0≤k<m (its value is
neighbourOffset(int)
method.
In particular, in BasicSkeletonPixelClassifier2D
implementation,
the order of neighbours is described by the following diagram:
0 1 2 7 C 3 6 5 4
So, 8 low bits of apertureBits contain the values of the corresponding neighbouring elements in anticlockwise order (the xaxis is directed rightward, the yaxis is directed downward).
It is supposed that the central element (C) of the skeleton is unit
(for zero elements ot the skeleton matrix, asPixelTypes
method of
this class returns SkeletonPixelClassifier.TYPE_ZERO
without calling this method).
Note, that the situation, when the 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
.
apertureBits
 the values of all 8 neighbours of the current unit element of the source skeleton
bit matrix.