public abstract class StreamingApertureProcessor extends AbstractArrayProcessorWithContextSwitching
Streaming aperture matrix processor: an algorithm, processing one or
several ndimensional matrices
and returning one resulting matrix,
where the value of every element of the resulting matrix depends on (and only on)
the source elements in an aperture with the fixed shape "around" the same position.
This class allows to optimize such type of processing in all cases, when the source matrix
is not direct accessible
, for example, if it is very large
and created via LargeMemoryModel
: this class automatically splits the source matrix into blocks
which can fit in Java memory, downloads them into (directly accessible) matrices, created by
SimpleMemoryModel
, and processes them by the abstract method
asProcessed
, overridden by the user.
It is supposed that the type of matrix elements is one of primitive Java types
(boolean, char, byte, short, int,
long, float, double) and, so, represents an integer or a real number,
according to comments to PFixedArray.getLong(long)
and PArray.getDouble(long)
methods.
See below for more details.
First of all, let's define all terms and specify, what kind of algorithms can be performed by this class.
This class works with some AlgART matrix
M, called the source matrix,
some list of additional matrices
pattern
P, called the aperture shape.
The dimensions of all additional arguments always must be the same as the dimensions of the source
matrix: dimEquals
(M)dimCount()
==M.dimCount()
integer pattern
;
if a pattern, passed to the main process
method of this class, is not integer, it is automatically
rounded to the nearest integer pattern by the call
round()
dimCount()
points
of the pattern P).
We always consider that the point x lies inside M matrix
(dim
(k)PFixedArray.getLong(long)
, if the type of the matrix elements is boolean, char,
byte, short, int or long, or real: PArray.getDouble(long)
,
if the element type is float or double) of the underlying array
array()
pseudoCyclicIndex
(x'_{0}, x'_{1}, ..., x'_{n−1})pointCount()
PFixedArray.getLong(long)
, if the type of the matrix elements is boolean, char,
byte, short, int or long, or real: PArray.getDouble(long)
,
if the element type is float or double) of the underlying array
array()
index
(x_{0}, x_{1}, ..., x_{n−1})r = g (v_{0}, v_{1}, ..., v_{N−1}, w_{0}, w_{1}, ..., w_{K−1}).The processing function g is a parameter of this object and is specified by the concrete implementation of
asProcessed(Class, Matrix, List, Pattern)
abstract method.
As This class declares two base methods:
asProcessed(Class, Matrix, List, Pattern)
abstract method, which fully defines the processing
algorithm, i.e. the processing function g, and returns the result of this algorithm as a
"lazy" matrix R (i.e. an immutable view of the passed source matrix,
such that any reading data from it calculates and returns the resulting r elements);process(Matrix, Matrix, List, Pattern)
nonabstract method,
which really performs all calculations, using asProcessed
method, and stores the resulting matrix R in its first argument dest.Usually, this class really represents a streaming aperture processor, according the rules listed above.
Such implementations of this class are called standard implementations.
In standard implementations, it is enough to implement only the abstract method
asProcessed
.
But it is also allowed this class to represent any other algorithm, that converts M matrix and
a set of asProcessed
and
process
.
You can detect, is this implementation standard or no, with help of
isStandardImplementation()
method.
Note 1: the definition of the aperture above always supposes the pseudocyclic continuation
of the source matrix, as described in Matrix.pseudoCyclicIndex(long...)
method. You can use
ContinuedStreamingApertureProcessor
(an example of nonstandard implementation of this class)
to change this behaviour to another continuation way.
Note 2: it is easy to see that all basic morphology, defined in
Morphology
interface
(in a simple case when the number of morphology pattern dimensions
is equal to the number of the source matrix dimensions M.dimCount()
,
as this class requires),
and all rank operations, defined in RankMorphology
interface,
are streaming aperture processors, when they use standard pseudocyclic continuation of the matrix
(ContinuedMorphology
and
ContinuedRankMorphology
work in other way).
The basic morphology operations have no additional arguments M_{k},
as well as aperture sum rank operation. The percentile has 1 additional argument r,
the rank has 1 additional argument v, the mean between percentiles and
mean between values have 2 additional arguments. Most of filters, using in image processing,
like the traditional linear filters, are also streaming aperture processors.
The main task, solved by this class, is a ready implementation of the second
(process
) method on the base of the first method
(asProcessed
) for a case of the standard implementations
of this class. Namely, the implementation, offered by this class, performs the necessary calculations
via one or more calls of asProcessed
method,
and it tries to optimize them by downloading parts of the source matrix M into quick accessible
(i.e. direct accessible
) temporary matrices,
created by SimpleMemoryModel
, and applying asProcessed
to them. The idea of this optimization is the following. Usually, calculating the result of
asProcessed
for every aperture position x
requires accessing to N elements of the source matrix in the aperture.
If the source matrix is not direct accessible, it can require essential time, especially if
it is created by LargeMemoryModel
. But if you are using this class, you can call
process
method and be almost sure,
that it will call asProcessed
method with relatively
little direct accessible
temporary matrices.
Such preloading usually increases performance in times even without any additional efforts;
but if you want to provide maximal performance, you should check (in your implementation of
asProcessed
), whether the passed src
matrix is direct accessible
, and, probably, provide
a special optimized branch of the algorithm which works with the
internal Java array
.
The amount of Java memory, which process
method
may spend for the optimization, is specified via maxTempBufferSize(PArray)
method
and usually corresponds to Arrays.SystemSettings.maxTempJavaMemory()
limit.
This optimization is possible only in standard implementations, when your
asProcessed
method really represents
some streaming aperture processor. It means that it calculates and returns the results of
some processing function g (not depending on the order of first N arguments),
as described in the definition above. If these conditions are not fulfilled, the result of
process
method can be incorrect. For example,
a typical possible error while implementing asProcessed
is using the value w of the element of the source matrix M at the position x.
It can lead to error, because process
method sometimes
shifts
the passed pattern and correspondingly
shifts
the source matrix M
for optimization goals — so, your asProcessed
method, while trying to access to the element of the source matrix M at the position x,
will really read the value of another element instead. If you need to implement an algorithm, where the result
element r at the position x depends also on the element of the source matrix
at the same position x, you should pass the source matrix M also as one of additional
M_{k} matrices. You can find an example of this technique in comments to
RankProcessors.getPercentilePairProcessor
method, where the usage of it for implementing the corresponding
BasicRankMorphology
methods is described.
Note that this class does not try to preload necessary parts of the additional M_{k}
matrices into Java memory (i.e. temporary matrices, created by SimpleMemoryModel
). The reason is that
the aperture size N is usually much greater than the number of additional matrices K
(in most applications K is from 0 to 2..3), so it is not too important to optimize
access to additional matrices. But, if necessary, you can do it yourself in your
asProcessed
method by good implementing
Array.getData(long, Object, int, int)
method in the "lazy" builtin array of the resulting matrix.
To do this, you need to load the corresponding subarrays of the additional arguments into your own Java arrays
by the corresponding Array.getData(long, Object, int, int)
calls for all arrays
array()
JArrayPool
class can help you to minimize necessary
memory allocations.
This package provides a set of methods for creating objects, extending this class for
all basic rank operations
,
in RankProcessors
class.
Warning: this class can process only patterns
where pointCount()
≤Integer.MAX_VALUEPattern
argument,
can throw TooManyPointsInPatternError
or OutOfMemoryError in the same situations as Pattern.points()
method.
The classes, implementing this interface, are usually immutable and threadsafe: there are no ways to modify settings of the created instance. It is not guaranteed for any classes, but it is guaranteed for all instances created by the methods of the classes of this package.
Modifier  Constructor and Description 

protected 
StreamingApertureProcessor(ArrayContext context)
Creates an instance of this class with the given context.

Modifier and Type  Method and Description 

abstract <T extends PArray> 
asProcessed(java.lang.Class<? extends T> requiredType,
Matrix<? extends PArray> src,
java.util.List<? extends Matrix<? extends PArray>> additionalMatrices,
Pattern pattern)
Returns an immutable view of the passed source matrix

<T extends PArray> 
asProcessed(java.lang.Class<? extends T> requiredType,
Matrix<? extends PArray> src,
Matrix<? extends PArray> additionalMatrix1,
Matrix<? extends PArray> additionalMatrix2,
Matrix<? extends PArray> additionalMatrix3,
Pattern pattern)
Equivalent to
asProcessed (requiredType, src, Matrices.several (PArray.class, additionalMatrix1, additionalMatrix2, additionalMatrix3), pattern). 
<T extends PArray> 
asProcessed(java.lang.Class<? extends T> requiredType,
Matrix<? extends PArray> src,
Matrix<? extends PArray> additionalMatrix1,
Matrix<? extends PArray> additionalMatrix2,
Pattern pattern)
Equivalent to
asProcessed (requiredType, src, Matrices.several (PArray.class, additionalMatrix1, additionalMatrix2), pattern). 
<T extends PArray> 
asProcessed(java.lang.Class<? extends T> requiredType,
Matrix<? extends PArray> src,
Matrix<? extends PArray> additionalMatrix,
Pattern pattern)
Equivalent to
asProcessed (requiredType, src, Matrices.several (PArray.class, additionalMatrix), pattern). 
<T extends PArray> 
asProcessed(java.lang.Class<? extends T> requiredType,
Matrix<? extends PArray> src,
Pattern pattern)
Equivalent to
asProcessed (requiredType, src, Matrices.several (PArray.class), pattern). 
protected static void 
checkArguments(Matrix<? extends PArray> dest,
Matrix<? extends PArray> src,
java.util.List<? extends Matrix<? extends PArray>> additionalMatrices,
Pattern pattern)
Checks whether the passed arguments are allowed arguments for
process(Matrix, Matrix, List, Pattern) method and throws the corresponding exception
if it is not so. 
StreamingApertureProcessor 
context(ArrayContext newContext)
This method is implemented here via cloning this object
(by standard clone() call) and replacing the value of the field,
where a reference to the current context is stored, with newContext value.

boolean 
isStandardImplementation()
Returns true if there is a guarantee that this object is
a standard implementations of this class.

protected long 
maxTempBufferSize(PArray src)
Specifies the maximal amount of usual Java memory,
measured in elements of temporary arrays, that
process method
may freely use for optimization needs. 
void 
process(Matrix<? extends UpdatablePArray> dest,
Matrix<? extends PArray> src,
java.util.List<? extends Matrix<? extends PArray>> additionalMatrices,
Pattern pattern)
Processes the passed source matrix

void 
process(Matrix<? extends UpdatablePArray> dest,
Matrix<? extends PArray> src,
Matrix<? extends PArray> additionalMatrix1,
Matrix<? extends PArray> additionalMatrix2,
Matrix<? extends PArray> additionalMatrix3,
Pattern pattern)
Equivalent to
process (dest, src, Matrices.several (PArray.class, additionalMatrix1, additionalMatrix2, additionalMatrix3), pattern). 
void 
process(Matrix<? extends UpdatablePArray> dest,
Matrix<? extends PArray> src,
Matrix<? extends PArray> additionalMatrix1,
Matrix<? extends PArray> additionalMatrix2,
Pattern pattern)
Equivalent to
process (dest, src, Matrices.several (PArray.class, additionalMatrix1, additionalMatrix2), pattern). 
void 
process(Matrix<? extends UpdatablePArray> dest,
Matrix<? extends PArray> src,
Matrix<? extends PArray> additionalMatrix,
Pattern pattern)
Equivalent to
process (dest, src, Matrices.several (PArray.class, additionalMatrix1), pattern). 
void 
process(Matrix<? extends UpdatablePArray> dest,
Matrix<? extends PArray> src,
Pattern pattern)
Equivalent to
process (dest, src, Matrices.several (PArray.class), pattern). 
context, contextPart, memoryModel
protected StreamingApertureProcessor(ArrayContext context)
context
 the context used by this instance for all operations.public StreamingApertureProcessor context(ArrayContext newContext)
AbstractArrayProcessorWithContextSwitching
This method is implemented here via cloning this object (by standard clone() call) and replacing the value of the field, where a reference to the current context is stored, with newContext value. This technique is suitable for most implementation. However, if you need, you can override this method; maybe, it is enough to override clone() instead.
context
in interface ArrayProcessorWithContextSwitching
context
in class AbstractArrayProcessorWithContextSwitching
newContext
 another context, used by the returned instance; may be null.public boolean isStandardImplementation()
StreamingApertureProcessor
class for more details.public final <T extends PArray> Matrix<T> asProcessed(java.lang.Class<? extends T> requiredType, Matrix<? extends PArray> src, Pattern pattern)
asProcessed
(requiredType, src, Matrices.several
(PArray.class), pattern).requiredType
 desired type of the builtin array in the returned matrix.src
 the source matrix M.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires at least 1 additional matrix.public final <T extends PArray> Matrix<T> asProcessed(java.lang.Class<? extends T> requiredType, Matrix<? extends PArray> src, Matrix<? extends PArray> additionalMatrix, Pattern pattern)
asProcessed
(requiredType, src, Matrices.several
(PArray.class, additionalMatrix), pattern).requiredType
 desired type of the builtin array in the returned matrix.src
 the source matrix M.additionalMatrix
 the additional matrix M_{0}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.SizeMismatchException
 if the passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires more than 1 additional matrix.public final <T extends PArray> Matrix<T> asProcessed(java.lang.Class<? extends T> requiredType, Matrix<? extends PArray> src, Matrix<? extends PArray> additionalMatrix1, Matrix<? extends PArray> additionalMatrix2, Pattern pattern)
asProcessed
(requiredType, src, Matrices.several
(PArray.class, additionalMatrix1, additionalMatrix2), pattern).requiredType
 desired type of the builtin array in the returned matrix.src
 the source matrix M.additionalMatrix1
 the additional matrix M_{0}.additionalMatrix2
 the additional matrix M_{1}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.SizeMismatchException
 if the passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires more than 2 additional matrices.public final <T extends PArray> Matrix<T> asProcessed(java.lang.Class<? extends T> requiredType, Matrix<? extends PArray> src, Matrix<? extends PArray> additionalMatrix1, Matrix<? extends PArray> additionalMatrix2, Matrix<? extends PArray> additionalMatrix3, Pattern pattern)
asProcessed
(requiredType, src, Matrices.several
(PArray.class, additionalMatrix1, additionalMatrix2, additionalMatrix3), pattern).requiredType
 the desired type of the builtin array in the returned matrix.src
 the source matrix M.additionalMatrix1
 the additional matrix M_{0}.additionalMatrix2
 the additional matrix M_{1}.additionalMatrix3
 the additional matrix M_{2}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.SizeMismatchException
 if the passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires more than 3 additional matrices.public abstract <T extends PArray> Matrix<T> asProcessed(java.lang.Class<? extends T> requiredType, Matrix<? extends PArray> src, java.util.List<? extends Matrix<? extends PArray>> additionalMatrices, Pattern pattern)
comments to this class
for more details.
The matrix, returned by this method, is immutable, and the class of its builtin array
implements one of the basic interfaces
BitArray
, CharArray
,
ByteArray
, ShortArray
,
IntArray
, LongArray
,
FloatArray
or DoubleArray
.
The class of desired interface (one of 8 possible classes) must be passed as requiredType argument.
So, it defines the element type of the returned matrix.
The rules of casting the floatingpoint result of the processing function g
to the desired element type depend on implementation.
In many (but not all) implementations they are the same as in
Arrays.asFuncArray(boolean, net.algart.math.functions.Func, Class, PArray...)
method with the argument truncateOverflows=true.
The concrete algorithm, implementing by this class, can require some number of additional arguments M_{k}. If the number of matrices in the passed list additionalMatrices is less than the required one, this method throws IllegalArgumentException. If the number of passed matrices is greater than the required one, it is not an error: the extra arguments are ignored.
Usually you should use process
method, which work
faster than this method.
requiredType
 the desired type of the builtin array in the returned matrix.src
 the source matrix M.additionalMatrices
 the additional matrices M_{0}, M_{1},
..., M_{K−1}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null or
if one of additionalMatrices elements is null.SizeMismatchException
 if some passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if the number of additional matrices additionalMatrices.size()
is less than the number of arguments, required by this implementation.public final void process(Matrix<? extends UpdatablePArray> dest, Matrix<? extends PArray> src, Pattern pattern)
process
(dest, src, Matrices.several
(PArray.class), pattern).dest
 the resulting matrix R.src
 the source matrix M.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.SizeMismatchException
 if the passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires at least 1 additional matrix.public final void process(Matrix<? extends UpdatablePArray> dest, Matrix<? extends PArray> src, Matrix<? extends PArray> additionalMatrix, Pattern pattern)
process
(dest, src, Matrices.several
(PArray.class, additionalMatrix1), pattern).dest
 the resulting matrix R.src
 the source matrix M.additionalMatrix
 the additional matrix M_{0}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.SizeMismatchException
 if the passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires more than 1 additional matrix.public final void process(Matrix<? extends UpdatablePArray> dest, Matrix<? extends PArray> src, Matrix<? extends PArray> additionalMatrix1, Matrix<? extends PArray> additionalMatrix2, Pattern pattern)
process
(dest, src, Matrices.several
(PArray.class, additionalMatrix1, additionalMatrix2), pattern).dest
 the resulting matrix R.src
 the source matrix M.additionalMatrix1
 the additional matrix M_{0}.additionalMatrix2
 the additional matrix M_{1}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.SizeMismatchException
 if the passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires more than 2 additional matrices.public final void process(Matrix<? extends UpdatablePArray> dest, Matrix<? extends PArray> src, Matrix<? extends PArray> additionalMatrix1, Matrix<? extends PArray> additionalMatrix2, Matrix<? extends PArray> additionalMatrix3, Pattern pattern)
process
(dest, src, Matrices.several
(PArray.class, additionalMatrix1, additionalMatrix2, additionalMatrix3), pattern).dest
 the resulting matrix R.src
 the source matrix M.additionalMatrix1
 the additional matrix M_{0}.additionalMatrix2
 the additional matrix M_{1}.additionalMatrix3
 the additional matrix M_{2}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null.SizeMismatchException
 if the passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if this implementation requires more than 3 additional matrices.public void process(Matrix<? extends UpdatablePArray> dest, Matrix<? extends PArray> src, java.util.List<? extends Matrix<? extends PArray>> additionalMatrices, Pattern pattern)
comments to this class
for more details.
This default implementations is based on one or more calls of
asProcessed
method and
copying its result into dest matrix.
The requiredType argument of asProcessed
method
is chosen as dest.type
(PArray.class).
If you need to create a nonstandard implementation (a class which does not represent
a streaming aperture processor, complying with strict definition from the comments to this class),
you must override this method. You also may override this method, if it is possible to provide
better performance than the default implementation, for example, for some specific variants of
the aperture shape pattern.
If the element type of dest matrix is not floatingpoint,
then this method casts the floatingpoint result of the processing function g
to the types of dest elements. The rules of casting depend on implementation
and usually are the same as in asProcessed
method.
The default implementation does not need casting, because all necessary casting is already performed
by asProcessed
method.
The concrete algorithm, implementing by this class, can require some number of additional arguments M_{k}. If the number of matrices in the passed list additionalMatrices is less than the required one, this method throws IllegalArgumentException. If the number of passed matrices is greater than the required one, it is not an error: the extra arguments are ignored.
The aperture shape pattern, passed to this method, is automatically rounded to the nearest
integer pattern
by the operators
round()
dest
 the resulting matrix R.src
 the source matrix M.additionalMatrices
 the additional matrices M_{0}, M_{1},
..., M_{K−1}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null or
if one of additionalMatrices elements is null.SizeMismatchException
 if some passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
or if the number of additional matrices additionalMatrices.size()
is less than the number of arguments, required by this implementation.protected long maxTempBufferSize(PArray src)
process
method
may freely use for optimization needs.
The src arguments is array()
process
method.
By default, this method returns Math.round(maxTempJavaMemory/elementSize),
where maxTempJavaMemory =
Math.max(Arrays.SystemSettings.MIN_OPTIMIZATION_JAVA_MEMORY
,
Arrays.SystemSettings.maxTempJavaMemory()
)
and elementSize is the number of bytes, required for each element of src array
(i.e. bitsPerElement()
/8.0
You may override this method if you want to change this behaviour.
For example, it can be necessary if your implementation of
asProcessed
method allocates some Java memory itself:
in this case, you should correct the result of this method in such a way, that the total
amount of allocated temporary Java memory will not exceed maxTempJavaMemory limit.
protected static void checkArguments(Matrix<? extends PArray> dest, Matrix<? extends PArray> src, java.util.List<? extends Matrix<? extends PArray>> additionalMatrices, Pattern pattern)
process(Matrix, Matrix, List, Pattern)
method and throws the corresponding exception
if it is not so. Does nothing if the arguments are correct.
More precisely, this method checks that all arguments are not null,
all elements of additionalMatrices (if this list is not empty) are not null,
dest and src matrices and elements of additionalMatrices (if this list is not empty)
have the same dimensions
and
pattern.dimCount()
==src.dimCount()
.
This method is called in the beginning of process
method.
It also can be used in the beginning of asProcessed
method,
with passing src argument of that method in a role of both dest and src arguments
of this one.
dest
 the resulting matrix R.src
 the source matrix M.additionalMatrices
 the additional matrices M_{0}, M_{1},
..., M_{K−1}.pattern
 the aperture shape P.java.lang.NullPointerException
 if one of the arguments is null or
if one of additionalMatrices elements is null.SizeMismatchException
 if some passed matrices have different dimensions.java.lang.IllegalArgumentException
 if the number of the pattern dimensions
pattern.dimCount()
is not equal
to src.dimCount()
.