/* 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.zonal;
import it.geosolutions.jaiext.range.Range;
import it.geosolutions.jaiext.stats.Statistics.StatsType;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.util.List;
import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptorImpl;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.ROI;
import javax.media.jai.RenderedOp;
import javax.media.jai.registry.RenderedRegistryMode;
/**
* An <code>OperationDescriptor</code> describing the Zonal Statistics operation.
*
* <p>
* The ZonalStats operation takes in input a source image, an optional classifier image and a list of geometries on which the selected statistics are
* calculated. These statistics are defined by the input {@link StatsType} array. The calculations can NoData. It is important to remember that the
* classifier must be of integral data type.The possible statistics are:
* </p>
*
* <p>
* <ul>
* <li>Mean</li>
* <li>Sum</li>
* <li>Maximum</li>
* <li>Minimum</li>
* <li>Extrema</li>
* <li>Variance</li>
* <li>Standard Deviation</li>
* <li>Histogram</li>
* <li>Mode</li>
* <li>Median</li>
* </ul>
* </p>
*
* <p>
* It is important to remember that if the Median, Mode or Histogram operations must be executed, even their Bounds and Bin numbers must be defined.
* The source can have all the possible JAI accepted data types. The statistical calculations are performed on every tile with an adequate
* synchronization and stored inside an instance of the {@link ZoneGeometry} class. For avoiding concurrency issues, the statistic calculation is done
* in a synchronized block. The statistical results are returned by calling the getProperty() method. The calculation happens only the first time for
* avoiding unnecessary loss of time.
* </p>
*
* <p>
* The results are returned by the getProperty() method as a List<ZoneGeometry>. Every item contains the results for the related geometry. These
* results are stored as a Map<Integer, Map<Integer, Statistics[]>. The inner map contains the results for every zone indicated by the optional
* classifier object (if the classifier is not present, the statistics are stored inside the 0-key item). The outer map contains the results for every
* band. The user must only select the band, the zone(if present) and the index associated to the desired Statistics object and then call the
* getResult() method for having the result.
* </p>
*
*
* <p>
* <table border=1>
* <caption>Resource List</caption>
* <tr>
* <th>Name</th>
* <th>Value</th>
* </tr>
* <tr>
* <td>GlobalName</td>
* <td>Zonal</td>
* </tr>
* <tr>
* <td>LocalName</td>
* <td>Zonal</td>
* </tr>
* <tr>
* <td>Vendor</td>
* <td>it.geosolutions.jaiext</td>
* </tr>
* <tr>
* <td>Description</td>
* <td>Image operator for calculating statistics on different image zones supporting ROI and No Data.</td>
* </tr>
* <tr>
* <td>DocURL</td>
* <td>Not Defined</td>
* </tr>
* <tr>
* <td>Version</td>
* <td>1.0</td>
* </tr>
* <tr>
* <td>arg0Desc</td>
* <td>Classifier image.</td>
* </tr>
* <tr>
* <td>arg1Desc</td>
* <td>Transformation object used for mapping the Source image to the classifier.</td>
* </tr>
* <tr>
* <td>arg2Desc</td>
* <td>List of all the geometries to analyze.</td>
* </tr>
* <tr>
* <td>arg3Desc</td>
* <td>No Data Range used.</td>
* </tr>
* <tr>
* <td>arg4Desc</td>
* <td>ROI Object used.</td>
* </tr>
* <tr>
* <td>arg5Desc</td>
* <td>Boolean indicatin if the ROI RasterAccessor should be used during computations.</td>
* </tr>
* <tr>
* <td>arg6Desc</td>
* <td>Array containing the indexes of the bands to calculate.</td>
* </tr>
* <tr>
* <td>arg7Desc</td>
* <td>Array indicating which statistical operations must be performed on all the selected bands.</td>
* </tr>
* <tr>
* <td>arg8Desc</td>
* <td>Array indicating the minimum bounds for complex statistics on all the selected bands.</td>
* </tr>
* <tr>
* <td>arg9Desc</td>
* <td>Array indicating the maximum bounds for complex statistics on all the selected bands.</td>
* </tr>
* <tr>
* <td>arg10Desc</td>
* <td>Array indicating the number of bins for complex statistics on all the selected bands.</td>
* </tr>
* <tr>
* <td>arg11Desc</td>
* <td>List of the possible ranges for dividing the statistics.</td>
* </tr>
* <tr>
* <td>arg12Desc</td>
* <td>Boolean indicating if the results must be calculated for each range.</td>
* </tr>
* </table>
* </p>
*
* <p>
* <table border=1>
* <caption>Parameter List</caption>
* <tr>
* <th>Name</th>
* <th>Class Type</th>
* <th>Default Value</th>
* </tr>
* <tr>
* <td>classifier</td>
* <td>RenderedImage</td>
* <td>null</td>
* <tr>
* <td>transform</td>
* <td>AffineTransform</td>
* <td>null</td>
* <tr>
* <td>roilist</td>
* <td>List</td>
* <td>null</td>
* <tr>
* <td>noData</td>
* <td>it.geosolutions.jaiext.range.Range</td>
* <td>null</td>
* <tr>
* <td>mask</td>
* <td>javax.media.jai.ROI</td>
* <td>null</td>
* <tr>
* <td>useROIAccessor</td>
* <td>Boolean</td>
* <td>false</td>
* <tr>
* <td>bands</td>
* <td>int[]</td>
* <td>null</td>
* <tr>
* <td>stats</td>
* <td>it.geosolutions.jaiext.stats.Statistics.StatsType[]</td>
* <td>null</td>
* <tr>
* <td>minbound</td>
* <td>double[]</td>
* <td>null</td>
* <tr>
* <td>maxbound</td>
* <td>double[]</td>
* <td>null</td>
* <tr>
* <td>numbin</td>
* <td>int[]</td>
* <td>null</td>
* <tr>
* <td>rangeData</td>
* <td>List</td>
* <td>null</td>
* <tr>
* <td>localStats</td>
* <td>Boolean</td>
* <td>false</td>
* </table>
* </p>
*
*/
public class ZonalStatsDescriptor extends OperationDescriptorImpl {
/** Zonal Statistics property name */
public final static String ZS_PROPERTY = "JAI-EXT.zonalstats";
/**
* The resource strings that provide the general documentation and specify the parameter list for this operation.
*/
private static final String[][] resources = {
{ "GlobalName", "Zonal" },
{ "LocalName", "Zonal" },
{ "Vendor", "it.geosolutions.jaiext" },
{ "Description",
"Image operator for calculating statistics on various Geometries supporting ROI and No Data" },
{ "DocURL", "Not defined" },
{ "Version", "1.0" },
{ "arg0Desc", "Classifier image" },
{ "arg1Desc",
"Transformation object used for mapping the Source image to the classifier" },
{ "arg2Desc", "List of all the geometries to analyze" },
{ "arg3Desc", "No Data Range used" },
{ "arg4Desc", "ROI Object used" },
{ "arg5Desc",
"Boolean indicatin if the ROI RasterAccessor should be used during computations" },
{ "arg6Desc", "Array containing the indexes of the bands to calculate" },
{ "arg7Desc",
"Array indicating which statistical operations must be performed on all the selected bands" },
{ "arg8Desc",
"Array indicating the minimum bounds for complex statistics on all the selected bands" },
{ "arg9Desc",
"Array indicating the maximum bounds for complex statistics on all the selected bands" },
{ "arg10Desc",
"Array indicating the number of bins for complex statistics on all the selected bands" },
{ "arg11Desc", "List of the possible ranges for dividing the statistics" },
{ "arg12Desc", "Boolean indicating if the results must be calculated for each range" }
};
/** The parameter class list for this operation. */
private static final Class[] paramClasses = { RenderedImage.class, AffineTransform.class,
java.util.List.class, it.geosolutions.jaiext.range.Range.class,
javax.media.jai.ROI.class, Boolean.class, int[].class,
it.geosolutions.jaiext.stats.Statistics.StatsType[].class, double[].class,
double[].class, int[].class, java.util.List.class, Boolean.class };
/** The parameter name list for this operation. */
private static final String[] paramNames = { "classifier", "transform", "roilist", "noData",
"mask", "useROIAccessor", "bands", "stats", "minbound", "maxbound", "numbin",
"rangeData", "localStats" };
/** The parameter default value list for this operation. */
private static final Object[] paramDefaults = { null, null, null, null, null, false,
new int[] { 0 }, null, null, null, null, null, false };
public ZonalStatsDescriptor() {
super(resources, 1, paramClasses, paramNames, paramDefaults);
}
/**
* Performs statistical operations on different image zones defined by the input geometry list.
*
* <p>
* Creates a <code>ParameterBlockJAI</code> from all supplied arguments except <code>hints</code> and invokes
* {@link JAI#create(String,ParameterBlock,RenderingHints)}.
*
* @see JAI
* @see ParameterBlockJAI
* @see RenderedOp
*
* @param source <code>RenderedImage</code> source image.
* @param classifier <code>RenderedImage</code> optional classifier image(Integral dataType).
* @param transform affine transformation used for mapping source image on the classifier.
* @param roilist list of all the geometries.
* @param NoData No Data range used for calculation.
* @param mask optional mask for reducing the computations on a selected ROI.
* @param useROIAccessor boolean indicating if a ROI RasterAccessor should be used during computations with the mask.
* @param bands Array indicating which band to consider.
* @param stats Array indicating which statistics to consider.
* @param minBound Array indicating minimum bounds for complex computations.
* @param maxBound Array indicating maximum bounds for complex computations.
* @param numBins Array indicating the number of bins for complex computations.
* @param rangeData List of the possible range to calculate the statistics.
* @param localStats Boolean indicating if the statistics must be stored for each range.
* @param hints The <code>RenderingHints</code> to use.
* @return The <code>RenderedOp</code> source image.
* @throws IllegalArgumentException if <code>source</code> is <code>null</code>.
*/
public static RenderedOp create(RenderedImage source, RenderedImage classifier,
AffineTransform transform, List<ROI> roilist, Range noData, ROI mask,
boolean useROIAccessor, int[] bands, StatsType[] stats, double[] minBound,
double[] maxBound, int[] numBins, List<Range> rangeData, boolean localStats,
RenderingHints hints) {
// Creation of a parameterBlockJAI containing all the operation parameters
ParameterBlockJAI pb = new ParameterBlockJAI("Zonal", RenderedRegistryMode.MODE_NAME);
// Source image
pb.setSource(source, 0);
// Image parameters
pb.setParameter("classifier", classifier);
pb.setParameter("transform", transform);
pb.setParameter("roilist", roilist);
pb.setParameter("NoData", noData);
pb.setParameter("mask", mask);
pb.setParameter("useROIAccessor", useROIAccessor);
pb.setParameter("bands", bands);
pb.setParameter("stats", stats);
pb.setParameter("minbound", minBound);
pb.setParameter("maxbound", maxBound);
pb.setParameter("numbin", numBins);
pb.setParameter("rangeData", rangeData);
pb.setParameter("localStats", localStats);
// RenderedImage creation
return JAI.create("Zonal", pb, hints);
}
/**
* Performs statistical operations on different image zones defined by the input geometry list.
*
* <p>
* Creates a <code>ParameterBlockJAI</code> from all supplied arguments except <code>hints</code> and invokes
* {@link JAI#create(String,ParameterBlock,RenderingHints)}.
*
* @see JAI
* @see ParameterBlockJAI
* @see RenderedOp
*
* @param source <code>RenderedImage</code> source image.
* @param classifier <code>RenderedImage</code> optional classifier image(Integral dataType).
* @param transform affine transformation used for mapping source image on the classifier.
* @param roilist list of all the geometries.
* @param NoData No Data range used for calculation.
* @param mask optional mask for reducing the computations on a selected ROI.
* @param useROIAccessor boolean indicating if a ROI RasterAccessor should be used during computations with the mask.
* @param bands Array indicating which band to consider.
* @param stats Array indicating which statistics to consider.
* @param rangeData List of the possible range to calculate the statistics.
* @param localStats Boolean indicating if the statistics must be stored for each range.
* @return The <code>RenderedOp</code> source image.
* @throws IllegalArgumentException if <code>source</code> is <code>null</code>.
*/
public static RenderedOp create(RenderedImage source, RenderedImage classifier,
AffineTransform transform, List<ROI> roilist, Range noData, ROI mask,
boolean useROIAccessor, int[] bands, StatsType[] stats, List<Range> rangeData,
boolean localStats, RenderingHints hints) {
return create(source, classifier, transform, roilist, noData, mask, useROIAccessor, bands,
stats, null, null, null, rangeData, localStats, hints);
}
}