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

net.algart.maps.pyramids.io.api.PlanePyramidSource Maven / Gradle / Ivy

Go to download

Open-source libraries, providing the base functions for SciChains product in area of computer vision.

There is a newer version: 4.4.10
Show newest version
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017-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.maps.pyramids.io.api;

import net.algart.arrays.Arrays;
import net.algart.arrays.Matrices;
import net.algart.arrays.Matrix;
import net.algart.arrays.PArray;
import net.algart.maps.pyramids.io.api.sources.DefaultPlanePyramidSource;
import net.algart.math.IPoint;
import net.algart.math.IRectangularArea;
import net.algart.math.functions.Func;

import java.nio.channels.NotYetConnectedException;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.OptionalDouble;

public interface PlanePyramidSource {
    int DIM_BAND = 0;
    int DIM_WIDTH = 1;
    int DIM_HEIGHT = 2;
    // - note: we don't call this "DIM_X/Y", because in usual matrices dimX is dim(0)

    int DEFAULT_COMPRESSION = Math.max(2,
            Arrays.SystemSettings.getIntProperty(
                    "net.algart.maps.pyramids.io.defaultPyramidCompression", 4));
    long DEFAULT_TILE_DIM = Math.max(16,
            Arrays.SystemSettings.getLongProperty(
                    "net.algart.maps.pyramids.io.tile", 1024));
    long DEFAULT_MINIMAL_PYRAMID_SIZE = 8;

    enum SpecialImageKind {
        /**
         * No image.
         *
         * 

When passed to {@link #readSpecialMatrix(SpecialImageKind)} method, * the result is always empty ({@link Optional#empty()}). */ NONE, /** * Coarse image of the full slide. Usually contains the {@link #LABEL_ONLY_IMAGE label} as a part. * *

Some implementations of {@link PlanePyramidSource} can use it automatically * as the background for the pyramid data. */ WHOLE_SLIDE, /** * Coarse image with all existing pyramid data. Never contains the {@link #LABEL_ONLY_IMAGE label}. * May be used, for example, for visual navigation goals. */ MAP_IMAGE, /** * The label image: a little photo of some paper on the scan * with printed or written information about the slide. */ LABEL_ONLY_IMAGE, /** * The thumbnail: something like {@link #MAP_IMAGE}, but containing the same information as a regular * pyramid (while {@link #MAP_IMAGE} may contain other coarse data). Usually generated automatically * by scanner software and looks like last available levels. */ THUMBNAIL_IMAGE, /** * Simplest universal thumbnail: the last (smallest) available level of the full image. * When passed to {@link #readSpecialMatrix(SpecialImageKind)} method, * the result is always the full image, returned by * {@link #readFullMatrix readFullMatrix}(numberOfResolutions()-1). * *

You may use this variant instead of any other special kind, if * {@link #isSpecialMatrixSupported(SpecialImageKind)} * informs that a kind is not supported (though it is not a good idea for replacement of * {@link #LABEL_ONLY_IMAGE}). * But you need to remember that some pyramids has only large layers, so this "thumbnail" * can be very large. * *

For this kind, result of {@link #readSpecialMatrix(SpecialImageKind)} method is never empty. */ SMALLEST_LAYER, /** * Some format-specific special image. * *

If the format does not provide such an image, * {@link #readSpecialMatrix(SpecialImageKind)} method returns the empty result for this kind * ({@link Optional#empty()}). */ CUSTOM_KIND_1, /** * Some format-specific special image. * *

If the format does not provide such an image, * {@link #readSpecialMatrix(SpecialImageKind)} method returns the empty result for this kind * ({@link Optional#empty()}). */ CUSTOM_KIND_2, /** * Some format-specific special image. * *

If the format does not provide such an image, * {@link #readSpecialMatrix(SpecialImageKind)} method returns the empty result for this kind * ({@link Optional#empty()}). */ CUSTOM_KIND_3, /** * Some format-specific special image. * *

If the format does not provide such an image, * {@link #readSpecialMatrix(SpecialImageKind)} method returns the empty result for this kind * ({@link Optional#empty()}). */ CUSTOM_KIND_4, /** * Some format-specific special image. * *

If the format does not provide such an image, * {@link #readSpecialMatrix(SpecialImageKind)} method returns the empty result for this kind * ({@link Optional#empty()}). */ CUSTOM_KIND_5, /** * Impossible image kind, that should be never returned for correct special images, but can be returned * by some methods to indicate special situation (for example, when it is not a special image). * *

When passed to {@link #readSpecialMatrix(SpecialImageKind)} method, * the result is always empty ({@link Optional#empty()}), as for {@link #NONE} kind. */ INVALID } enum FlushMode { /** * Like {@link #STANDARD}, but permits loss of some data. * Can be useful, for example, if you want to cancel long-time operation * that writes some large object. */ QUICK_WITH_POSSIBLE_LOSS_OF_DATA() { @Override public boolean dataMustBeFlushed() { return false; } @Override public boolean forcePhysicalWriting() { return false; } @Override public boolean flushLongTermResources() { return false; } }, /** * Usual flushing, suitable for close() and similar methods. * Should close associated files, flush non-written data to disk etc. */ STANDARD() { @Override public boolean dataMustBeFlushed() { return true; } @Override public boolean forcePhysicalWriting() { return false; } @Override public boolean flushLongTermResources() { return false; } }, /** * Forces strong freeing any resources, associated with this object and with a group of similar objects. * If some buffers are not written yet to disk, should enforce physical flushing them to disk by means of * corresponding OS calls. If there are some service threads, necessary for correct work with this type * of sources and created automatically while using this source, should try to stop these threads. * However, next usage of this kind of sources after such flushing may require additional time. * *

This mode is suitable if the user wants to finish working with his task, for example, closes * the window or stops an application. Note: pyramid sources, based on SCIFIO library * (until version 0.44 including), must use this flushing mode, in other case * that library will prevent closing the application. */ FLUSH_LONG_TERM_RESOURCES() { @Override public boolean dataMustBeFlushed() { return true; } @Override public boolean forcePhysicalWriting() { return true; } @Override public boolean flushLongTermResources() { return true; } }; public abstract boolean dataMustBeFlushed(); public abstract boolean forcePhysicalWriting(); public abstract boolean flushLongTermResources(); } enum AveragingMode { /** * For binary data means simple, for other types means averaging. * Note that in a case of BIT_TO_BYTE the source data are already converted to bytes (if a pyramid * contains more than 1 level). * Recommended for algorithmic needs. */ DEFAULT, /** * For binary data means conversion to bytes + averaging, for other types means averaging. * Recommended for viewers. */ AVERAGING, /** * Step decimation. Never averages pixels. */ SIMPLE, /** * Like {@link #MIN}, but affects binary data only (for other types performs averaging). */ AND, /** * Like {@link #MAX}, but affects binary data only (for other types performs averaging). */ OR, MIN, MAX; public Matrices.ResizingMethod averagingMethod(Matrix matrix) { switch (this) { case AND: if (matrix.elementType() != boolean.class) { break; } // else equivalent to the following MIN case MIN: return AveragingMode.AVERAGING_MIN; case OR: if (matrix.elementType() != boolean.class) { break; } // else equivalent to the following MAX case MAX: return AveragingMode.AVERAGING_MAX; case DEFAULT: case AVERAGING: if (matrix.elementType() != boolean.class) { break; } else { return Matrices.ResizingMethod.SIMPLE; } case SIMPLE: return Matrices.ResizingMethod.SIMPLE; } return Matrices.ResizingMethod.POLYLINEAR_AVERAGING; } private static final Matrices.ResizingMethod.Averaging AVERAGING_MIN = new Matrices.ResizingMethod.Averaging(Matrices.InterpolationMethod.STEP_FUNCTION) { @Override protected Func getAveragingFunc(long[] apertureDim) { return Func.MIN; } }; private static final Matrices.ResizingMethod.Averaging AVERAGING_MAX = new Matrices.ResizingMethod.Averaging(Matrices.InterpolationMethod.STEP_FUNCTION) { @Override protected Func getAveragingFunc(long[] apertureDim) { return Func.MAX; } }; } int numberOfResolutions(); // Relation of sizes of the level #k and the level #k+1 int compression(); // Usually 1, 3, 4; must be positive; works very quickly int bandCount(); boolean[] getResolutionLevelsAvailability(); boolean isResolutionLevelAvailable(int resolutionLevel); /** *

Returns dimensions of any pyramid level. Number of elements in the result arrays is always 3:

*
    *
  • first element result[0] is always equal to {@link #bandCount()};
  • *
  • the element result[{@link #DIM_WIDTH}] is the x-dimension of the level in pixels; *
  • the element result[{@link #DIM_HEIGHT}] is the y-dimension of the level in pixels. *
* *

This method always returns a new Java array and never returns a reference to an internal field.

* * @param resolutionLevel the level of pyramid; zero level (resolutionLevel=0) corresponds * to the best resolution. * @return dimensions of the specified pyramid level. * @throws NoSuchElementException if !{@link #isResolutionLevelAvailable(int) * isResolutionLevelAvailable(resolutionLevel)} */ long[] dimensions(int resolutionLevel) throws NoSuchElementException; /** * Returns the dimension #index of the given pyramid level. * Equivalent to {@link #dimensions(int) dimensions(resolutionLevel)}[index], * but works faster. * * @param index the index of dimension. * @return the dimension #index of this level. * @throws IndexOutOfBoundsException if index<0 or index>2. */ default long dim(int resolutionLevel, int index) { return dimensions(resolutionLevel)[index]; } default long width(int resolutionLevel) { return dim(resolutionLevel, DIM_WIDTH); } default long height(int resolutionLevel) { return dim(resolutionLevel, DIM_HEIGHT); } /** * Returns true if {@link #elementType()} method works properly. * In other case, that method throws UnsupportedOperationException. * In particular, returns true in {@link DefaultPlanePyramidSource}. * * @return whether {@link #elementType()} is supported. */ boolean isElementTypeSupported(); Class elementType() throws UnsupportedOperationException; default OptionalDouble pixelSizeInMicrons() { return OptionalDouble.empty(); } default OptionalDouble magnification() { return OptionalDouble.empty(); } /** *

Returns a set of all areas, which are 2D rectangles, filled by actual data, at the zero level. * All other areas should be considered to be a background and may be not passed to * image analysis algorithms.

* *

Some pyramids, including the default implementation in {@link AbstractPlanePyramidSource}, do not * support this feature. In this case, the method returns null. This situation may be * interpreted as if we have only 1 actual area, corresponding to the whole pyramid * from (0, 0) to ({@link #dimensions(int) dimensions}(0)[{@link #DIM_WIDTH}]−1, * {@link #dimensions(int) dimensions}(0)[{@link #DIM_HEIGHT}]−1).

* * @return a list of all areas (2D rectangles), filled by actual data, at the level #0, * or null if it is not supported. */ default List zeroLevelActualRectangles() { return null; } /** *

Returns a set of all areas, filled by actual data, at the zero level, in a form of a list * of polygons, represented by their consecutive vertices. * All other areas should be considered to be a background and may be not passed to * image analysis algorithms.

* *

More precisely, each element P of the returned list, i.e. List<List<IPoint>>, * corresponds to one connected 2D polygon. The structure of this element P is the following:

* *
    *
  • P.get(0) is the list of sequential vertices of the polygon; each vertex * appears in this list only once;
  • *
  • P.get(1), P.get(2), ..., P.get(m), where * m=P.size() describe sequential vertices of all polygonal holes, * that may appear in the polygon. If the polygon has no holes (very probable case) or if * their detection is not supported, the list P contains only 1 element (m=1). *
  • *
* *

The default implementation in {@link AbstractPlanePyramidSource} calls {@link #zeroLevelActualRectangles()} * and converts each rectangle to the list P, containing only 1 element, and this element * is the list of 4 vertices of the rectangle. If {@link #zeroLevelActualRectangles()} returns null, * the default implementation also returns null.

* * @return the list of all polygonal areas, filled by actual data, at the level #0, and their * holes (if they exist), or null if this ability is not supported. */ default List>> zeroLevelActualAreaBoundaries() { return null; } Matrix readSubMatrix(int resolutionLevel, long fromX, long fromY, long toX, long toY) throws NoSuchElementException, NotYetConnectedException; // throws if !isResolutionLevelAvailable(resolutionLevel), if !isDataReady() default boolean isFullMatrixSupported() { return true; } // Works faster than equivalent readSubMatrix call if possible; // but may work very slowly in compressed implementations Matrix readFullMatrix(int resolutionLevel) throws NoSuchElementException, NotYetConnectedException, UnsupportedOperationException; // throws if !isResolutionLevelAvailable(resolutionLevel), // if !isDataReady(), if !isFullMatrixSupported() /** * Returns true if this special image kind is provided by current format. *

Default implementation in AbstractPlanePyramidSource return false. * * @param kind the kind of special image. * @return whether this kind is supported; false by default. */ boolean isSpecialMatrixSupported(SpecialImageKind kind); /** * Reads special image according specified kind. *

If the argument is {@link SpecialImageKind#NONE}, return null. In all other cases * returns some non-null result. *

If there is no appropriate image, returns {@link Optional#empty()}.. * * @param kind what special image is requested. * @return special image or {@link Optional#empty()} if this kind is not supported. */ Optional> readSpecialMatrix(SpecialImageKind kind) throws NotYetConnectedException; /** * Returns true if the data at all available levels of this source are available. * In other case, {@link #readSubMatrix(int, long, long, long, long)} and {@link #readFullMatrix(int)} * method can throw NotYetConnectedException (but also, maybe, work properly), *

Note: all other methods, including {@link #dimensions(int)}, must work without * NotYetConnectedException even if this method returns false. * * @return whether the data at all available levels of this source are available. */ boolean isDataReady(); /** * Returns some additional information about this pyramid or {@link Optional#empty()} if it is not supported. * The returned string should be formatted according JSON standard. * * @return additional information about the pyramid or empty result. */ default Optional metadata() { return Optional.empty(); } /** * Re-initializes object and loads all necessary resources. * *

This method should be called before using this object, if * {@link #freeResources(FlushMode)} was called before. * If you will not directly call this method, all will work normally, * but some classes may work more slowly. * For example, some classes may work with clones of this object, * so, if it is not initialized, then all its clones will be also non-initialized * and will be reinitialized while every usage.

*/ void loadResources(); void freeResources(FlushMode flushMode); }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy