Class ApertureBasedSkeletonPixelClassifier
- Direct Known Subclasses:
BasicSkeletonPixelClassifier2D
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 2-dimensional 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 3-dimensional 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 3-dimensional 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 3-dimensional case, where the number of neighbours is 33−1=26<32,
but not enough already for 4-dimensional case, where the number of neighbours is 34−1=80
(and even 64-bit long type would have been insufficient).
This class is immutable and thread-safe: there are no ways to modify settings of the created instance.
- Author:
- Daniel Alievsky
-
Nested Class Summary
Nested classes/interfaces inherited from class net.algart.matrices.skeletons.SkeletonPixelClassifier
SkeletonPixelClassifier.AttachmentInformation
-
Field Summary
Fields inherited from class net.algart.matrices.skeletons.SkeletonPixelClassifier
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
-
Constructor Summary
ModifierConstructorDescriptionprotected
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. -
Method Summary
Modifier and TypeMethodDescriptionfinal 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 thestraight-and-diagonal 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 ofneighbourOffset(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 byasPixelTypes
method withNEIGHBOUR_INDEX_OF_ATTACHED_NODE
value of attachmentInformation argument, on the base of bit values of all neighbours (in terms of thestraight-and-diagonal 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 byasPixelTypes
method withNEIGHBOUR_INDEX_OF_ATTACHING_BRANCH
value of attachmentInformation argument, on the base of bit values of all neighbours (in terms of thestraight-and-diagonal 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.Methods inherited from class net.algart.matrices.skeletons.SkeletonPixelClassifier
dimCount, isAttachableBranchEndPixelType, isBranchPixelType, isFreeBranchEndPixelType, isIllegalPixelType, isNodeOrFreeBranchEndPixelType, isNodePixelType, isUsualBranchPixelType, neighbourOffset, numberOfNeighbours
-
Constructor Details
-
ApertureBasedSkeletonPixelClassifier
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. The number of dimensions must be 1, 2 or 3.The argument neighbourOffsets must contain offsets of all neighbours, in terms of the
straight-and-diagonal connectivity kind
, of any matrix element, in some order. More precisely, this array must contain elements (2, 8 or 26 for 1-, 2-, 3-dimensional cases) innumberOfNeighbours()
=3dimCount-13/3x3/3x3x3-aperture , and each its element neighbourOffsets[k] must be equal to the result ofneighbourOffset(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.
- Parameters:
dimCount
- the number of dimensions, which will be returned bydimCount()
method.neighbourOffsets
- offsets of all neighbours of any matrix element, in terms ofneighbourOffset(int)
method.- Throws:
NullPointerException
- if neighbourOffsets or one of its elements is null.IllegalArgumentException
- if dimCount is not in 1..3 range, or if neighbourOffsets.length!=3dimCount-1, or if neighbourOffsets[k].length!=dimCount for some k, or if neighbourOffsets does not contain, in some order, the offsets of all 3dimCount-1 neighbours (in particular, if some elements neighbourOffsets[k][j] are not in -1..+1 range or if offsets of some neighbours are equal).
-
-
Method Details
-
neighbourOffset
public void neighbourOffset(long[] coordinateIncrements, int neighbourIndex) Description copied from class:SkeletonPixelClassifier
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.- Specified by:
neighbourOffset
in classSkeletonPixelClassifier
- 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.- See Also:
-
reverseNeighbourIndex
public int reverseNeighbourIndex(int neighbourIndex) Description copied from class:SkeletonPixelClassifier
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.- Specified by:
reverseNeighbourIndex
in classSkeletonPixelClassifier
- 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.
-
asPixelTypes
public Matrix<? extends PIntegerArray> asPixelTypes(Matrix<? extends BitArray> skeleton, SkeletonPixelClassifier.AttachmentInformation attachmentInformation) Description copied from class:SkeletonPixelClassifier
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:
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;- 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,SkeletonPixelClassifier.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
SkeletonPixelClassifier.TYPE_USUAL_NODE
,SkeletonPixelClassifier.TYPE_ISOLATED
andSkeletonPixelClassifier.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
andSkeletonPixelClassifier.TYPE_USUAL_BRANCH
— are also adjacent integers -4..-3. Then, note that two constants, corresponding to nodes and isolated pixels —SkeletonPixelClassifier.TYPE_USUAL_NODE
andSkeletonPixelClassifier.TYPE_ISOLATED
— are also adjacent integers -2..-1. This can be useful for extracting special kinds of skeleton pixels into bit matrices.- Specified by:
asPixelTypes
in classSkeletonPixelClassifier
- 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.
-
markNeighbouringNodesNotConnectedViaDegeneratedBranches
public void markNeighbouringNodesNotConnectedViaDegeneratedBranches(int[] pixelTypesOfAllNeighbours) Description copied from class:SkeletonPixelClassifier
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 toSkeletonPixelClassifier.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 areSkeletonPixelClassifier.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 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.)- Specified by:
markNeighbouringNodesNotConnectedViaDegeneratedBranches
in classSkeletonPixelClassifier
- Parameters:
pixelTypesOfAllNeighbours
- an array of the pixel types of all neighbours of some given element, supposed to be anode
; this method will replace someSkeletonPixelClassifier.TYPE_USUAL_NODE
values in this array with Integer.MIN_VALUE.
-
asNeighbourhoodBitMaps
public final 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 thestraight-and-diagonal connectivity kind
).More precisely, each integer element w of the resulting matrix will contain:
- in the bit #0 (in other words,
w&1 ): the value of the corresponding element C of the source skeleton bit matrix; - in the bit #k+1, 0≤k<
numberOfNeighbours()
(in other words,(w>>>(k+1))&1 ): the value of the neighbour #k of the central element C, in terms ofneighbourOffset(int)
method; - all other bits of the elements if the resulting matrix will be zero.
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 x-axis is directed rightward, the y-axis is directed downward).
The implementation of
asPixelTypes
method in this class is based on this method andpixelTypeOrAttachingBranch(int)
andpixelTypeOrAttachedNode(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 asapertureBits=w>>>1 argument topixelTypeOrAttachingBranch(int)
orpixelTypeOrAttachedNode(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 pseudo-cyclical continuation — see the end of the
comments to SkeletonPixelClassifier
.- Parameters:
skeleton
- the skeleton matrix that should be processed.- Returns:
- the matrix of integer values with the same sizes, containing the bit maps of the neighbourhoods of all skeleton pixels.
- Throws:
NullPointerException
- if skeleton is null.IllegalArgumentException
- if skeleton.dimCount()!=SkeletonPixelClassifier.dimCount()
.
- in the bit #0 (in other words,
-
pixelTypeOrAttachingBranch
protected abstract int pixelTypeOrAttachingBranch(int apertureBits) Calculates and returns the value of an element C' in the resulting matrix, produced byasPixelTypes
method withNEIGHBOUR_INDEX_OF_ATTACHING_BRANCH
value of attachmentInformation argument, on the base of bit values of all neighbours (in terms of thestraight-and-diagonal 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(apertureBits>>>k)&1 ), is equal to the value of the neighbour #k in terms ofneighbourOffset(int)
method. In particular, inBasicSkeletonPixelClassifier2D
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 x-axis is directed rightward, the y-axis 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 returnsSkeletonPixelClassifier.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 pseudo-cyclical continuation — see the end of the
comments to SkeletonPixelClassifier
.- Parameters:
apertureBits
- the values of all 8 neighbours of the current unit element of the source skeleton bit matrix.- Returns:
- the type of this pixel of the skeleton.
-
pixelTypeOrAttachedNode
protected abstract int pixelTypeOrAttachedNode(int apertureBits) Calculates and returns the value of an element C' in the resulting matrix, produced byasPixelTypes
method withNEIGHBOUR_INDEX_OF_ATTACHED_NODE
value of attachmentInformation argument, on the base of bit values of all neighbours (in terms of thestraight-and-diagonal 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(apertureBits>>>k)&1 ), is equal to the value of the neighbour #k in terms ofneighbourOffset(int)
method. In particular, inBasicSkeletonPixelClassifier2D
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 x-axis is directed rightward, the y-axis 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 returnsSkeletonPixelClassifier.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 pseudo-cyclical continuation — see the end of the
comments to SkeletonPixelClassifier
.- Parameters:
apertureBits
- the values of all 8 neighbours of the current unit element of the source skeleton bit matrix.- Returns:
- the type of this pixel of the skeleton.
-