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. MultiLevelImages 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-46 - Getting issue details... STATUS