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

net.algart.matrices.morphology.BasicRankMorphology 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.morphology;

import net.algart.arrays.*;
import net.algart.math.functions.Func;
import net.algart.math.patterns.Pattern;
import net.algart.matrices.StreamingApertureProcessor;

import java.util.Objects;

/**
 * 

Almost complete implementation of {@link RankMorphology} interface with an instantiation method * of some complete implementation.

* *

This class fully implements all methods, declared in {@link RankMorphology} interface, * according to the detailed specifications listed in the comments to that interface. * The only methods, which stay abstract here, are the following 3 methods of {@link AbstractMorphology} * superclass:

* *
    *
  • {@link #context(ArrayContext newContext)},
  • *
  • {@link #asDilationOrErosion(Matrix src, Pattern pattern, boolean isDilation)},
  • *
  • {@link * #dilationOrErosion(Matrix dest, Matrix src, Pattern pattern, boolean isDilation, boolean disableMemoryAllocation)}. *
  • *
* *

All other methods are implemented via the simple calls of * {@link StreamingApertureProcessor#asProcessed(Class, Matrix, java.util.List, Pattern) asProcessed} * and {@link StreamingApertureProcessor#process(Matrix, Matrix, java.util.List, Pattern) process} * method of the corresponding streaming aperture processors, listed in {@link RankProcessors} class.

* *

This package provides some concrete complete inheritor, which implements also these 3 methods. * This inheritor is instantiated by the following method:

* *
    *
  • {@link #getInstance(ArrayContext, double, CustomRankPrecision)}.
  • *
* *

But you can also inherit this class yourself and implement dilation and erosion (the basic operations * of the mathematical morphology) in other way.

* * @author Daniel Alievsky */ public abstract class BasicRankMorphology extends AbstractRankMorphology implements RankMorphology { final boolean interpolated; final int[] bitLevels; // we never change them, so the standard cloning scheme is suitable BasicRankMorphology(ArrayContext context, boolean interpolated, int[] bitLevels) { super(context); Objects.requireNonNull(bitLevels, "Null bitLevels argument"); this.bitLevels = bitLevels.clone(); this.interpolated = interpolated; RankProcessors.getPercentiler(null, interpolated, this.bitLevels); // checking bitLevels } /** * Returns new instance of some inheritor of this class, implementing dilation and erosion operations * via the percentiles. Namely, in the created object * {@link #dilation(Matrix, Pattern) dilation}(m,pattern) method is equivalent to * {@link #percentile(Matrix, double, Pattern) * percentile}(m,dilationLevel*N,pattern) and * {@link #erosion(Matrix, Pattern) erosion}(m,pattern) method is equivalent to * {@link #percentile(Matrix, double, Pattern) * percentile}(m,dilationLevel*N,pattern.{@link Pattern#symmetric() symmetric()}), * where N=pattern.{@link Pattern#pointCount() pointCount()}-1 * and dilationLevel is the argument of this method. This argument must be in range * 0.0 ≤ dilationLevel ≤ 1.0. * *

More precisely, in the created object the methods *

    *
  1. {@link #asDilationOrErosion(Matrix src, Pattern pattern, boolean isDilation)} and
  2. *
  3. {@link * #dilationOrErosion(Matrix dest, Matrix src, Pattern pattern, boolean isDilation, boolean disableMemoryAllocation)} *
  4. *
*

work in the following way. * *

Let the double value r be * r=dilationLevel*(pattern.{@link Pattern#pointCount() pointCount()}-1) * in a case of dilation (isDilation argument is true) or * r=(1.0-dilationLevel)*(pattern.{@link Pattern#pointCount() pointCount()}-1) * in a case of erosion (isDilation argument is false). * Then, let index be: *

    *
  • this double value index=r, if the element type of * the source matrix src is float or double or * if we are using the precise histogram model * (precision.{@link CustomRankPrecision#interpolated() interpolated()} is true);
  • *
  • or the rounded (long) integer value index=Math.round(r), * if the source matrix is fixed-point and we are using the simple histogram model * (precision.{@link CustomRankPrecision#interpolated() interpolated()} is false).
  • *
* *

At last, let P be pattern * in a case of dilation (isDilation argument is true) * or pattern.{@link Pattern#symmetric() symmetric()} * in a case of erosion (isDilation argument is false). * *

Then, in the returned object the 1st method * {@link #asDilationOrErosion(Matrix, Pattern, boolean) asDilationOrErosion} * is equivalent to * {@link #asPercentile(Matrix, double, Pattern) asPercentile}(src,index,P) * and the 2nd method {@link #dilationOrErosion(Matrix, Matrix, Pattern, boolean, boolean) dilationOrErosion} * is equivalent to * {@link #percentile(Matrix, Matrix, double, Pattern) percentile}(dest,src,index,P). * (The disableMemoryAllocation argument of * {@link #dilationOrErosion(Matrix, Matrix, Pattern, boolean, boolean) dilationOrErosion} method * is ignored by this implementation.) * *

Please note: using Math.round for rounding the percentile index does not correspond * to the standard behaviour of integer percentiles, which are rounded, in a case of the precise histogram model, * according more complicated rules (see comments to * {@link RankMorphology#percentile(Matrix, Matrix, Pattern)} and * {@link Histogram#iPreciseValue(long[], double)} methods). * So, this method does not try to round the real percentile index r in the precise histogram model. * But in the simple histogram model, when the element type is fixed-point and some form of rounding is required * in any case, this method calls Math.round — it provides * better "symmetry" between dilation and erosion operations. * *

The precise behaviour of all methods of {@link RankMorphology} interface in the returned object * depends on precision object: see comments to {@link CustomRankPrecision} and * {@link RankMorphology}. * * @param context the {@link #context() context} that will be used by this object; * can be {@code null}, then it will be ignored. * @param dilationLevel the level: 1.0 means strict dilation and erosion as described in {@link Morphology} * interface, 0.5 means median, 0.0 means that dilation works like erosion and erosion * works like dilation (but with a {@link Pattern#symmetric() symmetric} pattern). * @param precision precision characteristics of all rank operations, performed by the created object. * @return new instance of this class. * @throws NullPointerException if precision argument is {@code null} * @throws IllegalArgumentException if the dilationLevel argument * is out of 0.0..1.0 range * of if bitLevels=precision.{@link CustomRankPrecision#bitLevels() * bitLevels()} are incorrect: * bitLevels.length==0, or if bitLevels.length>31, * or if some of the elements bitLevels is not in 1..30 range, or if * bitLevels[k]>=bitLevels[k+1] * for some k. */ public static RankMorphology getInstance( ArrayContext context, double dilationLevel, CustomRankPrecision precision) { return new FixedPercentileRankMorphology(context, dilationLevel, precision.interpolated(), precision.bitLevels()); } @Override public boolean isPseudoCyclic() { return true; } @Override protected abstract Matrix asDilationOrErosion( Matrix src, Pattern pattern, boolean isDilation); @Override protected abstract Matrix dilationOrErosion( Matrix dest, Matrix src, Pattern pattern, boolean isDilation, boolean disableMemoryAllocation); @Override public Matrix asPercentile( Matrix src, Matrix percentileIndexes, Pattern pattern) { StreamingApertureProcessor percentiler = RankProcessors.getPercentiler(context(), interpolated, bitLevels); return percentiler.asProcessed(src.array().type(), src, percentileIndexes, pattern); } @Override public void percentile( Matrix dest, Matrix src, Matrix percentileIndexes, Pattern pattern) { StreamingApertureProcessor percentiler = RankProcessors.getPercentiler(context(), interpolated, bitLevels); percentiler.process(dest, src, percentileIndexes, pattern); } @Override public Matrix asRank( Class requiredType, Matrix baseMatrix, Matrix rankedMatrix, Pattern pattern) { StreamingApertureProcessor ranker = RankProcessors.getRanker(context(), interpolated && PFloatingArray.class.isAssignableFrom(requiredType), bitLevels); // if requiredType is not floating-point, interpolation leads to the same ranks return ranker.asProcessed(requiredType, baseMatrix, rankedMatrix, pattern); } @Override public void rank( Matrix dest, Matrix baseMatrix, Matrix rankedMatrix, Pattern pattern) { StreamingApertureProcessor ranker = RankProcessors.getRanker(context(), interpolated && PFloatingArray.class.isAssignableFrom(dest.type()), bitLevels); // if dest.type() is not floating-point, interpolation leads to the same ranks ranker.process(dest, baseMatrix, rankedMatrix, pattern); } @Override public Matrix asMeanBetweenPercentiles( Matrix src, Matrix fromPercentilesIndexes, Matrix toPercentilesIndexes, Pattern pattern, double filler) { StreamingApertureProcessor averager = RankProcessors.getAveragerBetweenPercentiles(context(), filler, interpolated, bitLevels); return averager.asProcessed(src.array().type(), src, fromPercentilesIndexes, toPercentilesIndexes, pattern); } @Override public void meanBetweenPercentiles( Matrix dest, Matrix src, Matrix fromPercentilesIndexes, Matrix toPercentilesIndexes, Pattern pattern, double filler) { StreamingApertureProcessor averager = RankProcessors.getAveragerBetweenPercentiles(context(), filler, interpolated, bitLevels); averager.process(dest, src, fromPercentilesIndexes, toPercentilesIndexes, pattern); } @Override public Matrix asMeanBetweenValues( Matrix src, Matrix minValues, Matrix maxValues, Pattern pattern, double filler) { StreamingApertureProcessor averager = RankProcessors.getAveragerBetweenValues(context(), filler, interpolated, bitLevels); return averager.asProcessed(src.array().type(), src, minValues, maxValues, pattern); } @Override public void meanBetweenValues( Matrix dest, Matrix src, Matrix minValues, Matrix maxValues, Pattern pattern, double filler) { StreamingApertureProcessor averager = RankProcessors.getAveragerBetweenValues(context(), filler, interpolated, bitLevels); averager.process(dest, src, minValues, maxValues, pattern); } @Override public Matrix asFunctionOfSum( Matrix src, Pattern pattern, Func processingFunc) { StreamingApertureProcessor averager = RankProcessors.getSummator(context(), processingFunc); return averager.asProcessed(src.array().type(), src, pattern); } @Override public void functionOfSum( Matrix dest, Matrix src, Pattern pattern, Func processingFunc) { StreamingApertureProcessor averager = RankProcessors.getSummator(context(), processingFunc); averager.process(dest, src, pattern); } @Override public Matrix asFunctionOfPercentilePair( Matrix src, Matrix percentilesIndexes1, Matrix percentilesIndexes2, Pattern pattern, Func processingFunc) { StreamingApertureProcessor contraster = RankProcessors.getPercentilePairProcessor(context(), processingFunc, interpolated, bitLevels); return contraster.asProcessed(src.array().type(), src, src, percentilesIndexes1, percentilesIndexes2, pattern); } @Override public void functionOfPercentilePair( Matrix dest, Matrix src, Matrix percentilesIndexes1, Matrix percentilesIndexes2, Pattern pattern, Func processingFunc) { StreamingApertureProcessor contraster = RankProcessors.getPercentilePairProcessor(context(), processingFunc, interpolated, bitLevels); contraster.process(dest, src, src, percentilesIndexes1, percentilesIndexes2, pattern); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy