The programmer interface of the Patch classes
successfully encapsulates and hides the somewhat complex
implementation and invocation details of the underlying
patch enumeration, windowing, weighting, and merging.
The program NStatVarPush
shows the instantiation and invocation of the patch method.
In general,
The programmer chooses among two patch operators:
PatchPush or PatchPull.
PatchPush defines the patches as subsets of the input, while
PatchPull defines them as subsets of the output.
The initialization of the patch operators requires three arguments:
the patch size and overlap,
the input or output space, and
an operator factory object.
The patch operators implement
Jest's operator interface Schwab and Schroeder (1997) and,consequently,
the standard image() method accepts the input quilt and returns
the processed output quilt.
public class NStatVarPush {
public static void main(String[] args) {
ArgumentKeeper argKeeper = new ArgumentKeeper(args); // read args
Rsf iput = RsfFactory.newRsf (System.in ); // read input quilt
float olap = argKeeper.getFloat ("overlap" , "0.5");
int[] psze = argKeeper.getIntArray("patchsize", "321");
OperatorFactory opFac = new StatVarFactory();
PatchPushOp pchOp = new PatchPushOp((RsfSpace) iput.getSpace(),
olap, psze, opFac);
Rsf oput = (Rsf) pchOp.image(iput); // image quilt
oput.write("pushOput.H"); iput.write("pushIput.H"); // write output quilt
}
}
package nstat.var;
import jam.operator.*;
import rsf.vector.*;
import rsf.operator.*;
import sep.io.ArgumentKeeper;
import nstat.patch.*;
The patch operators require an operator factory to generate the stationary operators needed to process each stationary patch. Such a factory is usually easily programmed, because most of its methods are simply wrappers for the instantiation methods of the stationary operator. Why are such wrappers necessary? A factory standardizes instantiation methods, which cannot be standardized directly by inheritance from an abstract interface (). Additionally, the operator factory supplies methods that return the domain given a range and vice versa. Table 1 shows the basic methods of the operator factory interface.
xspc = fac.createDomain(yspc) | creates domain space for given range space | |
yspc = fac.createRange( xspc) | creates range space for given domain space | |
oper = fac.getOp(xspc,yspc) | creates operator given domain and range |
The programmer-friendly patch operators
encapsulate
the tedious and error-prone computations that split, process, and merge
nonstationary data sets.
Internally,
the patch operators invoke a class called PatchEnumeration
that organizes the patch processing.
The enumeration computes the actual patch location.
The patch size is kept constant,
but the overlap may slightly vary in order to fit the given
patch size into the given input quilt size.
The patch location is defined by the patch size and a patch anchor,
the lowest-index vertex of the patch on the quilt space.
The PatchEnumeration object directs a Window operator
to extract the various patches. For efficiency, the
Window operator can change its domain and range without
being instantiated.
The operator handles
minor rounding errors in the spaces' offset and increment
intelligently, so that the patch's space remains a subspace
of the quilt space.
For each extracted patch, the patch operator requests a corresponding
operator
from the operator factory.
After processing the patch, the
patch operator creates an interpolation operator
.
The interpolation
operator weights the output patch and adds it to the output quilt
.
The same interpolation operator images an identity vector and adds it to
the weight quilt
.
After the last patch is processed, the patch operator divides the
output quilt's elements by the corresponding elements of the weight quilt.
The encapsulation of the patch operator
greatly owes its implementation to
Jest's novel and careful formulation of domains, ranges, and
vector spaces.