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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new c92fbca Add a simple interpolation test.
c92fbca is described below
commit c92fbca4ea76b61d979ec90d39bf1e2a2b838011
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Thu Mar 26 11:18:35 2020 +0100
Add a simple interpolation test.
---
.../java/org/apache/sis/image/Interpolation.java | 7 +-
.../org/apache/sis/image/LanczosInterpolation.java | 4 +-
.../java/org/apache/sis/image/ResampledImage.java | 13 ++-
.../org/apache/sis/image/InterpolationTest.java | 114 +++++++++++++++++++++
.../apache/sis/test/suite/FeatureTestSuite.java | 1 +
5 files changed, 132 insertions(+), 7 deletions(-)
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java b/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java
index cdb0498..ef5ac57 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/Interpolation.java
@@ -25,6 +25,9 @@ import java.nio.DoubleBuffer;
* of pixels using a local neighborhood. The sampling is performed by the {@link ResampledImage}
class, which
* gives the sample values to the {@code interpolate(…)} method of this interpolation.
*
+ * <p>All methods in this interface shall be safe for concurrent use in multi-threading
context.
+ * For example interpolations may be executed in a different thread for each tile in an image.</p>
+ *
* <p>This interface is designed for interpolations in a two-dimensional space only.</p>
*
* @author Rémi Marechal (Geomatys)
@@ -134,7 +137,9 @@ public interface Interpolation {
};
/**
- * Lanczos interpolation. The kernel is:
+ * Lanczos interpolation for photographic images.
+ * This interpolation is not recommended for images that may contain NaN values.
+ * The Lanczos reconstruction kernel is:
*
* <blockquote>
* <var>L</var>(<var>x</var>) = <var>a</var>⋅sin(π⋅<var>x</var>)⋅sin(π⋅<var>x</var>/<var>a</var>)/(π⋅<var>x</var>)²
diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/LanczosInterpolation.java
b/core/sis-feature/src/main/java/org/apache/sis/image/LanczosInterpolation.java
index 138df5f..91e63e7 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/image/LanczosInterpolation.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/image/LanczosInterpolation.java
@@ -22,8 +22,8 @@ import java.nio.DoubleBuffer;
/**
- * Lanczos interpolation of arbitrary size.
- * The kernel is:
+ * Lanczos interpolation of arbitrary size. This interpolation is good for photographic images
but
+ * not recommended for images that may contain NaN values. The Lanczos reconstruction kernel
is:
*
* <blockquote>
* <var>L</var>(<var>x</var>) = <var>a</var>⋅sin(π⋅<var>x</var>)⋅sin(π⋅<var>x</var>/<var>a</var>)/(π⋅<var>x</var>)²
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 5323ce9..ca61728 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
@@ -16,6 +16,7 @@
*/
package org.apache.sis.image;
+import java.util.Arrays;
import java.nio.DoubleBuffer;
import java.awt.Dimension;
import java.awt.Rectangle;
@@ -103,14 +104,17 @@ public class ResampledImage extends ComputedImage {
* by a non-linear transform from <em>this</em> image to the specified <em>source</em>
image.
* That transform should map {@linkplain org.opengis.referencing.datum.PixelInCell#CELL_CENTER
pixel centers}.
*
+ * <p>If a pixel in this image can not be mapped to a pixel in the source image,
then the sample values are set
+ * to {@code fillValues}. If the given array is {@code null}, or if any element in the
given array is {@code null},
+ * then the default fill value is NaN for floating point data types or zero for integer
data types.</p>
+ *
* @param bounds domain of pixel coordinates of this resampled image.
* @param toSource conversion of pixel coordinates of this image to pixel coordinates
of {@code source} image.
* @param source the image to be resampled.
* @param interpolation the object to use for performing interpolations.
* @param fillValues the values to use for pixels in this image that can not be
mapped to pixels in source image.
- * The array length must be equal to the number of bands. If the
array is {@code null},
- * the default value is zero in all bands. If any element in the
array is {@code null},
- * the default value is zero for the corresponding band.
+ * The array length must be equal to the number of bands.
+ * May be {@code null} or contain {@code null} elements.
*/
public ResampledImage(final Rectangle bounds, final MathTransform toSource, final RenderedImage
source,
final Interpolation interpolation, final Number[] fillValues)
@@ -168,6 +172,7 @@ public class ResampledImage extends ComputedImage {
this.fillValues = fill;
} else {
final double[] fill = new double[numBands];
+ Arrays.fill(fill, Double.NaN);
if (fillValues != null) {
for (int i=0; i<numBands; i++) {
final Number f = fillValues[i];
@@ -345,7 +350,7 @@ public class ResampledImage extends ComputedImage {
values = new double[numBands];
intValues = new int[scanline * numBands];
valuesArray = intValues;
- final NumberRange<?>[] ranges = it.getSampleRanges();
+ final NumberRange<?>[] ranges = it.getSampleRanges(); // Assumes source.sampleModel
== this.sampleModel.
minValues = new long[ranges.length];
maxValues = new long[ranges.length];
for (int i=0; i<ranges.length; i++) {
diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/InterpolationTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/InterpolationTest.java
new file mode 100644
index 0000000..d304163
--- /dev/null
+++ b/core/sis-feature/src/test/java/org/apache/sis/image/InterpolationTest.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sis.image;
+
+import java.util.Random;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.image.DataBuffer;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import org.apache.sis.internal.referencing.j2d.AffineTransform2D;
+import org.apache.sis.test.TestCase;
+import org.apache.sis.test.TestUtilities;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests {@link Interpolation} predefined instances.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @version 1.1
+ * @since 1.1
+ */
+public final strictfp class InterpolationTest extends TestCase {
+ /**
+ * Size of tiles in this test. The width should be different than the height
+ * for increasing the chances to detect errors in index calculations.
+ */
+ private static final int TILE_WIDTH = 5, TILE_HEIGHT = 4;
+
+ /**
+ * Creates a rendered image with arbitrary tiles.
+ *
+ * @param dataType {@link DataBuffer#TYPE_SHORT} or {@link DataBuffer#TYPE_FLOAT}.
+ */
+ private static PlanarImage createImage(final int dataType) {
+ final Random random = TestUtilities.createRandomNumberGenerator();
+ final TiledImageMock image = new TiledImageMock(
+ DataBuffer.TYPE_SHORT, 2, // dataType and numBands
+ random.nextInt(32) - 10, // minX
+ random.nextInt(32) - 10, // minY
+ TILE_WIDTH * 3, // width
+ TILE_HEIGHT * 3, // height
+ TILE_WIDTH,
+ TILE_HEIGHT,
+ random.nextInt(32) - 10, // minTileX
+ random.nextInt(32) - 10); // minTileY
+ image.validate();
+ image.initializeAllTiles(0);
+ image.setRandomValues(1, random, 1024);
+ return image;
+ }
+
+ /**
+ * Tests interpolation in the simple case where the image is scaled by a factor 2.
+ * All sample values at even indices in the result should be equal to sample values
+ * at the index divided by 2 in the source image. Sample values at odd indices have
+ * values that depend on the interpolation method.
+ *
+ * @param interpolation the interpolation method to test.
+ * @param isInteger whether to test with integer values or floating point type.
+ * @throws NoninvertibleTransformException if the test did not setup the transform correctly.
+ */
+ private static void scaleByTwo(final Interpolation interpolation, final boolean isInteger)
throws NoninvertibleTransformException {
+ final PlanarImage source = createImage(isInteger ? DataBuffer.TYPE_SHORT : DataBuffer.TYPE_FLOAT);
+ final Rectangle bounds = new Rectangle(-40, 50, source.getWidth() * 2, source.getHeight()
* 2);
+ final AffineTransform tr = AffineTransform.getTranslateInstance(source.getMinX(),
source.getMinY());
+ tr.scale(0.5, 0.5);
+ tr.translate(-bounds.x, -bounds.y);
+ final ResampledImage target = new ResampledImage(bounds, new AffineTransform2D(tr),
source, interpolation, null);
+ assertNull(target.verify()); // Fails if we did not setup the `toSource` transform
correctly.
+
+ tr.invert();
+ final PixelIterator ps = PixelIterator.create(source);
+ final PixelIterator pt = PixelIterator.create(target);
+ double[] sv = null;
+ double[] tv = null;
+ while (ps.next()) {
+ Point p = ps.getPosition();
+ p = (Point) tr.transform(p, p);
+ pt.moveTo(p.x, p.y);
+ sv = ps.getPixel(sv);
+ tv = pt.getPixel(tv);
+ assertArrayEquals(sv, tv, 1E-12);
+ }
+ }
+
+ /**
+ * Tests {@link Interpolation#BILINEAR}.
+ *
+ * @throws NoninvertibleTransformException if the test did not setup the transform correctly.
+ */
+ @Test
+ public void testBilinear() throws NoninvertibleTransformException {
+ scaleByTwo(Interpolation.BILINEAR, true);
+ scaleByTwo(Interpolation.BILINEAR, false);
+ }
+}
diff --git a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
index 355cc3e..7c90233 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/test/suite/FeatureTestSuite.java
@@ -81,6 +81,7 @@ import org.junit.runners.Suite;
org.apache.sis.image.DefaultIteratorTest.class,
org.apache.sis.image.LinearIteratorTest.class,
org.apache.sis.image.StatisticsCalculatorTest.class,
+ org.apache.sis.image.InterpolationTest.class,
org.apache.sis.coverage.CategoryTest.class,
org.apache.sis.coverage.CategoryListTest.class,
org.apache.sis.coverage.SampleDimensionTest.class,
|