In the SNAP product data model, bands obtain their pixel data from source images which are in instances of type 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 resolutioon levels and for requested image tiles at that resolution level. A number of sub-classes exists as well as a number of helper classes.
The following example explains how a band "output_band" is computed from two input bands using the following helper classes:
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 aRenderedImage
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.
Product product = new Product("test", "test", width, height); product.setPreferredTileSize(tileSize, tileSize); product.setNumResolutionsMax(5); Band inputBand1 = product.addBand("input_band_1", "X * X - Y * Y", ProductData.TYPE_FLOAT64); Band inputBand2 = product.addBand("input_band_2", "2 * X * Y", ProductData.TYPE_FLOAT64); Band outputBand = product.addBand("output_band", ProductData.TYPE_FLOAT64); final MultiLevelModel multiLevelModel = ImageManager.getMultiLevelModel(inputBand1); final MultiLevelSource multiLevelSource = new AbstractMultiLevelSource(multiLevelModel) { @Override public void reset() { super.reset(); // Tell the parent product that it's band data has changed outputBand.fireProductNodeDataChanged(); } // Get the image for a given resolution level @Override public RenderedImage createImage(int level) { return new RasterDataNodeOpImage(outputBand, ResolutionLevel.create(getModel(), level)) { // Compute the tile data @Override protected void computeProductData(ProductData outputData, Rectangle region) throws IOException { int numElems = region.width * region.height; ProductData inputData1 = ProductData.createInstance(ProductData.TYPE_FLOAT64, numElems); ProductData inputData2 = ProductData.createInstance(ProductData.TYPE_FLOAT64, numElems); inputBand1.readRasterData(region.x, region.y, region.width, region.height, inputData1); inputBand2.readRasterData(region.x, region.y, region.width, region.height, inputData2); for (int i = 0; i < numElems; i++) { double value1 = inputData1.getElemDoubleAt(i); double value2 = inputData2.getElemDoubleAt(i); outputData.setElemDoubleAt(i, value1 - value2); } } }; } }; outputBand.setSourceImage(new DefaultMultiLevelImage(multiLevelSource));