sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 04/04: Add more interpolation tests. Contains a correction about the size of ResampledImage tiles.
Date Sun, 05 Apr 2020 20:31:59 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit c0ad361ea2c27195e5681162b4865372cb7fb46d
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sun Apr 5 19:25:24 2020 +0200

    Add more interpolation tests. Contains a correction about the size of ResampledImage tiles.
---
 .../java/org/apache/sis/image/ResampledImage.java  |   2 +-
 .../coverage/j2d/BandedSampleConverter.java        |   2 +-
 .../sis/internal/coverage/j2d/ImageLayout.java     |  37 ++++---
 .../org/apache/sis/image/ResampledImageTest.java   | 107 +++++++++++++++++++--
 4 files changed, 125 insertions(+), 23 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
index f9f1b05..b181a96 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/ResampledImage.java
@@ -132,7 +132,7 @@ public class ResampledImage extends ComputedImage {
     protected ResampledImage(final Rectangle bounds, final MathTransform toSource, final
RenderedImage source,
                              final Interpolation interpolation, final Number[] fillValues)
     {
-        super(ImageLayout.DEFAULT.createCompatibleSampleModel(source), source);
+        super(ImageLayout.DEFAULT.createCompatibleSampleModel(source, bounds), source);
         ArgumentChecks.ensureNonNull("interpolation", interpolation);
         ArgumentChecks.ensureStrictlyPositive("width",  width  = bounds.width);
         ArgumentChecks.ensureStrictlyPositive("height", height = bounds.height);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
index c890cd1..156212c 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/BandedSampleConverter.java
@@ -162,7 +162,7 @@ public class BandedSampleConverter extends ComputedImage {
         if (layout == null) {
             layout = ImageLayout.DEFAULT;
         }
-        final Dimension tile = layout.suggestTileSize(source);
+        final Dimension tile = layout.suggestTileSize(source, null);
         final BandedSampleModel sampleModel = RasterFactory.unique(
                 new BandedSampleModel(targetType, tile.width, tile.height, numBands));
         /*
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageLayout.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageLayout.java
index 2cf3ce4..ae0da95 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageLayout.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/j2d/ImageLayout.java
@@ -18,6 +18,7 @@ package org.apache.sis.internal.coverage.j2d;
 
 import java.util.Arrays;
 import java.awt.Dimension;
+import java.awt.Rectangle;
 import java.awt.image.ColorModel;
 import java.awt.image.IndexColorModel;
 import java.awt.image.RenderedImage;
@@ -177,15 +178,13 @@ public class ImageLayout {
      * <p>This method also checks whether the color model supports transparency. If
not, then this
      * method will not return a size that may result in the creation of partially empty tiles.</p>
      *
-     * @param  image  the image for which to derive a tile size, or {@code null}.
+     * @param  image   the image for which to derive a tile size, or {@code null}.
+     * @param  bounds  the bounds of the image to create, or {@code null} is same as {@code
image}.
      * @return suggested tile size for the given image.
      */
-    public Dimension suggestTileSize(final RenderedImage image) {
-        if (image == null) {
-            return new Dimension(preferredTileWidth, preferredTileHeight);
-        }
+    public Dimension suggestTileSize(final RenderedImage image, final Rectangle bounds) {
         boolean pt = allowPartialTiles;
-        if (pt) {
+        if (pt && image != null) {
             final ColorModel cm = image.getColorModel();
             if (pt = (cm != null)) {
                 if (cm instanceof IndexColorModel) {
@@ -201,10 +200,21 @@ public class ImageLayout {
          * operations may assume that a call to `source.getTile(…)` will return a tile
covering fully the
          * tile to compute.
          */
-        final boolean singleXTile = image.getNumXTiles() <= 1;
-        final boolean singleYTile = image.getNumYTiles() <= 1;
-        int width  =  singleXTile ? image.getWidth()  : image.getTileWidth();
-        int height =  singleYTile ? image.getHeight() : image.getTileHeight();
+        final boolean singleXTile, singleYTile;
+        final int width, height;
+        if (bounds != null) {
+            singleXTile = true;
+            singleYTile = true;
+            width  = bounds.width;
+            height = bounds.height;
+        } else if (image != null) {
+            singleXTile = image.getNumXTiles() <= 1;
+            singleYTile = image.getNumYTiles() <= 1;
+            width  = singleXTile ? image.getWidth()  : image.getTileWidth();
+            height = singleYTile ? image.getHeight() : image.getTileHeight();
+        } else {
+            return new Dimension(preferredTileWidth, preferredTileHeight);
+        }
         return new Dimension(toTileSize(width,  preferredTileWidth,  pt & singleXTile),
                              toTileSize(height, preferredTileHeight, pt & singleYTile));
     }
@@ -215,14 +225,15 @@ public class ImageLayout {
      * for determining the {@code sampleModel} argument of {@link ComputedImage}
      * constructor.
      *
-     * @param  image  the image form which to get a sample model.
+     * @param  image   the image form which to get a sample model.
+     * @param  bounds  the bounds of the image to create, or {@code null} is same as {@code
image}.
      * @return image sample model with preferred tile size.
      *
      * @see ComputedImage#ComputedImage(SampleModel, RenderedImage...)
      */
-    public SampleModel createCompatibleSampleModel(final RenderedImage image) {
+    public SampleModel createCompatibleSampleModel(final RenderedImage image, final Rectangle
bounds) {
         ArgumentChecks.ensureNonNull("image", image);
-        final Dimension tile = suggestTileSize(image);
+        final Dimension tile = suggestTileSize(image, bounds);
         SampleModel sm = image.getSampleModel();
         if (sm.getWidth() != tile.width || sm.getHeight() != tile.height) {
             sm = sm.createCompatibleSampleModel(tile.width, tile.height);
diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/ResampledImageTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/ResampledImageTest.java
index 5585cde..3b01c55 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/image/ResampledImageTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/image/ResampledImageTest.java
@@ -23,11 +23,15 @@ import java.awt.Point;
 import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferFloat;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
 import java.awt.image.WritableRaster;
 import java.awt.image.BandedSampleModel;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.NoninvertibleTransformException;
 import org.apache.sis.internal.coverage.j2d.TiledImage;
+import org.apache.sis.internal.coverage.j2d.RasterFactory;
 import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.test.TestUtilities;
@@ -49,7 +53,7 @@ public final strictfp class ResampledImageTest extends TestCase {
      * The source image. This is initialized to arbitrary values in two bands.
      * Location and number of tiles are random.
      */
-    private PlanarImage source;
+    private RenderedImage source;
 
     /**
      * The result of resampling {@link #source} image.
@@ -63,11 +67,11 @@ public final strictfp class ResampledImageTest extends TestCase {
     private AffineTransform sourceToTarget;
 
     /**
-     * Creates a rendered image with arbitrary tiles.
+     * Creates a rendered image with arbitrary tiles and some random values.
      *
      * @param  dataType  {@link DataBuffer#TYPE_SHORT} or {@link DataBuffer#TYPE_FLOAT}.
      */
-    private static PlanarImage createImage(final int dataType) {
+    private static PlanarImage createRandomImage(final int dataType) {
         final Random random  = TestUtilities.createRandomNumberGenerator();
         final int tileWidth  = random.nextInt(8) + 3;
         final int tileHeight = random.nextInt(8) + 3;
@@ -189,7 +193,7 @@ public final strictfp class ResampledImageTest extends TestCase {
      */
     @Test
     public void testNearestOnFloats() throws NoninvertibleTransformException {
-        source = createImage(DataBuffer.TYPE_FLOAT);
+        source = createRandomImage(DataBuffer.TYPE_FLOAT);
         createScaledByTwo(Interpolation.BILINEAR, -30, 12);
         verifyAtIntegerPositions();
     }
@@ -201,7 +205,7 @@ public final strictfp class ResampledImageTest extends TestCase {
      */
     @Test
     public void testNearestOnIntegers() throws NoninvertibleTransformException {
-        source = createImage(DataBuffer.TYPE_SHORT);
+        source = createRandomImage(DataBuffer.TYPE_SHORT);
         createScaledByTwo(Interpolation.BILINEAR, 18, 20);
         verifyAtIntegerPositions();
     }
@@ -213,7 +217,7 @@ public final strictfp class ResampledImageTest extends TestCase {
      */
     @Test
     public void testBilinearOnFloats() throws NoninvertibleTransformException {
-        source = createImage(DataBuffer.TYPE_FLOAT);
+        source = createRandomImage(DataBuffer.TYPE_FLOAT);
         createScaledByTwo(Interpolation.BILINEAR, -40, 50);
         verifyAtIntegerPositions();
         verifyAtMiddlePositions(1E-12);
@@ -226,7 +230,7 @@ public final strictfp class ResampledImageTest extends TestCase {
      */
     @Test
     public void testBilinearOnIntegers() throws NoninvertibleTransformException {
-        source = createImage(DataBuffer.TYPE_SHORT);
+        source = createRandomImage(DataBuffer.TYPE_SHORT);
         createScaledByTwo(Interpolation.BILINEAR, 40, -50);
         verifyAtIntegerPositions();
         verifyAtMiddlePositions(0.5);
@@ -249,7 +253,7 @@ public final strictfp class ResampledImageTest extends TestCase {
             }
         }
         source = new TiledImage(null, 3, 3, 0, 0, raster);
-        assertNull(source.verify());
+        assertNull(((TiledImage) source).verify());
         createScaledByTwo(Interpolation.BILINEAR, -2, -2);
         final PixelIterator pt = PixelIterator.create(target);
         assertResultEquals(pt, -0.5f, -1.0f,  0.5f);
@@ -269,8 +273,95 @@ public final strictfp class ResampledImageTest extends TestCase {
         assertResultEquals(pt,  1.5f,  1.5f, 10.0f);            // Lower right corner
     }
 
+    /**
+     * Verifies that a pixel value in the image created by {@link #createScaledByTwo(Interpolation,
int, int)}
+     * is equals to the expected value.
+     *
+     * @param pt        a pixel iterator over the resampled image. Its position will be modified.
+     * @param x         <var>x</var> coordinate in the source image.
+     * @param y         <var>y</var> coordinate in the source image.
+     * @param expected  the expected value.
+     */
     private static void assertResultEquals(final PixelIterator pt, float x, float y, float
expected) {
+        // Multiplication by 2 is for converting source coordinates to target coordinates.
         pt.moveTo((int) (x*2), (int) (y*2));
         assertEquals(expected, pt.getSampleFloat(0), 1E-9f);
     }
+
+    /**
+     * Resamples a single-tiled and single-banded image with values 1 everywhere except in
center.
+     * The {@linkplain #source} is a 3×3 image with the following values:
+     *
+     * <blockquote><pre>
+     *   1 1 1
+     *   1 2 1
+     *   1 1 1
+     * </pre></blockquote>
+     *
+     * The {@linkplain #target} is a 9×9 image computed using the given interpolation method.
+     * It is caller's responsibility to verify the result.
+     *
+     * @param  interpolation  the interpolation method to test.
+     * @return the resampled raster values.
+     */
+    private float[] resampleSimpleImage(final Interpolation interpolation) throws NoninvertibleTransformException
{
+        source = RasterFactory.createGrayScaleImage(DataBuffer.TYPE_FLOAT, 3, 3, 1, 0, 0,
2);
+        final WritableRaster raster = ((BufferedImage) source).getRaster();
+
+        raster.setSample(0, 0, 0, 1);    raster.setSample(1, 0, 0, 1);    raster.setSample(2,
0, 0, 1);
+        raster.setSample(0, 1, 0, 1);    raster.setSample(1, 1, 0, 2);    raster.setSample(2,
1, 0, 1);
+        raster.setSample(0, 2, 0, 1);    raster.setSample(1, 2, 0, 1);    raster.setSample(2,
2, 0, 1);
+
+        sourceToTarget = AffineTransform.getTranslateInstance(-0.5, -0.5);
+        sourceToTarget.scale(3, 3);
+        sourceToTarget.translate(0.5, 0.5);
+        target = new ResampledImage(new Rectangle(9, 9),
+                new AffineTransform2D(sourceToTarget.createInverse()), source, interpolation,
null);
+
+        assertEquals("numXTiles", 1, target.getNumXTiles());
+        assertEquals("numYTiles", 1, target.getNumYTiles());
+        final DataBufferFloat data = (DataBufferFloat) target.getTile(0,0).getDataBuffer();
+        assertEquals("numBanks", 1, data.getNumBanks());
+        return data.getData();
+    }
+
+    /**
+     * Checks all values of a nearest-neighbor interpolation on a simple image.
+     *
+     * @throws NoninvertibleTransformException if the test did not setup the transform correctly.
+     */
+    @Test
+    public void verifyNearestResults() throws NoninvertibleTransformException {
+        assertArrayEquals(new float[] {
+            1,1,1,1,1,1,1,1,1,
+            1,1,1,1,1,1,1,1,1,
+            1,1,1,1,1,1,1,1,1,
+            1,1,1,2,2,2,1,1,1,
+            1,1,1,2,2,2,1,1,1,
+            1,1,1,2,2,2,1,1,1,
+            1,1,1,1,1,1,1,1,1,
+            1,1,1,1,1,1,1,1,1,
+            1,1,1,1,1,1,1,1,1
+        }, resampleSimpleImage(Interpolation.NEAREST), (float) STRICT);
+    }
+
+    /**
+     * Checks all values of a bilinear interpolation on a simple image.
+     *
+     * @throws NoninvertibleTransformException if the test did not setup the transform correctly.
+     */
+    @Test
+    public void verifyBilinearResults() throws NoninvertibleTransformException {
+        assertArrayEquals(new float[] {
+            1.111111111f, 1f, 0.888888888f, 0.777777777f, 0.666666666f, 0.777777777f, 0.888888888f,
1f, 1.111111111f,
+            1.000000000f, 1f, 1.000000000f, 1.000000000f, 1.000000000f, 1.000000000f, 1.000000000f,
1f, 1.000000000f,
+            0.888888888f, 1f, 1.111111111f, 1.222222222f, 1.333333333f, 1.222222222f, 1.111111111f,
1f, 0.888888888f,
+            0.777777777f, 1f, 1.222222222f, 1.444444444f, 1.666666666f, 1.444444444f, 1.222222222f,
1f, 0.777777777f,
+            0.666666666f, 1f, 1.333333333f, 1.666666666f,      2f,      1.666666666f, 1.333333333f,
1f, 0.666666666f,
+            0.777777777f, 1f, 1.222222222f, 1.444444444f, 1.666666666f, 1.444444444f, 1.222222222f,
1f, 0.777777777f,
+            0.888888888f, 1f, 1.111111111f, 1.222222222f, 1.333333333f, 1.222222222f, 1.111111111f,
1f, 0.888888888f,
+            1.000000000f, 1f, 1.000000000f, 1.000000000f, 1.000000000f, 1.000000000f, 1.000000000f,
1f, 1.000000000f,
+            1.111111111f, 1f, 0.888888888f, 0.777777777f, 0.666666666f, 0.777777777f, 0.888888888f,
1f, 1.111111111f
+        }, resampleSimpleImage(Interpolation.BILINEAR), (float) STRICT);
+    }
 }


Mime
View raw message