All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.algart.matrices.skeletons.ThinningSkeleton Maven / Gradle / Ivy

Go to download

Open-source Java libraries, supporting generalized smart arrays and matrices with elements of any types, including a wide set of 2D-, 3D- and multidimensional image processing and other algorithms, working with arrays and matrices.

There is a newer version: 1.4.23
Show newest version
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2007-2024 Daniel Alievsky, AlgART Laboratory (http://algart.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package net.algart.matrices.skeletons;

import net.algart.arrays.*;

/**
 * 

Common 2-dimensional skeletonization algorithm of binary matrices, based on ≤8 thinning steps, * corresponding to all or some from 8 directions with the step 45 degree. * The following concrete skeletonization classes implements it:

* *
    *
  • {@link OctupleThinningSkeleton2D};
  • *
  • {@link WeakOctupleThinningSkeleton2D};
  • *
  • {@link Quadruple3x5ThinningSkeleton2D};
  • *
  • {@link StrongQuadruple3x5ThinningSkeleton2D}.
  • *
* *

This interface extends {@link IterativeArrayProcessor} interface, * iteratively processing some bit matrix ({@link Matrix}({@link UpdatableBitArray})), named * result and usually passed to instantiation methods. * It is supposed, that in all implementations of this interface:

* *
    *
  • {@link #performIteration(net.algart.arrays.ArrayContext) performIteration(ArrayContext)} * method sequentially calls {@link #asThinning(int directionIndex)} method and copies its result to * the result matrix for directionIndex=0,1,2,3,4,5,6,7. * It means, that all "objects" in the matrix (areas filled by 1 elements) * are "thinned" 8 times: from left direction, from left-top diagonal direction, etc. * Depending on implementation, * {@link #performIteration(net.algart.arrays.ArrayContext) performIteration(ArrayContext)} may skip * calling {@link #asThinning asThinning} for some of these directions — you can check this * by {@link #isThinningRequired(int)} method. *
  • * *
  • {@link #done() done()} method returns true if the last iteration was unable to change the matrix: * all "objects" are already "thin".
  • * *
  • {@link #result() result()} method always returns the reference to the source matrix, passed to * instantiation methods of the inheritors.
  • *
* *

All classes of this package, implementing this interface, guarantee that 8-connected "objects" * (areas filled by 1 elements) always stay 8-connected.

* *

More precisely, let's consider an AlgART bit matrix * {@link Matrix}<{@link UpdatableBitArray}>, processed by this class. * The 8-connected object is a connected component of the graph, built on the matrix, * where unit matrix elements are vertices, and neighbour unit elements are connected by edges. * Neighbour elements are 2 elements with coordinates (x1, y1) * and (x2, y2), where * max(|x1x2|, * |y1y2|) = 1, * i.e. every matrix element has 8 neighbours. * We can consider that the matrix contains images of some objects: * unit bits (1) are white pixels, belonging to objects, zero bits (0) are black pixels of the background. * Then our term "8-connected objects" describes the white objects, separated by black space.

* *

The state "8-connected objects always stay 8-connected" means the following. * Let A is the current result matrix and A' is either the result * {@link #asThinning(int)} method or the new result matrix after calling * {@link #performIteration(net.algart.arrays.ArrayContext) performIteration(ArrayContext)} method. * It is guaranteed that:

*
    *
  1. the set of unit elements of the matrix A' is equal to or is a subset of the set of unit element * of the matrix A; in other words, the skeletonization always reduces objects and never expands them; *
  2. *
  3. if C is some 8-connected object in the matrix A and C' is a set of points (unit elements) * in the matrix A', belonging to the area C, then C' is an empty set or 8-connected object. *
  4. *
* *

It is obvious that the same state is true if we performs any number of calls of * {@link #performIteration(net.algart.arrays.ArrayContext) performIteration} instead of one call.

* *

For most kinds of skeletons, the 2nd condition is more strong: the 8-connected object C' cannot be * an empty set. In other words, connected objects are never removed at all, they are only "thinned". * The only skeletons of this package, for which it is not true, are so called topological skeletons, * offered by {@link OctupleThinningSkeleton2D} and {@link WeakOctupleThinningSkeleton2D} classed * by the corresponding "topological" argument of the instantiation methods.

* *

The resulting "skeleton" (after finishing {@link #process()} method) * are usually "thin" enough (1-pixel lines), but some little not "thin" areas are possible.

* *

All classes of this package, implementing this interface, suppose that the processed matrix * is infinitely pseudo-cyclically continued, as well * {@link Matrices#asShifted Matrices.asShifted} method supposes it. * You can change this behavior by appending the source matrix with zero elements * by calling {@link 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 {@link net.algart.arrays.Matrix.ContinuationMode#ZERO_CONSTANT}.

* *

The classes, implementing this interface, are usually thread-compatible * and can be synchronized manually, if multithreading access is necessary.

* * @author Daniel Alievsky */ public interface ThinningSkeleton extends IterativeArrayProcessor> { /** * Returns true if and only if * {@link #performIteration(net.algart.arrays.ArrayContext) performIteration(ArrayContext)} method * really calls {@link #asThinning(int directionIndex)} for this direction * and copies its result to the result matrix. * It depends on the implementation of this interface. * * @param directionIndex the direction of thinning, from 0 to 7. * @return whether the matrix should be thinned along this direction. * @throws IllegalArgumentException if directionIndex is not in 0..7 range. */ boolean isThinningRequired(int directionIndex); // WARNING: SUN BUG IN javadoc UTILITY (1.6.0_04, 1.7.0-ea)! // Below we cannot write "{@link #result()}" - it leads to ClassCastException in javadoc. /** * Returns current {@link IterativeArrayProcessor#result() result()} matrix thinned along the given direction. * The result is "lazy": it is only a view of the current matrix. It is the basic method, * implementing the skeletonization algorithm. * *

Generally speaking, the "thinning" means removing elements * from the boundary of any "object" (area of the matrix filled by 1). * directionIndex specifies the "eroded side" of objects, * or the direction of thinning:

    *
  • 0 means removing elements from the left, i.e. from the side (x−1,y),
  • *
  • 1 means "diagonal" removal from the side (x−1,y−1),
  • *
  • 2 means removal from the side (x,y−1),
  • *
  • 3 means "diagonal" removal from the side (x+1,y−1),
  • *
  • 4 means removal from the right, i.e. from the side (x+1,y),
  • *
  • 5 means "diagonal" removal from the side (x+1,y+1),
  • *
  • 6 means removal from the side (x,y+1),
  • *
  • 7 means "diagonal" removal from the side (x−1,y+1).
  • *
*

Some directions may be ignored by an implementation; in this case, the reference to the current * {@link IterativeArrayProcessor#result() result()} matrix is returned. * Note: there is no guarantee that this method ignores directions, for which * {@link #isThinningRequired(int directionIndex)} method returns false. * * @param directionIndex the direction of thinning, from 0 to 7. * @return the thinned view if the current {@link #result()} matrix. * @throws IllegalArgumentException if directionIndex is not in 0..7 range. */ Matrix asThinning(int directionIndex); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy