/* JAI-Ext - OpenSource Java Advanced Image Extensions Library * http://www.geo-solutions.it/ * Copyright 2014 GeoSolutions * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package it.geosolutions.jaiext.stats; import it.geosolutions.jaiext.iterators.RandomIterFactory; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.stats.Statistics.StatsType; import java.awt.Rectangle; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.util.Map; import javax.media.jai.ImageLayout; import javax.media.jai.ROI; import javax.media.jai.RasterAccessor; import javax.media.jai.RasterFormatTag; import javax.media.jai.iterator.RandomIter; /** * The SimpleStatsOpImage class performs various simple statistics operations on an image. The statistical operation are indicated by the * {@link StatsType} class. A simple operation is an operation which not stores the pixel values into an array but only updates every time its * statistical parameters. These operations can be calculated together by adding entries in the definition array "statsTypes". A ROI object passed to * the constructor is taken into account by counting only the samples inside of it; an eventual No Data Range is considered by counting only values * that are not No Data. The statistical calculation is performed by calling the getProperty() method. The statistics are calculated for every image * tile and then the partial results are accumulated and passed to the getProperty() method. For avoiding unnecessary calculations the statistics can * be calculated only the first time; but if the user needs to re-calculate the statistics, they can be cleared with the clearStatistic() method and * then returned by calling again the getProperty() method. */ public class SimpleStatsOpImage extends StatisticsOpImage { public SimpleStatsOpImage(RenderedImage source, int xPeriod, int yPeriod, ROI roi, Range noData, boolean useROIAccessor, int[] bands, StatsType[] statsTypes) { super(source, xPeriod, yPeriod, roi, noData, useROIAccessor, bands, statsTypes, null, null, null); // Storage of the statistic types indexes if present, and check if they are not complex statistic // objects like Histogram if (statsTypes != null) { for (int i = 0; i < statsTypes.length; i++) { if (statsTypes[i].getStatsId() > 6) { throw new IllegalArgumentException("Wrong statistic types"); } } } else { throw new IllegalArgumentException("Statistic types not present"); } this.statsTypes = statsTypes; // Number of statistics calculated this.statNum = statsTypes.length; // Storage of the band indexes and length this.bands = bands; // Creation of a global container of all the selected statistics for every band this.stats = new Statistics[selectedBands][statNum]; // Filling of the container for (int i = 0; i < selectedBands; i++) { for (int j = 0; j < statNum; j++) { stats[i][j] = StatsFactory.createSimpleStatisticsObjectFromInt(statsTypes[j] .getStatsId()); } } } /** * Returns a tile for reading. * * @param tileX The X index of the tile. * @param tileY The Y index of the tile. * @return The tile as a <code>Raster</code>. */ public Raster computeTile(int tileX, int tileY) { // STATISTICAL ELABORATIONS // selection of the format tags RasterFormatTag[] formatTags = getFormatTags(); // Selection of the RasterAccessor parameters Raster source = getSourceImage(0).getTile(tileX, tileY); // Control if the Period is bigger than the tile dimension, in that case, the // statistics are not updated if (xPeriod > getTileWidth() || yPeriod > getTileHeight()) { return source; } Rectangle srcRect = getSourceImage(0).getBounds().intersection(source.getBounds()); // creation of the RasterAccessor RasterAccessor src = new RasterAccessor(source, srcRect, formatTags[0], getSourceImage(0) .getColorModel()); // ROI calculations if roiAccessor is used RasterAccessor roi = null; RandomIter roiIter = null; if (useROIAccessor) { // Note that the getExtendedData() method is not called because the input images are padded. // For each image there is a check if the rectangle is contained inside the source image; // if this not happen, the data is taken from the padded image. Raster roiRaster = null; if(srcROIImage.getBounds().contains(srcRect)){ roiRaster = srcROIImage.getData(srcRect); }else{ roiRaster = srcROIImgExt.getData(srcRect); } // creation of the rasterAccessor roi = new RasterAccessor(roiRaster, srcRect, RasterAccessor.findCompatibleTags( new RenderedImage[] { srcROIImage }, srcROIImage)[0], srcROIImage.getColorModel()); } else if(hasROI) { roiIter = RandomIterFactory.create(srcROIImage, srcROIImage.getBounds(), true, true); } // Creation of local objects containing the same statistics as the initials Statistics[][] statArray = new Statistics[selectedBands][statNum]; // Filling of the container for (int i = 0; i < selectedBands; i++) { for (int j = 0; j < statNum; j++) { statArray[i][j] = StatsFactory.createSimpleStatisticsObjectFromInt(statsTypes[j] .getStatsId()); } } // Computation of the statistics switch (src.getDataType()) { case DataBuffer.TYPE_BYTE: byteLoop(src, srcRect, roi, statArray, roiIter); break; case DataBuffer.TYPE_USHORT: ushortLoop(src, srcRect, roi, statArray, roiIter); break; case DataBuffer.TYPE_SHORT: shortLoop(src, srcRect, roi, statArray, roiIter); break; case DataBuffer.TYPE_INT: intLoop(src, srcRect, roi, statArray, roiIter); break; case DataBuffer.TYPE_FLOAT: floatLoop(src, srcRect, roi, statArray, roiIter); break; case DataBuffer.TYPE_DOUBLE: doubleLoop(src, srcRect, roi, statArray, roiIter); break; } // Cumulative addition (SYNCHRONIZED) synchronized (this) { // Cycle on the selected Bands for (int i = 0; i < selectedBands; i++) { for (int j = 0; j < statNum; j++) { // Accumulation for the selected band and the selected statistic stats[i][j].accumulateStats(statArray[i][j]); } } } return source; } }