Class StrongQuadruple3x5ThinningSkeleton2D

java.lang.Object
net.algart.arrays.AbstractIterativeArrayProcessor<Matrix<? extends UpdatableBitArray>>
net.algart.matrices.skeletons.StrongQuadruple3x5ThinningSkeleton2D
All Implemented Interfaces:
ArrayProcessor, IterativeArrayProcessor<Matrix<? extends UpdatableBitArray>>, ThinningSkeleton

public class StrongQuadruple3x5ThinningSkeleton2D extends AbstractIterativeArrayProcessor<Matrix<? extends UpdatableBitArray>> implements ThinningSkeleton

Stronger version of Quadruple3x5ThinningSkeleton2D skeletonization algorithm.

This class implements almost the same algorithm as Quadruple3x5ThinningSkeleton2D, but the thinning method is more aggressive (and slow: it is the slowest thinning skeleton in this package). This class is also based on analysis of 3x5 aperture. This algorithm also guarantees that 8-connected "objects" (areas filled by 1 elements) always stay 8-connected: see ThinningSkeleton interface about the precise sense of this state.

The main difference from Quadruple3x5ThinningSkeleton2D is that this class never keeps 3x3 and 3x2 rectangles, filled by 1 — they are successfully skeletonized. (More precisely, there is only one degenerated case, when such rectangles can appear in the skeletonization result: if all pixels of the bit matrix, supposed to be infinitely pseudo-cyclically continued, are filled by 1. All skeletonization algorithms do nothing in this case.) The corresponding "bad" cases of Quadruple3x5ThinningSkeleton2D will be skeletonized in the following or similar way:

 . . . . . . . .                     . . . . . . . .
 1 . . 1 . . 1 .                     1 . . 1 . . 1 .
 . 1 . 1 . 1 . .                     . 1 . 1 . 1 . .
 . . 1 1 1 . . .  is transformed to  . . 1 . 1 . . .
 . . 1 1 1 . . .                     . . 1 . 1 . . .
 . 1 . 1 . 1 . .                     . 1 . 1 . 1 . .
 1 . . 1 . . 1 .                     1 . . 1 . . 1 .

 1 . . 1 . . 1 .                     1 . . 1 . . 1 .
 . 1 . 1 . 1 . .                     . 1 . 1 . 1 . .
 . . 1 1 1 . . .                     . . 1 1 1 . . .
 1 1 1 1 1 1 1 .  is transformed to  1 1 . 1 . 1 1 .
 . . 1 1 1 . . .                     . . 1 1 1 . . .
 . 1 . 1 . 1 . .                     . 1 . 1 . 1 . .
 1 . . 1 . . 1 .                     1 . . 1 . . 1 .
 

Below are some "bad" cases, when some areas cannot be "thinned" by this algorithm:

 . . . . . . . .    . . . . . . .      . . . 1 . . .
 . . . . . . . .    . 1 . . 1 . .      . 1 . 1 . 1 .
 . . 1 . . 1 . .    . . 1 1 . . .      . . 1 1 1 . .
 . . . 1 1 . . .    . . 1 1 1 1 .      . . . 1 . . .
 . . . 1 1 . . .    . 1 . 1 . . .      . 1 1 1 1 1 .
 . . 1 . . 1 . .    . . . 1 . . .      . . . 1 . . .
 . . . . . . . .    . . . . . . .      . . . 1 . . .
 

It is obvious that the left configuration cannot be thinned more without breaking connectivity. Other configurations, theoretically, can be reduced by removing pixels in intersections of horizontal and vertical lines, for example:

 . . . ? . . .
 . ? . ? . ? .
 . . ? . ? . .
 . . . ? . . .
 . ? ? . ? ? .
 . . . ? . . .
 . . . ? . . .
 

But it means appearing strange 1-pixels "holes" in any intersection of horizontal and vertical lines and seems to be a bad idea for most applications.

I recommend to run this algorithm after finishing OctupleThinningSkeleton2D and WeakOctupleThinningSkeleton2D algorithms (for example, with help of IterativeArrayProcessor.chain(IterativeArrayProcessor, double) method).

This class is based on Matrices.asShifted method with some elementwise logical operations (AND, OR, NOT). So, the matrix is supposed to be 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) method, where the dimensions of the "submatrix" are greater than dimensions of the source one by 1 and the continuationMode argument is Matrix.ContinuationMode.ZERO_CONSTANT.

This class may be applied to a matrix with any number of dimensions, but it is designed for 2-dimensional case: all other dimensions will be ignored.

This class is not thread-safe, but is thread-compatible and can be synchronized manually, if multithread access is necessary.

Author:
Daniel Alievsky