/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2014-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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import it.geosolutions.jaiext.JAIExt;
import it.geosolutions.jaiext.iterators.RandomIterFactory;
import it.geosolutions.jaiext.range.NoDataContainer;
import it.geosolutions.jaiext.range.Range;
import it.geosolutions.jaiext.range.RangeFactory;
import java.awt.Rectangle;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.media.jai.InterpolationBicubic;
import javax.media.jai.InterpolationBilinear;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.ROI;
import javax.media.jai.ROIShape;
import javax.media.jai.iterator.RandomIter;
import org.geotools.TestData;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GridFormatFinder;
import org.geotools.factory.GeoTools;
import org.geotools.image.ImageWorker;
import org.geotools.resources.coverage.CoverageUtilities;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opengis.coverage.grid.GridCoverageReader;
public class ScaleProcessTest {
/** Tolerance value used for double comparison */
private static final double TOLERANCE = 0.01;
/** Coverage to elaborate */
private static GridCoverage2D coverage;
/** Nearest Interpolation */
private static InterpolationNearest nearest;
/** Bilinear Interpolation */
private static InterpolationBilinear bilinear;
/** Bicubic Interpolation */
private static InterpolationBicubic bicubic;
/** Scale X parameter */
private static double scaleX;
/** Scale Y parameter */
private static double scaleY;
private static GridCoverage2D coverageNoData;
private static GridCoverage2D coverageROI;
private static GridCoverage2D coverageNoDataROI;
private static ROI roi;
@BeforeClass
public static void setup() throws FileNotFoundException, IOException {
JAIExt.initJAIEXT(true, true);
//Selection of the File to use
File tiff = TestData.file(ScaleProcessTest.class, "sample.tif");
// Reading of the file with the GeoTiff reader
AbstractGridFormat format = GridFormatFinder.findFormat(tiff);
// Get a reader for the selected format
GridCoverageReader reader = format.getReader(tiff);
// Read the input Coverage
coverage = (GridCoverage2D) reader.read(null);
// Coverage properties
Map properties = coverage.getProperties();
if(properties == null){
properties = new HashMap<>();
}
GridCoverageFactory gcf = new GridCoverageFactory(GeoTools.getDefaultHints());
// Same coverage with NoData Property
Map properties1 = new HashMap(properties);
CoverageUtilities.setNoDataProperty(properties1, RangeFactory.create((short)-1, (short)1));
coverageNoData = gcf.create("nodata", coverage.getRenderedImage(), coverage.getEnvelope(), coverage.getSampleDimensions(), null, properties1);
// Same Coverage with ROI Property
Map properties2 = new HashMap(properties);
roi = new ROIShape(new Rectangle(8, 8, 2, 2));
CoverageUtilities.setROIProperty(properties2, roi);
coverageROI = gcf.create("roi", coverage.getRenderedImage(), coverage.getEnvelope(), coverage.getSampleDimensions(), null, properties2);
// Same Coverage with ROI and NoData Property
Map properties3 = new HashMap(properties);
CoverageUtilities.setNoDataProperty(properties3, RangeFactory.create((short)-1, (short)-1));
CoverageUtilities.setROIProperty(properties3, roi);
coverageNoDataROI = gcf.create("roiNoData", coverage.getRenderedImage(), coverage.getEnvelope(), coverage.getSampleDimensions(), null, properties3);
// Reader disposal
reader.dispose();
// Definition of the interpolation type
nearest = new InterpolationNearest();
bilinear = new InterpolationBilinear();
bicubic = new InterpolationBicubic(8);
// Definition of the transformation. (The final image should be doubled and translated)
scaleX = 2d;
scaleY = 2d;
}
@AfterClass
public static void afterClass() {
JAIExt.initJAIEXT(false, true);
}
@Test
public void testNoInterp() throws IOException {
// Selection of the Scale process
ScaleCoverage process = new ScaleCoverage();
// Execution of the operation
GridCoverage2D result = process.execute(coverage, scaleX, scaleY, 0, 0,
null);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
}
@Test
public void testNoBackground() throws IOException {
// Selection of the Scale process
ScaleCoverage process = new ScaleCoverage();
// Execution of the operation
GridCoverage2D result = process.execute(coverage, scaleX, scaleY, 0, 0,
nearest);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
}
@Test
public void testIdentity() throws IOException {
// Selection of the Scale process
ScaleCoverage process = new ScaleCoverage();
// Execution of the operation
GridCoverage2D result = process.execute(coverage, 1, 1, 0, 0,
nearest);
// Check if the final image is correct
ensureCorrectTransformation(result, 1, 1);
}
@Test
public void testNearestInterp() throws IOException {
// Selection of the Scale process
ScaleCoverage process = new ScaleCoverage();
// Definition of the Transformation object to use (The final image should be doubled and translated)
// Execution of the operation
GridCoverage2D result = process.execute(coverage, scaleX, scaleY,0, 0,
nearest);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
}
@Test
public void testBilinearInterp() throws IOException {
// Selection of the Scale process
ScaleCoverage process = new ScaleCoverage();
// Definition of the Transformation object to use (The final image should be doubled and translated)
// Execution of the operation
GridCoverage2D result = process.execute(coverage, scaleX, scaleY, 0, 0,
bilinear);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
}
@Test
public void testBicubicInterp() throws IOException {
// Selection of the Affine process
ScaleCoverage process = new ScaleCoverage();
// Definition of the Transformation object to use (The final image should be doubled and translated)
// Execution of the operation
GridCoverage2D result = process.execute(coverage, scaleX, scaleY, 0, 0,
bicubic);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
}
@Test
public void testNoData() throws IOException {
// Selection of the Affine process
ScaleCoverage process = new ScaleCoverage();
// Definition of the Transformation object to use (The final image should be doubled and translated)
// Execution of the operation
GridCoverage2D result = process.execute(coverageNoData, scaleX, scaleY, 0, 0,
bicubic);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
// Check if the NoData property is present
NoDataContainer container = CoverageUtilities.getNoDataProperty(result);
assertNotNull(container);
Range nod = container.getAsRange();
assertEquals(nod.getMax().intValue(), 1);
assertEquals(nod.getMin().intValue(), -1);
// Check if all the values are equal to 0
ImageWorker w = new ImageWorker(result.getRenderedImage());
w.setNoData(null);
int max = (int) w.getMaximums()[0];
int min = (int) w.getMinimums()[0];
assertEquals(max, 0);
assertEquals(min, 0);
}
@Test
public void testROI() throws IOException {
// Selection of the Affine process
ScaleCoverage process = new ScaleCoverage();
// Definition of the Transformation object to use (The final image should be doubled and translated)
// Execution of the operation
GridCoverage2D result = process.execute(coverageROI, scaleX, scaleY, 0, 0,
nearest);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
// Check if the NoData property is present
NoDataContainer container = CoverageUtilities.getNoDataProperty(result);
assertNull(container);
// Check if the ROI property is present
ROI roiNew = CoverageUtilities.getROIProperty(result);
assertNotNull(roiNew);
// Check if ROI has been scaled
Rectangle bounds = roiNew.getBounds();
Rectangle inBounds = roi.getBounds();
assertEquals(bounds.x, inBounds.x * scaleX, 0.0001);
assertEquals(bounds.y, inBounds.y * scaleY, 0.0001);
assertEquals(bounds.width, inBounds.width * scaleX, 0.0001);
assertEquals(bounds.height, inBounds.height * scaleY, 0.0001);
RenderedImage img = result.getRenderedImage();
RandomIter it = RandomIterFactory.create(img, null, true, true);
int minX = img.getMinX();
int minY = img.getMinY();
int maxX = img.getWidth() + minX;
int maxY = img.getHeight() + minY;
for(int x = minX; x < maxX; x++){
for(int y = minY; y < maxY; y++){
int sample = it.getSample(x, y, 0);
if(!roiNew.contains(x, y)){
assertEquals(sample, 0);
}
}
}
}
@Test
public void testROINoData() throws IOException {
// Selection of the Affine process
ScaleCoverage process = new ScaleCoverage();
// Definition of the Transformation object to use (The final image should be doubled and translated)
// Execution of the operation
GridCoverage2D result = process.execute(coverageNoDataROI, scaleX, scaleY, 0, 0,
nearest);
// Check if the final image is correct
ensureCorrectTransformation(result, scaleX, scaleY);
// Check if the NoData property is present
NoDataContainer container = CoverageUtilities.getNoDataProperty(result);
assertNotNull(container);
// Check if the ROI property is present
ROI roiNew = CoverageUtilities.getROIProperty(result);
assertNotNull(roiNew);
// Check if ROI has been scaled
Rectangle bounds = roiNew.getBounds();
Rectangle inBounds = roi.getBounds();
assertEquals(bounds.x, inBounds.x * scaleX, 0.0001);
assertEquals(bounds.y, inBounds.y * scaleY, 0.0001);
assertEquals(bounds.width, inBounds.width * scaleX, 0.0001);
assertEquals(bounds.height, inBounds.height * scaleY, 0.0001);
RenderedImage img = result.getRenderedImage();
RandomIter it = RandomIterFactory.create(img, null, true, true);
int minX = img.getMinX();
int minY = img.getMinY();
int maxX = img.getWidth() + minX;
int maxY = img.getHeight() + minY;
for(int x = minX; x < maxX; x++){
for(int y = minY; y < maxY; y++){
int sample = it.getSample(x, y, 0);
if(!roiNew.contains(x, y)){
assertEquals(sample, 0);
}
}
}
}
/**
* Check if the Coverage is correctly transformed.
*
* @param result
* @param m00
* @param m11
* @param m02
* @param m12
*/
private void ensureCorrectTransformation(GridCoverage2D result, double m00, double m11) {
// Selection of the RenderedImages associated to the coverages
RenderedImage inputImage = coverage.getRenderedImage();
RenderedImage outputImage = result.getRenderedImage();
// Definition of the source image parameters
double srcMinX = inputImage.getMinX();
double srcMinY = inputImage.getMinY();
double srcHeight = inputImage.getHeight();
double srcWidth = inputImage.getWidth();
// Definition of the destination image parameters
double dstMinX = outputImage.getMinX();
double dstMinY = outputImage.getMinY();
double dstHeight = outputImage.getHeight();
double dstWidth = outputImage.getWidth();
// Calculation of the parameters
double actualH = srcHeight * m00;
double actualW = srcWidth * m11;
// Ensure the results are correct
assertEquals(srcMinX, dstMinX, TOLERANCE);
assertEquals(srcMinY, dstMinY, TOLERANCE);
assertEquals(dstHeight, actualH, TOLERANCE);
assertEquals(dstWidth, actualW, TOLERANCE);
}
}