/* JAI-Ext - OpenSource Java Advanced Image Extensions Library * http://www.geo-solutions.it/ * Copyright 2016 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.threshold; import static org.junit.Assert.assertEquals; import it.geosolutions.jaiext.range.Range; import it.geosolutions.jaiext.range.RangeFactory; import it.geosolutions.jaiext.testclasses.TestBase; import it.geosolutions.rendered.viewer.RenderedImageBrowser; import java.awt.Point; import java.awt.Rectangle; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.renderable.ParameterBlock; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.media.jai.ROI; import javax.media.jai.ROIShape; import javax.media.jai.RenderedOp; import javax.media.jai.TiledImage; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; public class ThresholdTest extends TestBase { /** Logger */ private Logger logger = Logger.getLogger(ThresholdTest.class.getName()); /** Tolerance parameter used in comparison */ private static final double TOLERANCE = 0.1d; /** Input data used for testing */ private static RenderedImage[] testImages; /** NoData Range for Byte dataType */ private static Range noDataByte; /** NoData Range for Ushort dataType */ private static Range noDataUShort; /** NoData Range for Short dataType */ private static Range noDataShort; /** NoData Range for Int dataType */ private static Range noDataInt; /** NoData Range for Float dataType */ private static Range noDataFloat; /** NoData Range for Double dataType */ private static Range noDataDouble; /** ROI used in tests */ private static ROI roiObject; /** Value to set as Output NoData */ private static double destNoData; @BeforeClass public static void initialSetup() { // NoData definition byte noDataB = 50; short noDataS = 50; int noDataI = 50; float noDataF = 50; double noDataD = 50; // Image Creation testImages = new RenderedImage[6]; IMAGE_FILLER = true; testImages[DataBuffer.TYPE_BYTE] = createTestImage(DataBuffer.TYPE_BYTE, DEFAULT_WIDTH, DEFAULT_HEIGHT, noDataB, false, 3, 255); // 0 testImages[DataBuffer.TYPE_USHORT] = createTestImage(DataBuffer.TYPE_USHORT, DEFAULT_WIDTH, DEFAULT_HEIGHT, noDataS, false, 3); // 1 testImages[DataBuffer.TYPE_SHORT] = createTestImage(DataBuffer.TYPE_SHORT, DEFAULT_WIDTH, DEFAULT_HEIGHT, noDataS, false, 3); // 2 testImages[DataBuffer.TYPE_INT] = createTestImage(DataBuffer.TYPE_INT, DEFAULT_WIDTH, DEFAULT_HEIGHT, noDataI, false, 3); // 3 testImages[DataBuffer.TYPE_FLOAT] = createTestImage(DataBuffer.TYPE_FLOAT, DEFAULT_WIDTH, DEFAULT_HEIGHT, noDataF, false, 3); // 4 testImages[DataBuffer.TYPE_DOUBLE] = createTestImage(DataBuffer.TYPE_DOUBLE, DEFAULT_WIDTH, DEFAULT_HEIGHT, noDataD, false, 3); // 5 IMAGE_FILLER = false; // No Data Ranges boolean minIncluded = true; boolean maxIncluded = true; noDataByte = RangeFactory.create(noDataB, minIncluded, noDataB, maxIncluded); noDataUShort = RangeFactory.createU(noDataS, minIncluded, noDataS, maxIncluded); noDataShort = RangeFactory.create(noDataS, minIncluded, noDataS, maxIncluded); noDataInt = RangeFactory.create(noDataI, minIncluded, noDataI, maxIncluded); noDataFloat = RangeFactory.create(noDataF, minIncluded, noDataF, maxIncluded, true); noDataDouble = RangeFactory.create(noDataD, minIncluded, noDataD, maxIncluded, true); // ROI creation Rectangle roiBounds = new Rectangle(5, 5, DEFAULT_WIDTH / 4, DEFAULT_HEIGHT / 4); roiObject = new ROIShape(roiBounds); // Destination No Data destNoData = 100.0; } @Test public void test() { boolean roiUsed = false; boolean nodataUsed = false; Range noData = null; ROI roi = null; double[] low = new double[] { 0.0, 20.0, 0.0 }; double[] high = new double[] { 10.0, 80.0, 100.0 }; double[] constant = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[0]); threshold[1] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[1]); threshold[2] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[2]); threshold[3] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[3]); threshold[4] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[4]); threshold[5] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[5]); check(testImages[0], threshold[0], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[1], threshold[1], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[2], threshold[2], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[3], threshold[3], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[4], threshold[4], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[5], threshold[5], low, high, constant, roiUsed, roi, nodataUsed, noDataDouble); // Operations for showing the image if (INTERACTIVE) { RenderedImageBrowser.showChain(threshold[1].createInstance(), false, false); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } // Disposal of the output image for (int i = 0; i < 6; i++) threshold[i].dispose(); } @Test public void testNoData() { boolean roiUsed = false; boolean nodataUsed = true; ROI roi = null; double[] low = new double[] { 0.0, 20.0, 0.0 }; double[] high = new double[] { 10.0, 80.0, 100.0 }; double[] constant = new double[] { 100, 100, 100 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noDataByte, destNoData, roi, low, high, constant, null, testImages[0]); threshold[1] = ThresholdDescriptor.create(noDataUShort, destNoData, roi, low, high, constant, null, testImages[1]); threshold[2] = ThresholdDescriptor.create(noDataShort, destNoData, roi, low, high, constant, null, testImages[2]); threshold[3] = ThresholdDescriptor.create(noDataInt, destNoData, roi, low, high, constant, null, testImages[3]); threshold[4] = ThresholdDescriptor.create(noDataFloat, destNoData, roi, low, high, constant, null, testImages[4]); threshold[5] = ThresholdDescriptor.create(noDataDouble, destNoData, roi, low, high, constant, null, testImages[5]); check(testImages[0], threshold[0], low, high, constant, roiUsed, roi, nodataUsed, noDataByte); check(testImages[1], threshold[1], low, high, constant, roiUsed, roi, nodataUsed, noDataUShort); check(testImages[2], threshold[2], low, high, constant, roiUsed, roi, nodataUsed, noDataShort); check(testImages[3], threshold[3], low, high, constant, roiUsed, roi, nodataUsed, noDataInt); check(testImages[4], threshold[4], low, high, constant, roiUsed, roi, nodataUsed, noDataFloat); check(testImages[5], threshold[5], low, high, constant, roiUsed, roi, nodataUsed, noDataDouble); // Disposal of the output image for (int i = 0; i < 6; i++) threshold[i].dispose(); } @Test public void testROI() { boolean roiUsed = true; boolean nodataUsed = false; ROI roi = roiObject; Range noData = null; double[] low = new double[] { 0.0, 20.0, 0.0 }; double[] high = new double[] { 10.0, 80.0, 100.0 }; double[] constant = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[0]); threshold[1] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[1]); threshold[2] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[2]); threshold[3] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[3]); threshold[4] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[4]); threshold[5] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[5]); check(testImages[0], threshold[0], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[1], threshold[1], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[2], threshold[2], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[3], threshold[3], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[4], threshold[4], low, high, constant, roiUsed, roi, nodataUsed, noData); check(testImages[5], threshold[5], low, high, constant, roiUsed, roi, nodataUsed, noData); // Disposal of the output image for (int i = 0; i < 6; i++) threshold[i].dispose(); } @Test public void testROINoData() { boolean roiUsed = true; boolean nodataUsed = true; ROI roi = roiObject; double[] low = new double[] { 0.0, 20.0, 0.0 }; double[] high = new double[] { 10.0, 80.0, 100.0 }; double[] constant = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noDataByte, destNoData, roi, low, high, constant, null, testImages[0]); threshold[1] = ThresholdDescriptor.create(noDataUShort, destNoData, roi, low, high, constant, null, testImages[1]); threshold[2] = ThresholdDescriptor.create(noDataShort, destNoData, roi, low, high, constant, null, testImages[2]); threshold[3] = ThresholdDescriptor.create(noDataInt, destNoData, roi, low, high, constant, null, testImages[3]); threshold[4] = ThresholdDescriptor.create(noDataFloat, destNoData, roi, low, high, constant, null, testImages[4]); threshold[5] = ThresholdDescriptor.create(noDataDouble, destNoData, roi, low, high, constant, null, testImages[5]); check(testImages[0], threshold[0], low, high, constant, roiUsed, roi, nodataUsed, noDataByte); check(testImages[1], threshold[1], low, high, constant, roiUsed, roi, nodataUsed, noDataUShort); check(testImages[2], threshold[2], low, high, constant, roiUsed, roi, nodataUsed, noDataShort); check(testImages[3], threshold[3], low, high, constant, roiUsed, roi, nodataUsed, noDataInt); check(testImages[4], threshold[4], low, high, constant, roiUsed, roi, nodataUsed, noDataFloat); check(testImages[5], threshold[5], low, high, constant, roiUsed, roi, nodataUsed, noDataDouble); // Disposal of the output image for (int i = 0; i < 6; i++) threshold[i].dispose(); } @Test public void testParam() { boolean roiUsed = false; boolean nodataUsed = false; ROI roi = null; Range noData = null; double[] low = new double[] { 0.0 }; double[] high = new double[] { 10.0 }; double[] constant = new double[] { 255 }; // arrays created for check the final image, ThresholdOpImage create similar arrays // from the input arrays double[] lowC = new double[] { 0.0, 0.0, 0.0 }; double[] highC = new double[] { 10.0, 10.0, 10.0 }; double[] constantC = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[0]); threshold[1] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[1]); threshold[2] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[2]); threshold[3] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[3]); threshold[4] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[4]); threshold[5] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[5]); check(testImages[0], threshold[0], lowC, highC, constantC, roiUsed, roi, nodataUsed, noData); check(testImages[1], threshold[1], lowC, highC, constantC, roiUsed, roi, nodataUsed, noData); check(testImages[2], threshold[2], lowC, highC, constantC, roiUsed, roi, nodataUsed, noData); check(testImages[3], threshold[3], lowC, highC, constantC, roiUsed, roi, nodataUsed, noData); check(testImages[4], threshold[4], lowC, highC, constantC, roiUsed, roi, nodataUsed, noData); check(testImages[5], threshold[5], lowC, highC, constantC, roiUsed, roi, nodataUsed, noData); // Disposal of the output image for (int i = 0; i < 6; i++) threshold[i].dispose(); } // wrong number of parameters - an IllegalArgumentException is expected @Test(expected = IllegalArgumentException.class) public void textExceptionParam() { boolean roiUsed = false; boolean nodataUsed = false; ROI roi = null; Range noData = null; double[] low = new double[] { 10.0, 20.0 }; double[] high = new double[] { 10.0 }; double[] constant = new double[] { 255 }; // arrays created for check the final image, ThresholdOpImage create similar arrays // from the input arrays double[] lowC = new double[] { 0.0, 0.0, 0.0 }; double[] highC = new double[] { 10.0, 10.0, 10.0 }; double[] constantC = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[0]); } // wrong number of parameters - an IllegalArgumentException is expected @Test(expected = IllegalArgumentException.class) public void textExceptionParam2() { boolean roiUsed = false; boolean nodataUsed = false; ROI roi = null; Range noData = null; double[] low = new double[] {}; double[] high = new double[] { 10.0 }; double[] constant = new double[] { 255 }; // arrays created for check the final image, ThresholdOpImage create similar arrays // from the input arrays double[] lowC = new double[] { 0.0, 0.0, 0.0 }; double[] highC = new double[] { 10.0, 10.0, 10.0 }; double[] constantC = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[0]); } // low value > high value - an IllegalArgumentException is expected @Test(expected = IllegalArgumentException.class) public void textExceptionParam3() { boolean roiUsed = false; boolean nodataUsed = false; ROI roi = null; Range noData = null; double[] low = new double[] { 50 }; double[] high = new double[] { 20 }; double[] constant = new double[] { 255 }; // arrays created for check the final image, ThresholdOpImage create similar arrays // from the input arrays double[] lowC = new double[] { 0.0, 0.0, 0.0 }; double[] highC = new double[] { 10.0, 10.0, 10.0 }; double[] constantC = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, testImages[0]); } // source image is null - an IllegalArgumentException is expected @Test(expected = IllegalArgumentException.class) public void textExceptionParam4() { boolean roiUsed = false; boolean nodataUsed = false; ROI roi = null; Range noData = null; double[] low = new double[] { 50 }; double[] high = new double[] { 20 }; double[] constant = new double[] { 255 }; // arrays created for check the final image, ThresholdOpImage create similar arrays // from the input arrays double[] lowC = new double[] { 0.0, 0.0, 0.0 }; double[] highC = new double[] { 10.0, 10.0, 10.0 }; double[] constantC = new double[] { 255, 255, 255 }; // Threshold operation RenderedOp[] threshold = new RenderedOp[6]; threshold[0] = ThresholdDescriptor.create(noData, destNoData, roi, low, high, constant, null, null); } private void check(RenderedImage src, RenderedOp dest, double[] low, double[] high, double[] con, boolean roiUsed, ROI roi, boolean nodataUsed, Range noData) { int tileWidth = dest.getTileWidth(); int tileHeight = dest.getTileHeight(); int minTileX = dest.getMinTileX(); int minTileY = dest.getMinTileY(); int numXTiles = dest.getNumXTiles(); int numYTiles = dest.getNumYTiles(); int maxTileX = minTileX + numXTiles; int maxTileY = minTileY + numYTiles; // Ensure same size assertEquals(dest.getWidth(), src.getWidth()); assertEquals(dest.getHeight(), src.getHeight()); assertEquals(dest.getMinX(), src.getMinX()); assertEquals(dest.getMinY(), src.getMinY()); assertEquals(minTileX, src.getMinTileX()); assertEquals(minTileY, src.getMinTileY()); assertEquals(numXTiles, src.getNumXTiles()); assertEquals(numYTiles, src.getNumYTiles()); assertEquals(tileWidth, src.getTileWidth()); assertEquals(tileHeight, src.getTileHeight()); int srcBands = src.getSampleModel().getNumBands(); int dstBands = dest.getNumBands(); assertEquals(srcBands, dstBands); boolean valid = true; // Check on all the pixels if they have been calculate correctly for (int tileX = minTileX; tileX < maxTileX; tileX++) { for (int tileY = minTileY; tileY < maxTileY; tileY++) { Raster tile = dest.getTile(tileX, tileY); Raster srcTile = src.getTile(tileX, tileY); int minX = tile.getMinX(); int minY = tile.getMinY(); int maxX = minX + tileWidth - 1; int maxY = minY + tileHeight - 1; int minXsrc = srcTile.getMinX(); int minYsrc = srcTile.getMinY(); int xsrc = minXsrc; for (int x = minX; x <= maxX; x++) { int ysrc = minYsrc; for (int y = minY; y <= maxY; y++) { boolean isValidRoi = !roiUsed || (roiUsed && roi.contains(x, y)); if (isValidRoi) { for (int b = 0; b < dstBands; b++) { // Getting the result double samplesource = srcTile.getSampleDouble(xsrc, ysrc, b); double result = tile.getSampleDouble(x, y, b); if (nodataUsed && noData.contains(samplesource)) { assertEquals(result, destNoData, TOLERANCE); // if samplesource is in the range, result should be equal to con[b] } else if (samplesource >= low[b] && samplesource <= high[b]) { if (result != con[b]) { valid = false; } } logger.log(Level.FINE, "srcsample: " + samplesource + " dstsample: " + tile.getSampleDouble(x, y, b) + " low: " + low[b] + " high: " + high[b] + " constant: " + con[b]); } } else { for (int b = 0; b < dstBands; b++) { assertEquals(tile.getSampleDouble(x, y, b), destNoData, TOLERANCE); } } ysrc++; } xsrc++; } } } } }