How to develop a multi-level source image
In the SNAP product data model, bands obtain their pixel data from source images which are in instances of type The following example explains how a band "magnitude" is computed from two input bands "real" and "imag" using the following helper classes: Purpose
com.bc.ceres.glevel.MultiLevelImage
. A MultiLevelImage
is a actually a java.awt.image.RenderedImage
with the additional capability to serve sub-sampled versions of itself for given resolution levels ranging from zero to maximum value. Level zero is the MultiLevelImage
itself. MultiLevelImage
s are designed to somehow provide (e.g. compute or read) pixel data at requested resolution levels and for requested image tiles at that resolution level. A number of sub-classes exists as well as a number of helper classes.Example
com.bc.ceres.glevel.support.DefaultMultiLevelImage
- a default implementation of a multi-level images that requires a multi-level source.com.bc.ceres.glevel.support.AbstractMultiLevelSource
- an abstract, partly implementation of a multi-level source which requires implementors to provide a RenderedImage
for a given resolution level.org.esa.beam.jai.RasterDataNodeOpImage
- an abstract, partly implementation of a JAI OpImage for raster data nodes which requires implementors to prvide the actual pixel computation for a an image tile.static Product createTestProduct(int width, int height, int tileSize, int numResolutionsMax) {
Product product = new Product("test", "test", width, height);
product.setPreferredTileSize(tileSize, tileSize);
product.setNumResolutionsMax(numResolutionsMax);
Band realBand = product.addBand("real", "X * X - Y * Y", ProductData.TYPE_FLOAT64);
Band imagBand = product.addBand("imag", "2 * X * Y", ProductData.TYPE_FLOAT64);
Band magnitudeBand = product.addBand("magnitude", ProductData.TYPE_FLOAT64);
MultiLevelModel multiLevelModel = ImageManager.getMultiLevelModel(realBand);
MultiLevelSource multiLevelSource = new AbstractMultiLevelSource(multiLevelModel) {
@Override
public void reset() {
super.reset();
magnitudeBand.fireProductNodeDataChanged();
}
@Override
public RenderedImage createImage(int level) {
return new MagnitudeOpImage(magnitudeBand, ResolutionLevel.create(getModel(), level),
realBand, imagBand);
}
};
magnitudeBand.setSourceImage(new DefaultMultiLevelImage(multiLevelSource));
return product;
}
static class MagnitudeOpImage extends RasterDataNodeOpImage {
private final Band realBand;
private final Band imagBand;
public MagnitudeOpImage(Band outputBand, ResolutionLevel level, Band realBand, Band imagBand) {
super(outputBand, level);
this.realBand = realBand;
this.imagBand = imagBand;
}
@Override
protected void computeProductData(ProductData outputData, Rectangle region) throws IOException {
ProductData realData = getRawProductData(realBand, region);
ProductData imagData = getRawProductData(imagBand, region);
int numElems = region.width * region.height;
for (int i = 0; i < numElems; i++) {
double real = realData.getElemDoubleAt(i);
double imag = imagData.getElemDoubleAt(i);
double result = Math.sqrt(real * real + imag * imag);
outputData.setElemDoubleAt(i, result);
}
}
}
References:
- SNAP-46Getting issue details... STATUS