/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2015, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.process.raster;
import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader;
import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReaderSpi;
import it.geosolutions.jaiext.stats.Statistics;
import it.geosolutions.jaiext.stats.Statistics.StatsType;
import it.geosolutions.jaiext.zonal.ZoneGeometry;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.media.jai.PlanarImage;
import junit.framework.Assert;
import org.geotools.coverage.CoverageFactoryFinder;
import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.data.DataStore;
import org.geotools.data.FeatureSource;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.WorldFileReader;
import org.geotools.data.property.PropertyDataStore;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.test.TestData;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.operation.MathTransform;
/**
* This test-class checks the functionalities of the {@link RasterZonalStatistics2} process. The test is performed by comparing the results of the
* process with the previously known statistics for each geometry.
*
* @author geosolutions
*
*/
public class ZonalStatsProcess2Test extends Assert {
/**
* ZonalStats process
*/
private RasterZonalStatistics2 process;
/**
* Datastore containing the input features
*/
private DataStore ds;
@Before
public void setup() throws Exception {
// Preparation of the process
process = new RasterZonalStatistics2();
// Selection of the input files
File file = TestData.file(this, null);
ds = new PropertyDataStore(file);
TestData.unzipFile(this, "test.zip");
}
@After
public void tearDown() {
ds.dispose();
}
@Test
public void simpleZonalStatsProcess() throws Exception {
DataStore store = null;
TIFFImageReader reader = null;
GridCoverage2D coverage2D = null;
GridCoverage2D covClassificator = null;
SimpleFeatureIterator iterator = null;
try {
// build the feature collection
final File fileshp = TestData.file(this, "testpolygon.shp");
store = FileDataStoreFinder.getDataStore(fileshp.toURI().toURL());
assertNotNull(store);
assertTrue(store instanceof ShapefileDataStore);
FeatureSource<SimpleFeatureType, SimpleFeature> featureSource = store
.getFeatureSource(store.getNames().get(0));
SimpleFeatureCollection featureCollection = (SimpleFeatureCollection) featureSource
.getFeatures();
iterator = featureCollection.features();
List<SimpleFeature> zones = new ArrayList<SimpleFeature>(featureCollection.size());
while (iterator.hasNext()) {
SimpleFeature feature = iterator.next();
zones.add(feature);
}
// build the DataFile
final File tiff = TestData.file(this, "test.tif");
final File tfw = TestData.file(this, "test.tfw");
reader = (it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReader) new TIFFImageReaderSpi()
.createReaderInstance();
assertNotNull(reader);
reader.setInput(ImageIO.createImageInputStream(tiff));
final BufferedImage image = reader.read(0);
reader.dispose();
// Transformation from the Raster space to the Model space
final MathTransform transform = new WorldFileReader(tfw).getTransform();
// Creation of the data coverage
coverage2D = CoverageFactoryFinder.getGridCoverageFactory(null).create(
"coverage",
image,
new GridGeometry2D(new GridEnvelope2D(PlanarImage.wrapRenderedImage(image)
.getBounds()), transform, DefaultGeographicCRS.WGS84),
new GridSampleDimension[] { new GridSampleDimension("coverage") }, null, null);
assertNotNull(coverage2D);
// build the classificator
// generate the classificator image
final BufferedImage imageClassificator = new BufferedImage(120, 80,
BufferedImage.TYPE_BYTE_INDEXED);
final WritableRaster raster = imageClassificator.getRaster();
for (int i = raster.getWidth(); --i >= 0;) {
for (int j = raster.getHeight(); --j >= 0;) {
// create a simple raster used for classification
int sampleValue = (i % 2 == 0) ? 1 : 2;
raster.setSample(i, j, 0, sampleValue);
}
}
// create the coverage for the classification layer
covClassificator = CoverageFactoryFinder.getGridCoverageFactory(null).create(
"coverageClassificator",
imageClassificator,
new GridGeometry2D(new GridEnvelope2D(PlanarImage.wrapRenderedImage(
imageClassificator).getBounds()), coverage2D.getEnvelope()),
new GridSampleDimension[] { new GridSampleDimension("coverage") }, null, null);
assertNotNull(coverage2D);
// Statistics definition
StatsType[] def = new StatsType[] { StatsType.MIN, StatsType.MAX, StatsType.SUM,
StatsType.MEAN, StatsType.DEV_STD };
// invoke the process
List<ZoneGeometry> zoneListStart = process.execute(coverage2D, null, zones,
covClassificator, null, null, false, null, def, null, null, null, null, false);
// Reverse of the list due to a variation on the code
List<ZoneGeometry> zoneList = new ArrayList<ZoneGeometry>(zoneListStart);
// Zone 0
ZoneGeometry geo0 = zoneList.get(0);
// Class 1
Statistics[] statistics01 = geo0.getStatsPerBandNoRange(0, 1);
double min01 = (Double) statistics01[0].getResult();
double max01 = (Double) statistics01[1].getResult();
double mean01 = (Double) statistics01[3].getResult();
double sum01 = (Double) statistics01[2].getResult();
double dev_std01 = (Double) statistics01[4].getResult();
// Percentual variation between the correct statistics and the calculated
double minResult01 = Math.abs(1251 - min01) / 1251 * 100;
double maxResult01 = Math.abs(1683 - max01) / 1683 * 100;
double meanResult01 = Math.abs(1353.75 - mean01) / 1353.75 * 100;
double sumResult01 = Math.abs(894829 - sum01) / 894829 * 100;
double dev_stdResult01 = Math.abs(69.15 - dev_std01) / 69.15 * 100;
assertTrue(minResult01 < 5);
assertTrue(maxResult01 < 5);
assertTrue(meanResult01 < 5);
assertTrue(sumResult01 < 5);
assertTrue(dev_stdResult01 < 5);
// Class 2
Statistics[] statistics02 = geo0.getStatsPerBandNoRange(0, 2);
double min02 = (Double) statistics02[0].getResult();
double max02 = (Double) statistics02[1].getResult();
double mean02 = (Double) statistics02[3].getResult();
double sum02 = (Double) statistics02[2].getResult();
double dev_std02 = (Double) statistics02[4].getResult();
// Percentual variation between the correct statistics and the calculated
double minResult02 = Math.abs(1251 - min02) / 1251 * 100;
double maxResult02 = Math.abs(1589 - max02) / 1589 * 100;
double meanResult02 = Math.abs(1357.7 - mean02) / 1357.7 * 100;
double sumResult02 = Math.abs(944959 - sum02) / 944959 * 100;
double dev_stdResult02 = Math.abs(70.23 - dev_std02) / 70.23 * 100;
assertTrue(minResult02 < 5);
assertTrue(maxResult02 < 5);
assertTrue(meanResult02 < 5);
assertTrue(sumResult02 < 5);
assertTrue(dev_stdResult02 < 5);
// Zone 1
ZoneGeometry geo1 = zoneList.get(1);
// Class 1
Statistics[] statistics11 = geo1.getStatsPerBandNoRange(0, 1);
double min11 = (Double) statistics11[0].getResult();
double max11 = (Double) statistics11[1].getResult();
double mean11 = (Double) statistics11[3].getResult();
double sum11 = (Double) statistics11[2].getResult();
double dev_std11 = (Double) statistics11[4].getResult();
// Percentual variation between the correct statistics and the calculated
double minResult11 = Math.abs(1191 - min11) / 1191 * 100;
double maxResult11 = Math.abs(1411 - max11) / 1411 * 100;
double meanResult11 = Math.abs(1253.13 - mean11) / 1253.13 * 100;
double sumResult11 = Math.abs(904757 - sum11) / 904757 * 100;
double dev_stdResult11 = Math.abs(42.39 - dev_std11) / 42.39 * 100;
assertTrue(minResult11 < 5);
assertTrue(maxResult11 < 5);
assertTrue(meanResult11 < 5);
assertTrue(sumResult11 < 5);
assertTrue(dev_stdResult11 < 5);
// Class 2
Statistics[] statistics12 = geo1.getStatsPerBandNoRange(0, 2);
double min12 = (Double) statistics12[0].getResult();
double max12 = (Double) statistics12[1].getResult();
double mean12 = (Double) statistics12[3].getResult();
double sum12 = (Double) statistics12[2].getResult();
double dev_std12 = (Double) statistics12[4].getResult();
// Percentual variation between the correct statistics and the calculated
double minResult12 = Math.abs(1192 - min12) / 1192 * 100;
double maxResult12 = Math.abs(1430 - max12) / 1430 * 100;
double meanResult12 = Math.abs(1254.38 - mean12) / 1254.38 * 100;
double sumResult12 = Math.abs(883082 - sum12) / 883082 * 100;
double dev_stdResult12 = Math.abs(43.46 - dev_std12) / 43.46 * 100;
assertTrue(minResult12 < 5);
assertTrue(maxResult12 < 5);
assertTrue(meanResult12 < 5);
assertTrue(sumResult12 < 5);
assertTrue(dev_stdResult12 < 5);
// Zone 2
ZoneGeometry geo2 = zoneList.get(2);
// Class 1
Statistics[] statistics21 = geo2.getStatsPerBandNoRange(0, 1);
double min21 = (Double) statistics21[0].getResult();
double max21 = (Double) statistics21[1].getResult();
double mean21 = (Double) statistics21[3].getResult();
double sum21 = (Double) statistics21[2].getResult();
double dev_std21 = (Double) statistics21[4].getResult();
// Percentual variation between the correct statistics and the calculated
double minResult21 = Math.abs(1178 - min21) / 1178 * 100;
double maxResult21 = Math.abs(1351 - max21) / 1351 * 100;
double meanResult21 = Math.abs(1279.47 - mean21) / 1279.47 * 100;
double sumResult21 = Math.abs(509230 - sum21) / 509230 * 100;
double dev_stdResult21 = Math.abs(35.21 - dev_std21) / 35.21 * 100;
assertTrue(minResult21 < 5);
assertTrue(maxResult21 < 5);
assertTrue(meanResult21 < 5);
assertTrue(sumResult21 < 5);
assertTrue(dev_stdResult21 < 5);
// Class 2
Statistics[] statistics22 = geo2.getStatsPerBandNoRange(0, 2);
double min22 = (Double) statistics22[0].getResult();
double max22 = (Double) statistics22[1].getResult();
double mean22 = (Double) statistics22[3].getResult();
double sum22 = (Double) statistics22[2].getResult();
double dev_std22 = (Double) statistics22[4].getResult();
// Percentual variation between the correct statistics and the calculated
double minResult22 = Math.abs(1189 - min22) / 1189 * 100;
double maxResult22 = Math.abs(1348 - max22) / 1348 * 100;
double meanResult22 = Math.abs(1280.87 - mean22) / 1280.87 * 100;
double sumResult22 = Math.abs(490572 - sum22) / 490572 * 100;
double dev_stdResult22 = Math.abs(32.66 - dev_std22) / 32.66 * 100;
assertTrue(minResult22 < 5);
assertTrue(maxResult22 < 5);
assertTrue(meanResult22 < 5);
assertTrue(sumResult22 < 5);
assertTrue(dev_stdResult22 < 5);
} finally {
try {
if (store != null) {
store.dispose();
}
} catch (Exception e) {
}
try {
if (reader != null) {
reader.dispose();
}
} catch (Exception e) {
}
try {
if (coverage2D != null) {
coverage2D.dispose(true);
}
} catch (Exception e) {
}
try {
if (covClassificator != null) {
covClassificator.dispose(true);
}
} catch (Exception e) {
}
try {
if (iterator != null) {
iterator.close();
}
} catch (Exception e) {
}
}
}
}