/* 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.iterators; import static org.junit.Assert.assertEquals; import java.awt.image.ComponentSampleModel; import java.awt.image.DataBuffer; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import javax.media.jai.TiledImage; import javax.media.jai.iterator.RandomIter; import org.junit.BeforeClass; import org.junit.Test; /** * J-unit TestClass used for checking the functionalities of all the iterators. The tests called testRandomIterXXX creates a RandomIter with 3 * different data types and with 3 different RandomIter types: * <ul> * <li>With or without cached tiles.</li> * <li>With or without position array pre calculation (If this array is not calculated the tiles are always not cached).</li> * </ul> * * The evaluating the capability of the various type of RandomIter to get the correct samples or pixels, with the help of the old kind of RandomIter, * an array of 4 pixels has been stored for every data type and every RandomIter type. Other 3 tests are used for showing the calculation speed of the * selected RandomIter type(With or without cache, with or without array precalc). This RandomIter can be selected by passing the integral parameter * JAI.Ext.TestSelector to the JVM(0 = cached tiles, pre calculation; 1 = no cached tiles, pre calculation, 2 = no cached tiles, no pre calculation). * The speed tests can be tuned by changing the number of the benchmark and not benchmark cycles with the 2 parameters JAI.Ext.BenchmarkCycles and * JAI.Ext.NotBenchmarkCycles (default 1 and 0 respectively). * */ public class RandomIterTest { /** Number of benchmark iterations (Default 1) */ private final static Integer BENCHMARK_ITERATION = Integer.getInteger( "JAI.Ext.BenchmarkCycles", 1); /** Number of not benchmark iterations (Default 0) */ private final static int NOT_BENCHMARK_ITERATION = Integer.getInteger( "JAI.Ext.NotBenchmarkCycles", 0); /** Test selector for the speed test */ private final static int TEST_SELECTOR = Integer.getInteger("JAI.Ext.TestSelector",0); /** Test selector for the speed test */ private final static boolean SUBSEQUENCY = Boolean.getBoolean("JAI.Ext.Subsequency"); /** expected values from the RandomIterFallbackByte on an Integer image */ private static int[] valueArrayByte; /** expected values from the RandomIterFallbackShort on an Integer image */ private static int[] valueArrayShort; /** expected values from the RandomIterFallbackInt on an Integer image */ private static int[] valueArrayInt; /** expected values from the RandomIterFallbackByte on a Float image */ private static float[] valueArrayByteIMGFloat; /** expected values from the RandomIterFallbackShort on a Float image */ private static float[] valueArrayShortIMGFloat; /** expected values from the RandomIterFallbackInt on a Float image */ private static float[] valueArrayIntIMGFloat; /** expected values from the RandomIterFallbackByte on a Double image */ private static double[] valueArrayByteIMGDouble; /** expected values from the RandomIterFallbackShort on a Double image */ private static double[] valueArrayShortIMGDouble; /** expected values from the RandomIterFallbackInt on a Double image */ private static double[] valueArrayIntIMGDouble; /** Indexes of the expected values */ private static int[][] indexArray = new int[][] {{ 1, 5 }, { 40, 5 }, { 80, 5 }, { 250, 5 }}; /** Integral test image for RandomIterFallbackByte */ private static RenderedImage testImageByte; /** Integral test image for RandomIterFallbackShort */ private static RenderedImage testImageShort; /** Integral test image for RandomIterFallbackInt */ private static RenderedImage testImageInt; /** Float test image for RandomIterFallbackByte */ private static RenderedImage testImageByteIMGFloat; /** Float test image for RandomIterFallbackShort */ private static RenderedImage testImageShortIMGFloat; /** Float test image for RandomIterFallbackInt */ private static RenderedImage testImageIntIMGFloat; /** Double test image for RandomIterFallbackByte */ private static RenderedImage testImageByteIMGDouble; /** Double test image for RandomIterFallbackShort */ private static RenderedImage testImageShortIMGDouble; /** Double test image for RandomIterFallbackInt */ private static RenderedImage testImageIntIMGDouble; /** JAI RandomIter used for integral image */ private static RandomIter iterByte; /** JAI RandomIter used for integral image */ private static RandomIter iterShort; /** JAI RandomIter used for integral image */ private static RandomIter iterInt; /** JAI RandomIter used for float image */ private static RandomIter iterByteIMGFloat; /** JAI RandomIter used for float image */ private static RandomIter iterShortIMGFloat; /** JAI RandomIter used for float image */ private static RandomIter iterIntIMGFloat; /** JAI RandomIter used for double image */ private static RandomIter iterByteIMGDouble; /** JAI RandomIter used for double image */ private static RandomIter iterShortIMGDouble; /** JAI RandomIter used for double image */ private static RandomIter iterIntIMGDouble; /** Variable used as tolerance for comparing double or float values */ private final double DELTA = 0.01d; @BeforeClass public static void imagePreparation() { // IMAGE CREATIONS testImageByte = createTestImage(DataBuffer.TYPE_INT, 254, 254, 64, 64); testImageByteIMGFloat = createTestImage(DataBuffer.TYPE_FLOAT, 254, 254, 64, 64); testImageByteIMGDouble = createTestImage(DataBuffer.TYPE_DOUBLE, 254, 254, 64, 64); testImageShort = createTestImage(DataBuffer.TYPE_INT, 512, 254, 2, 64); testImageShortIMGFloat = createTestImage(DataBuffer.TYPE_INT, 512, 254, 2, 64); testImageShortIMGDouble = createTestImage(DataBuffer.TYPE_INT, 512, 254, 2, 64); testImageInt = createTestImage(DataBuffer.TYPE_INT, Short.MAX_VALUE * 2, 254, 1, 64); testImageIntIMGFloat = createTestImage(DataBuffer.TYPE_INT, Short.MAX_VALUE * 2, 254, 1, 64); testImageIntIMGDouble = createTestImage(DataBuffer.TYPE_INT, Short.MAX_VALUE * 2, 1024, 1, 64); // JAI INTERPOLATORS CREATIONS. USED ONLY FOR CALCULATING THE EXPECTED VALUES. iterByte = javax.media.jai.iterator.RandomIterFactory.create(testImageByte, null); iterShort = javax.media.jai.iterator.RandomIterFactory.create(testImageShort, null); iterInt = javax.media.jai.iterator.RandomIterFactory.create(testImageInt, null); iterByteIMGFloat = javax.media.jai.iterator.RandomIterFactory.create(testImageByteIMGFloat, null); iterShortIMGFloat = javax.media.jai.iterator.RandomIterFactory.create( testImageShortIMGFloat, null); iterIntIMGFloat = javax.media.jai.iterator.RandomIterFactory.create(testImageIntIMGFloat, null); iterByteIMGDouble = javax.media.jai.iterator.RandomIterFactory.create( testImageByteIMGDouble, null); iterShortIMGDouble = javax.media.jai.iterator.RandomIterFactory.create( testImageShortIMGDouble, null); iterIntIMGDouble = javax.media.jai.iterator.RandomIterFactory.create(testImageIntIMGDouble, null); // INITIALIZATION AND SAVING OF THE EXPECTED VALUES. valueArrayByte = new int[4]; valueArrayShort = new int[4]; valueArrayInt = new int[4]; valueArrayByteIMGFloat = new float[4]; valueArrayShortIMGFloat = new float[4]; valueArrayIntIMGFloat = new float[4]; valueArrayByteIMGDouble = new double[4]; valueArrayShortIMGDouble = new double[4]; valueArrayIntIMGDouble = new double[4]; // Store of the image data calculated for (int i = 0; i < indexArray.length; i++) { int x = indexArray[i][0]; int y = indexArray[i][1]; valueArrayByte[i] = iterByte.getSample(x, y, 0); valueArrayShort[i] = iterShort.getSample(x, y, 0); valueArrayInt[i] = iterInt.getSample(x, y, 0); valueArrayByteIMGFloat[i] = iterByteIMGFloat.getSampleFloat(x, y, 0); valueArrayShortIMGFloat[i] = iterShortIMGFloat.getSampleFloat(x, y, 0); valueArrayIntIMGFloat[i] = iterIntIMGFloat.getSampleFloat(x, y, 0); valueArrayByteIMGDouble[i] = iterByteIMGDouble.getSampleDouble(x, y, 0); valueArrayShortIMGDouble[i] = iterShortIMGDouble.getSampleDouble(x, y, 0); valueArrayIntIMGDouble[i] = iterIntIMGDouble.getSampleDouble(x, y, 0); } } // This tests is used for the RandomIterFallbackByte iterator on Integral,Float and Double images. @Test public void testRandomIterByte() { testRandomIterInt(testImageByte, valueArrayByte, true, true); testRandomIterFloat(testImageByteIMGFloat, valueArrayByteIMGFloat, true, true); testRandomIterDouble(testImageByteIMGDouble, valueArrayByteIMGDouble, true, true); } // This tests is used for the RandomIterFallbackByteNoCache iterator on Integral,Float and Double images. @Test public void testRandomIterByteNoCache() { testRandomIterInt(testImageByte, valueArrayByte, false, true); testRandomIterFloat(testImageByteIMGFloat, valueArrayByteIMGFloat, false, true); testRandomIterDouble(testImageByteIMGDouble, valueArrayByteIMGDouble, false, true); } // This tests is used for the RandomIterFallbackShort iterator on Integral,Float and Double images. @Test public void testRandomIterShort() { testRandomIterInt(testImageShort, valueArrayShort, true, true); testRandomIterFloat(testImageShortIMGFloat, valueArrayShortIMGFloat, true, true); testRandomIterDouble(testImageShortIMGDouble, valueArrayShortIMGDouble, true, true); } // This tests is used for the RandomIterFallbackShortNoCache iterator on Integral,Float and Double images. @Test public void testRandomIterShortNoCache() { testRandomIterInt(testImageShort, valueArrayShort, false, true); testRandomIterFloat(testImageShortIMGFloat, valueArrayShortIMGFloat, false, true); testRandomIterDouble(testImageShortIMGDouble, valueArrayShortIMGDouble, false, true); } // This tests is used for the RandomIterFallbackInt iterator on Integral,Float and Double images. @Test public void testRandomIterInt() { testRandomIterInt(testImageInt, valueArrayInt, true, true); testRandomIterFloat(testImageIntIMGFloat, valueArrayIntIMGFloat, true, true); testRandomIterDouble(testImageIntIMGDouble, valueArrayIntIMGDouble, true, true); } // This tests is used for the RandomIterFallbackIntNoCache iterator on Integral,Float and Double images. @Test public void testRandomIterIntNoCache() { testRandomIterInt(testImageInt, valueArrayInt, false, true); testRandomIterFloat(testImageIntIMGFloat, valueArrayIntIMGFloat, false, true); testRandomIterDouble(testImageIntIMGDouble, valueArrayIntIMGDouble, false, true); } // This tests is used for the RandomIterFallbackNoCacheNoArray iterator on Integral,Float and Double images. @Test public void testRandomIterNoArrayCalculation() { testRandomIterInt(testImageInt, valueArrayInt, false, false); testRandomIterFloat(testImageIntIMGFloat, valueArrayIntIMGFloat, false, false); testRandomIterDouble(testImageIntIMGDouble, valueArrayIntIMGDouble, false, false); } // This tests is used for the RandomIterFallbackByte speed test on an integral image. @Test public void testSpeed() { if (TEST_SELECTOR == 0) { testIteratorSpeed(testImageByte, true, true,SUBSEQUENCY); } } // This tests is used for the RandomIterFallbackByteNoCache speed test on an integral image. @Test public void testSpeedNoCached() { if (TEST_SELECTOR == 1) { testIteratorSpeed(testImageByte, false, true,SUBSEQUENCY); } } // This tests is used for the RandomIterFallbackNoCacheNoArray speed test on an integral image. @Test public void testSpeedNoArray() { if (TEST_SELECTOR == 2) { testIteratorSpeed(testImageByte, false, false,SUBSEQUENCY); } } /** Simple method for image creation */ public static RenderedImage createTestImage(int dataType, int width, int height, int tileW, int tileH) { // parameter block initialization int imageDim = width * height; final SampleModel sm; int numBands = 1; sm = new ComponentSampleModel(dataType, width, height, 3, width, new int[] { 0, imageDim, imageDim * 2 }); // Create the constant operation. TiledImage used = new TiledImage(sm, tileW, tileH); for (int b = 0; b < numBands; b++) { for (int j = 0; j < width; j++) { for (int k = 0; k < height; k++) { if (k < 255 && j < 255) { switch (dataType) { case DataBuffer.TYPE_BYTE: case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: case DataBuffer.TYPE_INT: int value = (int) (Math.random() * 10); used.setSample(j, k, b, value); break; case DataBuffer.TYPE_FLOAT: float valuef = (float) (Math.random() * 10); used.setSample(j, k, b, valuef); break; case DataBuffer.TYPE_DOUBLE: double valued = Math.random() * 10; used.setSample(j, k, b, valued); break; default: throw new IllegalArgumentException("Wrong data type"); } } } } } return used; } /** Method for testing the selected input RandomIter on an Integral image */ public void testRandomIterInt(RenderedImage img, int[] valueArray, boolean cachedTiles, boolean arrayCalculation) { RandomIter iter = RandomIterFactory.create(img, null, cachedTiles, arrayCalculation); int[] array = new int[3]; // Store of the image data calculated for (int i = 0; i < indexArray.length; i++) { int x = indexArray[i][0]; int y = indexArray[i][1]; int valueExpected = iter.getSample(x, y, 0); assertEquals(valueExpected, valueArray[i]); int valueExpectedArray = iter.getPixel(x, y, array)[0]; assertEquals(valueExpectedArray, valueArray[i]); } } /** Method for testing the selected input RandomIter on a Float image */ public void testRandomIterFloat(RenderedImage img, float[] valueArray, boolean cachedTiles, boolean arrayCalculation) { RandomIter iter = RandomIterFactory.create(img, null, cachedTiles, arrayCalculation); float[] array = new float[3]; // Store of the image data calculated for (int i = 0; i < indexArray.length; i++) { int x = indexArray[i][0]; int y = indexArray[i][1]; float valueExpected = iter.getSampleFloat(x, y, 0); assertEquals(valueExpected, valueArray[i], DELTA); float valueExpectedArray = iter.getPixel(x, y, array)[0]; assertEquals(valueExpectedArray, valueArray[i], DELTA); } } /** Method for testing the selected input RandomIter on a Double image */ public void testRandomIterDouble(RenderedImage img, double[] valueArray, boolean cachedTiles, boolean arrayCalculation) { RandomIter iter = RandomIterFactory.create(img, null, cachedTiles, arrayCalculation); double[] array = new double[3]; // Store of the image data calculated for (int i = 0; i < indexArray.length; i++) { int x = indexArray[i][0]; int y = indexArray[i][1]; double valueExpected = iter.getSampleDouble(x, y, 0); assertEquals(valueExpected, valueArray[i], DELTA); double valueExpectedArray = iter.getPixel(x, y, array)[0]; assertEquals(valueExpectedArray, valueArray[i], DELTA); } } /** Method for testing the one of the 3 types of RandomIter on the selected image */ public void testIteratorSpeed(RenderedImage img, boolean cachedTiles, boolean arrayCalculation, boolean subsequentIterator) { // RandomIter used RandomIter iter = RandomIterFactory.create(img, null, cachedTiles, arrayCalculation); String descriptor = ""; // String used for describing the result if (arrayCalculation) { descriptor += "ArrayCalculation "; if (cachedTiles) { descriptor += "Cached Tiles"; } else { descriptor += "No Cached Tiles"; } } else { descriptor += "No ArrayCalculation "; } int totalCycles = NOT_BENCHMARK_ITERATION + BENCHMARK_ITERATION; // Initialization of the statistics long mean = 0; long max = Long.MIN_VALUE; long min = Long.MAX_VALUE; // Image dimensions int imgMinX = testImageByte.getMinX(); int imgMinY = testImageByte.getMinY(); int imgWidth = testImageByte.getWidth(); int imgHeight = testImageByte.getHeight(); int x = imgMinX; int y = imgMinY; int xStep = (imgWidth-1)/totalCycles; int yStep = (imgHeight-1)/totalCycles; for (int i = 0; i < totalCycles; i++) { if(subsequentIterator){ // random pixel position x += xStep; y += yStep; }else{ // random pixel position x = (int) (Math.random() * imgWidth + imgMinX); y = (int) (Math.random() * imgHeight + imgMinY); } // selection of the sample long start = System.nanoTime(); iter.getSample(x, y, 0); long end = System.nanoTime() - start; // If the the first NOT_BENCHMARK_ITERATION cycles has been done, then the mean, maximum and minimum values are stored if (i > NOT_BENCHMARK_ITERATION - 1) { if (i == NOT_BENCHMARK_ITERATION) { mean = end; } else { mean = mean + end; } if (end > max) { max = end; } if (end < min) { min = end; } } } // Mean values double meanValue = mean / BENCHMARK_ITERATION; // Max and Min values stored as double double maxD = max; double minD = min; // Comparison between the mean times // Output System.out.println("\nMean value for RandomIterator with " + descriptor + " : " + meanValue + " nsec."); System.out.println("Maximum value for RandomIterator with " + descriptor + " : " + maxD + " nsec."); System.out.println("Minimum value for RandomIterator with " + descriptor + " : " + minD + " nsec."); iter.done(); } }