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

net.algart.matrices.skeletons.BasicSkeletonPixelClassifier2D 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.JArrays;

import java.util.Objects;

/**
 * 

Ready classifier of pixel of 2-dimensional {@link ThinningSkeleton thinning skeletons}. * *

There are only 3 instances of this class, returned by the methods:

* *
    *
  • {@link #getOctupleThinningInstance()},
  • *
  • {@link #getQuadruple3x5ThinningInstance()},
  • *
  • {@link #getStrongQuadruple3x5ThinningInstance()}.
  • *
* *

These classifiers are designed for processing bit matrices, which are the final results of * most popular 2-dimensional skeletonization algorithms: {@link OctupleThinningSkeleton2D}, * {@link Quadruple3x5ThinningSkeleton2D} and {@link StrongQuadruple3x5ThinningSkeleton2D}. * These algorithms have different "strength", so, using "stronger" classifier for "weaker" skeleton * (for example, using {@link #getStrongQuadruple3x5ThinningInstance()} for the resulting skeleton * of {@link OctupleThinningSkeleton2D} algorithm) can lead to recognition of some skeleton pixels as * "{@link #TYPE_ILLEGAL illegal}".

* *

This class is immutable and thread-safe: * there are no ways to modify settings of the created instance.

* * @author Daniel Alievsky */ public class BasicSkeletonPixelClassifier2D extends ApertureBasedSkeletonPixelClassifier { /*Repeat() XM_YM\s+=\s0 ==> YM = 1,,XP_YM = 2,,XP = 3,,XP_YP = 4,,YP = 5,,XM_YP = 6,,XM = 7 */ /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_XM_YM = 0; /*Repeat.AutoGeneratedStart !! Auto-generated: NOT EDIT !! */ /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_YM = 1; /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_XP_YM = 2; /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_XP = 3; /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_XP_YP = 4; /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_YP = 5; /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_XM_YP = 6; /** * {@value}: an index of the neighbour #{@value} of any element in terms of * {@link #neighbourOffset(int) neighbourOffset(int)} method. * It is one of possible non-negative values, returned by {@link #asPixelTypes asPixelTypes} method. * You can understand the sense of the name of this constant from the comments to these methods. */ public static final int NEIGHBOUR_INDEX_XM = 7; /*Repeat.AutoGeneratedEnd*/ /** * {@value}: minimal non-negative value, that can be returned by {@link #asPixelTypes asPixelTypes} method * in this class. */ public static final int NEIGHBOUR_INDEX_MIN = 0; /** * {@value}: maximal non-negative value, that can be returned by {@link #asPixelTypes asPixelTypes} method * in this class. */ public static final int NEIGHBOUR_INDEX_MAX = 7; private static final long[][] SHIFTS_A = { {-1, -1}, // A1 {0, -1}, // A2 {1, -1}, // A3 {1, 0}, // A4 {1, 1}, // A5 {0, 1}, // A6 {-1, 1}, // A7 {-1, 0}, // A8 }; private static final int[] OCTUPLE_THINNING_SKELETON_CLASSIFICATION_MAP = { // This constant contains of triplets: // the bits of 3x3 neighbourhood, // the negative pixel type or the index of the branch, to which this pixel should be attached, // the negative pixel type or the index of the node, from which this branch is originated. // This constant is applicable for OctupleThinningSkeleton2D and, with removing some configurations, // for Quadruple3x5ThinningSkeleton2D and StrongQuadruple3x5ThinningSkeleton2D. // For OctupleThinningSkeleton2D, 148 3x3 bit configurations in the skeleton are totally possible; // we'll give all them, usually with 5x5 neighbourhood, but without configurations, // which can be produced by rotation of the coordinate system. // // In bit configurations below: // "*" means the unit element (1), // "." means the zero element (0), // "?" (in 5x5 neighbourhood) means that this bit can be 0 in some configurations and 1 in others; // "O" means "?" for OctupleThinningSkeleton2D and "." for [Strong]Quadruple3x5ThinningSkeleton2D. // // Below "improbable" and "questionable" configurations are those bit sets 5x5, where the test // net.algart.matrices.skeletons.demo.AnalyseSkeletonConfigurations cannot guarantee that they are impossible; // all configurations besides possible, improbable and questionable are surely impossible. // We shall give all possible, improbable and questionable configurations of 5x5 neighbourhood // for OctupleThinningSkeleton2D/Quadruple3x5ThinningSkeleton2D and, if StrongQuadruple3x5ThinningSkeleton2D // has other configurations, give them separately (if StrongQuadruple3x5ThinningSkeleton2D has the same // possibilities as Quadruple3x5ThinningSkeleton2D, we don't comment this). // Note that "improbable" configurations have no relation to OctupleThinningSkeleton2D, but just to // Quadruple3x5ThinningSkeleton2D/StrongQuadruple3x5ThinningSkeleton2D. // (1/148) 0=0x0 (3x3, 1 unit bits): // . . . // . * . // . . . 0, TYPE_ISOLATED, TYPE_ISOLATED, // (2/148) 1=0x1 (3x3, 2 unit bits): // * . . // . * . // . . . 1, TYPE_FREE_BRANCH_END, TYPE_FREE_BRANCH_END, // (6/148) 2=0x2 (3x3, 2 unit bits): // . * . // . * . // . . . 2, TYPE_FREE_BRANCH_END, TYPE_FREE_BRANCH_END, // (10/148) 5=0x5 (3x3, 3 unit bits): // * . * // . * . // . . . 5, TYPE_USUAL_BRANCH, TYPE_USUAL_BRANCH, // (14/148) 9=0x9 (3x3, 3 unit bits): // * . . // . * * // . . . 9, TYPE_USUAL_BRANCH, TYPE_USUAL_BRANCH, // (18/148) 17=0x11 (3x3, 3 unit bits): // * . . // . * . // . . * 17, TYPE_USUAL_BRANCH, TYPE_USUAL_BRANCH, // (20/148) 18=0x12 (3x3, 3 unit bits): // . * . // . * . // . . * 18, TYPE_USUAL_BRANCH, TYPE_USUAL_BRANCH, // (24/148) 34=0x22 (3x3, 3 unit bits): // . * . // . * . // . * . 34, TYPE_USUAL_BRANCH, TYPE_USUAL_BRANCH, // (26/148) 13=0xD (3x3, 4 unit bits): // * . * // . * * // . . . // 13=0xD (3x3, 4 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * . // ? . . . * // ? ? ? ? ? // 13=0xD (3x3, 4 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * . * ? // ? . * * . // ? . . . * // ? ? ? ? ? 13, NEIGHBOUR_INDEX_XM_YM, NEIGHBOUR_INDEX_XP, // (30/148) 19=0x13 (3x3, 4 unit bits): // * * . // . * . // . . * // 19=0x13 (3x3, 4 unit bits) is possible inside the following series of 5x5 configurations // ? ? . * ? // ? * * . ? // ? . * . ? // ? . . * ? // ? ? ? ? ? // 19=0x13 (3x3, 4 unit bits) inside the following series of questionable 5x5 configurations // ? ? . * ? // ? * * . ? // ? . * . ? // ? . . * ? // ? ? ? ? ? 19, NEIGHBOUR_INDEX_XP_YP, NEIGHBOUR_INDEX_YM, // (34/148) 21=0x15 (3x3, 4 unit bits): // * . * // . * . // . . * 21, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (38/148) 22=0x16 (3x3, 4 unit bits): // . * * // . * . // . . * // 22=0x16 (3x3, 4 unit bits) is possible inside the following series of 5x5 configurations // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * ? // ? . * . O // ? . . * ? // ? ? ? ? ? // 22=0x16 (3x3, 4 unit bits) inside the following series of questionable 5x5 configurations // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * ? // ? . * . O // ? . . * ? // ? ? ? ? ? 22, NEIGHBOUR_INDEX_XP_YP, NEIGHBOUR_INDEX_YM, // (42/148) 25=0x19 (3x3, 4 unit bits): // * . . // . * * // . . * // 25=0x19 (3x3, 4 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . . * // ? . * * . // ? . . * ? // ? ? ? ? ? // 25=0x19 (3x3, 4 unit bits) inside the following series of questionable 5x5 configurations // ? ? ? ? ? // ? * . . * // ? . * * . // ? . . * ? // ? ? ? ? ? 25, NEIGHBOUR_INDEX_XM_YM, NEIGHBOUR_INDEX_XP, // (46/148) 35=0x23 (3x3, 4 unit bits): // * * . // . * . // . * . // 35=0x23 (3x3, 4 unit bits) is possible inside the following series of 5x5 configurations // ? ? . * ? // ? * * . ? // ? . * . ? // ? . * . ? // ? ? ? ? ? // 35=0x23 (3x3, 4 unit bits) inside the following series of questionable 5x5 configurations // ? ? . * ? // ? * * . ? // ? . * . ? // ? . * . ? // ? ? ? ? ? 35, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // (50/148) 37=0x25 (3x3, 4 unit bits): // * . * // . * . // . * . 37, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (54/148) 38=0x26 (3x3, 4 unit bits): // . * * // . * . // . * . // 38=0x26 (3x3, 4 unit bits) is possible inside the following series of 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? . * . ? // ? ? ? ? ? // 38=0x26 (3x3, 4 unit bits) inside the following series of questionable 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? . * . ? // ? ? ? ? ? 38, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // (58/148) 41=0x29 (3x3, 4 unit bits): // * . . // . * * // . * . 41, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (62/148) 23=0x17 (3x3, 5 unit bits): // * * * // . * . // . . * // 23=0x17 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? * O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . O // ? . . * ? // ? ? ? ? ? // 23=0x17 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? ? * O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . O // ? . . * ? // ? ? ? ? ? 23, NEIGHBOUR_INDEX_XP_YP, NEIGHBOUR_INDEX_YM, // (66/148) 29=0x1D (3x3, 5 unit bits): // * . * // . * * // . . * // 29=0x1D (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * * // ? . . * ? // ? ? ? ? ? // 29=0x1D (3x3, 5 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * . * ? // ? . * * * // ? . . * ? // ? ? ? ? ? // 29=0x1D (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? ? ? ? ? // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * * // ? . . * ? // ? ? ? ? ? 29, NEIGHBOUR_INDEX_XM_YM, NEIGHBOUR_INDEX_XP, // (70/148) 39=0x27 (3x3, 5 unit bits): // * * * // . * . // . * . // 39=0x27 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? * ? ? // ? * * * ? // ? . * . ? // ? . * . ? // ? ? ? ? ? // 39=0x27 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? ? * ? ? // ? * * * ? // ? . * . ? // ? . * . ? // ? ? ? ? ? 39, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // (74/148) 45=0x2D (3x3, 5 unit bits): // * . * // . * * // . * . // 45=0x2D (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * . // ? . * . * // ? ? ? ? ? // 45=0x2D (3x3, 5 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * . * . // ? . * * . // ? . * . * // ? ? ? ? ? // 45=0x2D (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? ? ? ? ? // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * . // ? . * . * // ? ? ? ? ? 45, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // together with symmetric configuration // (78/148) 51=0x33 (3x3, 5 unit bits): // * * . // . * . // . * * // 51=0x33 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? . * ? // ? * * . ? // ? . * . ? // ? . * * ? // ? * . ? ? // 51=0x33 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? ? . * ? // ? * * . ? // ? . * . ? // ? . * * ? // ? * . ? ? 51, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // 1-pixel branch // (80/148) 53=0x35 (3x3, 5 unit bits): // * . * // . * . // . * * // 53=0x35 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . * ? // ? . * . ? // ? . * * ? // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // 53=0x35 (3x3, 5 unit bits) inside the following series of improbable 5x5 configurations // ? ? ? ? ? // ? * . * ? // ? . * . ? // ? . * * ? // ? * . ? ? // 53=0x35 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? ? ? ? ? // ? * . * ? // ? . * . ? // ? . * * ? // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) 53, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (84/148) 54=0x36 (3x3, 5 unit bits): // . * * // . * . // . * * // 54=0x36 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? . * * ? // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // 54=0x36 (3x3, 5 unit bits) inside the following series of improbable 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . * // ? . * * . // ? * . ? . // 54=0x36 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? . * * ? // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) 54, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // 1-pixel branch // (88/148) 57=0x39 (3x3, 5 unit bits): // * . . // . * * // . * * // 57=0x39 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . . * // ? . * * . // ? . * * ? // ? * . ? ? // 57=0x39 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // * ? ? ? ? ? ? ? ? ? // ? * . . * ? * . . * // ? . * * . for OctupleThinningSkeleton2D, ? . * * . for [Strong]Quadruple3x5ThinningSkeleton2D // ? . * * ? ? . * * ? // ? * . ? ? ? * . ? ? 57, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (92/148) 85=0x55 (3x3, 5 unit bits): // * . * // . * . // * . * 85, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (93/148) 86=0x56 (3x3, 5 unit bits): // . * * // . * . // * . * // 86=0x56 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? * . * ? // ? ? ? ? ? // 86=0x56 (3x3, 5 unit bits) inside the following series of improbable 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? * . * ? // ? ? * * ? // 86=0x56 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? * . * ? // ? ? ? ? ? 86, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (97/148) 90=0x5A (3x3, 5 unit bits): // . * . // . * * // * . * // 90=0x5A (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * . * // ? . * * . // ? * . * O // ? ? O ? ? // 90=0x5A (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? ? ? O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * . * // ? . * * . // ? * . * O // ? ? O ? ? 90, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // together with symmetric configuration // (101/148) 102=0x66 (3x3, 5 unit bits): // . * * // . * . // * * . // 102=0x66 (3x3, 5 unit bits) is possible inside the following series of 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? * * . ? // ? ? . * ? // 102=0x66 (3x3, 5 unit bits) inside the following series of questionable 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * . ? // ? * * . ? // ? ? . * ? 102, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // 1-pixel branch // (103/148) 170=0xAA (3x3, 5 unit bits): // . * . // * * * // . * . 170, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (104/148) 55=0x37 (3x3, 6 unit bits): // * * * // . * . // . * * // 55=0x37 (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? ? * ? ? // ? * * * ? // ? . * . ? // ? . * * ? // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // 55=0x37 (3x3, 6 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * * * ? // ? . * . * // ? . * * . // ? * . ? . // 55=0x37 (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? ? * ? ? // ? * * * ? // ? . * . ? // ? . * * ? // ? * . O ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) 55, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // 1-pixel branch // (108/148) 61=0x3D (3x3, 6 unit bits): // * . * // . * * // . * * // In a case of OctupleThinningSkeleton2D/Quadruple3x5ThinningSkeleton2D: // 61=0x3D (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * * // ? . * * ? // ? * . ? ? // 61=0x3D (3x3, 6 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * . * . // ? . * * * // ? . * * ? // ? * . ? ? // 61=0x3D (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? ? ? ? ? // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? . * * * // ? . * * ? // ? * . ? ? // In a case of StrongQuadruple3x5ThinningSkeleton2D: // 61=0x3D (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? ? ? ? ? // ? * . * . // ? . * * * // ? . * * . // ? * . . * // 61=0x3D (3x3, 6 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * . * . // ? . * * * // ? . * * . // ? * . . * // 61=0x3D (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? ? ? ? ? // ? * . * . // ? . * * * // ? . * * . // ? * . . * 61, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (112/148) 87=0x57 (3x3, 6 unit bits): // * * * // . * . // * . * // 87=0x57 (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? O * ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . ? // ? * . * ? // ? ? ? ? ? // 87=0x57 (3x3, 6 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * * * ? // ? . * . ? // ? * . * ? // ? ? ? ? ? // 87=0x57 (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? O * ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . ? // ? * . * ? // ? ? ? ? ? 87, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // (116/148) 91=0x5B (3x3, 6 unit bits): // * * . // . * * // * . * // (91=0x5B is possible in OctupleThinningSkeleton2D only) // 91=0x5B (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? ? . * ? // ? * * . * // ? . * * . // ? * . * ? // ? ? ? ? ? // 91=0x5B (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? ? . * ? // ? * * . * // ? . * * . // ? * . * ? // ? ? ? ? ? 91, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // don't attach to the left down one to avoid asymmetry while finding the originating node // (120/148) 94=0x5E (3x3, 6 unit bits): // . * * // . * * // * . * // In a case of OctupleThinningSkeleton2D/Quadruple3x5ThinningSkeleton2D: // 94=0x5E (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * * * // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? ? O ? ? // 94=0x5E (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? * . ? ? // ? . * * ? // ? . * * * // ? * . * O ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? ? O ? ? // In a case of StrongQuadruple3x5ThinningSkeleton2D: // 94=0x5E (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? * . . * // ? . * * . // ? . * * * // ? * . * . // ? ? . ? ? // 94=0x5E (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? * . . * // ? . * * . // ? . * * * // ? * . * . // ? ? . ? ? 94, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (124/148) 103=0x67 (3x3, 6 unit bits): // * * * // . * . // * * . // 103=0x67 (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? O * ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . ? // ? * * . ? // ? ? . * ? // 103=0x67 (3x3, 6 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // . * * * ? // * . * . ? // ? * * . ? // ? ? . * ? // 103=0x67 (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? O * ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . ? // ? * * . ? // ? ? . * ? 103, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // 1-pixel branch // (128/148) 171=0xAB (3x3, 6 unit bits): // * * . // * * * // . * . // 171=0xAB (3x3, 6 unit bits) is possible inside the following series of 5x5 configurations // ? ? . * ? // ? * * . ? // . * * * ? // * . * . ? // ? O ? ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // 171=0xAB (3x3, 6 unit bits) inside the following series of questionable 5x5 configurations // ? ? . * ? // ? * * . ? // . * * * ? // * . * . ? // ? O ? ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) 171, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (132/148) 95=0x5F (3x3, 7 unit bits): // * * * // . * * // * . * // In a case of OctupleThinningSkeleton2D/Quadruple3x5ThinningSkeleton2D: // 95=0x5F (3x3, 7 unit bits) is possible inside the following series of 5x5 configurations // ? O * O * ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * O // ? . * * * // ? * . * O // ? ? . ? ? // 95=0x5F (3x3, 7 unit bits) inside the following series of improbable 5x5 configurations // ? . * ? * // ? * * * ? // * . * * * // ? * . * . // ? ? . ? ? // 95=0x5F (3x3, 7 unit bits) inside the following series of questionable 5x5 configurations // ? O * O * ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * O // ? . * * * // ? * . * O // ? ? . ? ? // In a case of StrongQuadruple3x5ThinningSkeleton2D: // 95=0x5F (3x3, 7 unit bits) is possible inside the following series of 5x5 configurations // (no differences) // 95=0x5F (3x3, 7 unit bits) inside the following series of improbable 5x5 configurations // ? . * . * // ? * * * . // * . * * * // ? * . * . // ? ? . ? ? // 95=0x5F (3x3, 7 unit bits) inside the following series of questionable 5x5 configurations // ? . * . * // ? * * * . // ? . * * * // ? * . * . // ? ? . ? ? 95, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (136/148) 119=0x77 (3x3, 7 unit bits): // * * * // . * . // * * * // 119=0x77 (3x3, 7 unit bits) is possible inside the following series of 5x5 configurations // ? O * ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . ? // ? * * * ? // ? ? * O ? // 119=0x77 (3x3, 7 unit bits) inside the following series of improbable 5x5 configurations // ? ? * ? ? // ? * * * ? // ? . * . ? // ? * * * ? // ? ? * ? ? // 119=0x77 (3x3, 7 unit bits) inside the following series of questionable 5x5 configurations // ? O * ? ? ("O" means "?" for OctupleThinningSkeleton2D, "." for others) // ? * * * ? // ? . * . ? // ? * * * ? // ? ? * O ? 119, NEIGHBOUR_INDEX_YP, NEIGHBOUR_INDEX_YM, // 1-pixel branch // (138/148) 175=0xAF (3x3, 7 unit bits): // * * * // * * * // . * . // (175=0xAF is possible in OctupleThinningSkeleton2D and Quadruple3x5ThinningSkeleton2D only) // In a case of OctupleThinningSkeleton2D: // 175=0xAF (3x3, 7 unit bits) is possible inside the following series of 5x5 configurations // ? ? * ? ? // ? * * * ? // . * * * . // * . * . * // ? ? ? ? ? // 175=0xAF (3x3, 7 unit bits) inside the following series of questionable 5x5 configurations // ? ? * ? ? // ? * * * ? // . * * * . // * . * . * // ? ? ? ? ? // In a case of Quadruple3x5ThinningSkeleton2D/StrongQuadruple3x5ThinningSkeleton2D: // 175=0xAF (3x3, 7 unit bits) is possible inside the following series of 5x5 configurations // * . * . * // . * * * . // . * * * . // * . * . * // ? . * . ? // 175=0xAF (3x3, 7 unit bits) inside the following series of questionable 5x5 configurations // ? ? * ? ? // ? * * * ? // . * * * . // * . * . * // ? . * ? ? 175, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (142/148) 187=0xBB (3x3, 7 unit bits): // * * . // * * * // . * * // (187=0xBB is possible in OctupleThinningSkeleton2D only) // 187=0xBB (3x3, 7 unit bits) is possible inside the following series of 5x5 configurations // ? ? . * ? // ? * * . * // . * * * . // * . * * ? // ? * . ? ? 187, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (144/148) 191=0xBF (3x3, 8 unit bits): // * * * // * * * // . * * // (191=0xBF is possible in OctupleThinningSkeleton2D only) // 191=0xBF (3x3, 8 unit bits) is possible inside the following series of 5x5 configurations // ? ? * ? ? // ? * * * ? // . * * * * // * . * * ? // ? * . ? ? // 191=0xBF (3x3, 8 unit bits) inside the following series of questionable 5x5 configurations // ? ? * ? ? // ? * * * ? // . * * * * // * . * * ? // ? * . ? ? 191, TYPE_USUAL_NODE, TYPE_USUAL_NODE, // always consider 2x2, 2x3, 3x2 and 3x3 unit areas as nodes // (148/148) 255=0xFF (3x3, 9 unit bits): // * * * // * * * // * * * // (255=0xFF is possible in OctupleThinningSkeleton2D and Quadruple3x5ThinningSkeleton2D only) // In a case of OctupleThinningSkeleton2D: // 255=0xFF (3x3, 9 unit bits) is possible inside the following series of 5x5 configurations // ? ? * ? ? // ? * * * ? // * * * * * // ? * * * ? // ? ? * ? ? // 255=0xFF (3x3, 9 unit bits) inside the following series of questionable 5x5 configurations // ? ? * ? ? // ? * * * ? // * * * * * // ? * * * ? // ? ? * ? ? // In a case of Quadruple3x5ThinningSkeleton2D/StrongQuadruple3x5ThinningSkeleton2D: // 255=0xFF (3x3, 9 unit bits) is possible inside the following series of 5x5 configurations // * . * . * // . * * * . // * * * * * // . * * * . // * . * . * 255, TYPE_USUAL_NODE, TYPE_USUAL_NODE, }; private static final BasicSkeletonPixelClassifier2D BASIC_OCTUPLE_THINNING_SKELETON_PIXEL_CLASSIFIER_2_D = new BasicSkeletonPixelClassifier2D( OCTUPLE_THINNING_SKELETON_CLASSIFICATION_MAP), BASIC_QUADRUPLE_3X5_THINNING_SKELETON_PIXEL_CLASSIFIER_2_D = new BasicSkeletonPixelClassifier2D( OCTUPLE_THINNING_SKELETON_CLASSIFICATION_MAP, 91, 187, 191), BASIC_STRONG_QUADRUPLE_3X5_THINNING_SKELETON_PIXEL_CLASSIFIER_2_D = new BasicSkeletonPixelClassifier2D( OCTUPLE_THINNING_SKELETON_CLASSIFICATION_MAP, 91, 187, 191, 175, 255); private final int[] classificationTableWithAttachingBranches = new int[256]; private final int[] classificationTableWithAttachedNodes = new int[256]; private BasicSkeletonPixelClassifier2D(int[] classificationMap, int... additionalIllegalConfigurations) { super(2, SHIFTS_A); Objects.requireNonNull(classificationMap, "Null classificationMap argument"); if (classificationMap.length % 3 != 0) { throw new IllegalArgumentException("Length of classificationMap does not divide by 3"); } JArrays.fill(this.classificationTableWithAttachingBranches, TYPE_ILLEGAL); JArrays.fill(this.classificationTableWithAttachedNodes, TYPE_ILLEGAL); for (int k = 0; k < classificationMap.length; k += 3) { int bitsA = classificationMap[k]; if (bitsA < 0 || bitsA > 255) { throw new IllegalArgumentException("First element of a triplet " + "in classificationMap (bit configuration code) is out of 0..255 range"); } int pixelTypeWithAttachingBranch = classificationMap[k + 1]; if (pixelTypeWithAttachingBranch > NEIGHBOUR_INDEX_MAX) { throw new IllegalArgumentException("Second element of a triplet " + "in classificationMap (pixel type or direction of attaching branch end) " + "is greater than " + NEIGHBOUR_INDEX_MAX); } int pixelTypeWithAttachedNode = classificationMap[k + 2]; if (pixelTypeWithAttachedNode > NEIGHBOUR_INDEX_MAX) { throw new IllegalArgumentException("Third element of a triplet " + "in classificationMap (pixel type or direction of attached node) " + "is greater than " + NEIGHBOUR_INDEX_MAX); } if ((pixelTypeWithAttachingBranch < 0 || pixelTypeWithAttachedNode < 0) && pixelTypeWithAttachedNode != pixelTypeWithAttachingBranch) { throw new IllegalArgumentException("Negative second and third elements of a triplet " + "in classificationMap (pixel type or direction of attached node) are not equal: " + pixelTypeWithAttachingBranch + " and " + pixelTypeWithAttachedNode); } this.classificationTableWithAttachingBranches[bitsA] = pixelTypeWithAttachingBranch; this.classificationTableWithAttachedNodes[bitsA] = pixelTypeWithAttachedNode; for (int directionIndex = 1; directionIndex <= 3; directionIndex++) { bitsA = rotated90BitsA(bitsA); pixelTypeWithAttachingBranch = rotated90Direction(pixelTypeWithAttachingBranch); pixelTypeWithAttachedNode = rotated90Direction(pixelTypeWithAttachedNode); this.classificationTableWithAttachingBranches[bitsA] = pixelTypeWithAttachingBranch; this.classificationTableWithAttachedNodes[bitsA] = pixelTypeWithAttachedNode; } } for (int bitsA : additionalIllegalConfigurations) { this.classificationTableWithAttachingBranches[bitsA] = TYPE_ILLEGAL; this.classificationTableWithAttachedNodes[bitsA] = TYPE_ILLEGAL; for (int directionIndex = 1; directionIndex <= 3; directionIndex++) { bitsA = rotated90BitsA(bitsA); this.classificationTableWithAttachingBranches[bitsA] = TYPE_ILLEGAL; this.classificationTableWithAttachedNodes[bitsA] = TYPE_ILLEGAL; } } } /*Repeat() OctupleThinning ==> Quadruple3x5Thinning,,StrongQuadruple3x5Thinning;; OCTUPLE_THINNING ==> QUADRUPLE_3X5_THINNING,,STRONG_QUADRUPLE_3X5_THINNING */ /** * Returns the instance of this class, intended for processing skeletons, which are * the final result of skeletonization by {@link OctupleThinningSkeleton2D} algorithm. * * @return the classifier of pixels of {@link OctupleThinningSkeleton2D} skeletons. */ public static BasicSkeletonPixelClassifier2D getOctupleThinningInstance() { return BASIC_OCTUPLE_THINNING_SKELETON_PIXEL_CLASSIFIER_2_D; } /*Repeat.AutoGeneratedStart !! Auto-generated: NOT EDIT !! */ /** * Returns the instance of this class, intended for processing skeletons, which are * the final result of skeletonization by {@link Quadruple3x5ThinningSkeleton2D} algorithm. * * @return the classifier of pixels of {@link Quadruple3x5ThinningSkeleton2D} skeletons. */ public static BasicSkeletonPixelClassifier2D getQuadruple3x5ThinningInstance() { return BASIC_QUADRUPLE_3X5_THINNING_SKELETON_PIXEL_CLASSIFIER_2_D; } /** * Returns the instance of this class, intended for processing skeletons, which are * the final result of skeletonization by {@link StrongQuadruple3x5ThinningSkeleton2D} algorithm. * * @return the classifier of pixels of {@link StrongQuadruple3x5ThinningSkeleton2D} skeletons. */ public static BasicSkeletonPixelClassifier2D getStrongQuadruple3x5ThinningInstance() { return BASIC_STRONG_QUADRUPLE_3X5_THINNING_SKELETON_PIXEL_CLASSIFIER_2_D; } /*Repeat.AutoGeneratedEnd*/ @Override protected int pixelTypeOrAttachingBranch(int apertureBits) { return classificationTableWithAttachingBranches[apertureBits]; } @Override protected int pixelTypeOrAttachedNode(int apertureBits) { return classificationTableWithAttachedNodes[apertureBits]; } // bit index: // A A A 0 1 2 // A * A 7 * 3 // A A A 6 5 4 private static int rotated90BitsA(int apertureBits) { assert 0 <= apertureBits && apertureBits < 256; int bit0 = apertureBits & 1; int bit1 = (apertureBits >> 1) & 1; int bit2 = (apertureBits >> 2) & 1; int bit3 = (apertureBits >> 3) & 1; int bit4 = (apertureBits >> 4) & 1; int bit5 = (apertureBits >> 5) & 1; int bit6 = (apertureBits >> 6) & 1; int bit7 = (apertureBits >> 7) & 1; return bit6 | (bit7 << 1) | (bit0 << 2) | (bit1 << 3) | (bit2 << 4) | (bit3 << 5) | (bit4 << 6) | (bit5 << 7); } // pixelType: // A A A 0 1 2 // A * A 7 * 3 // A A A 6 5 4 private static int rotated90Direction(int pixelType) { if (pixelType < 0) { return pixelType; } return (pixelType + 2) & 7; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy