sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 02/02: Do not overwrite puxels in destination image that are not covered by a pixel in source image.
Date Fri, 21 Aug 2020 11:01:37 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 533950959c450594b60feb88ad9df5bcea337d5c
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Fri Aug 21 12:32:34 2020 +0200

    Do not overwrite puxels in destination image that are not covered by a pixel in source
image.
---
 .../java/org/apache/sis/image/ResampledImage.java  | 47 ++++++++++++++++----
 .../org/apache/sis/image/ImageCombinerTest.java    | 51 +++++++++++++++++-----
 2 files changed, 78 insertions(+), 20 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 c3b823a..592b921 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
@@ -638,7 +638,8 @@ public class ResampledImage extends ComputedImage {
          * can take a shorter path were data are just copied. The lossless criterion allows
us to omit the checks
          * for minimal and maximal values. Shortcut may apply to both integer values and
floating point values.
          */
-        final boolean shortcut = (interpolation == Interpolation.NEAREST) &&
+        final boolean useFillValues = (getDestination() == null);
+        final boolean shortcut = useFillValues && (interpolation == Interpolation.NEAREST)
&&
                     ImageUtilities.isLosslessConversion(sampleModel, tile.getSampleModel());
         /*
          * Prepare a buffer where to store a line of interpolated values. We use this buffer
for transferring
@@ -700,10 +701,17 @@ public class ResampledImage extends ComputedImage {
             }
             toSourceSupport.transform(coordinates, 0, coordinates, 0, scanline);
             /*
-             * Special case for nearest-neighbor interpolation without the need to check
for min/max values.
-             * In this case values will be copied as `int` or `double` type without further
processing.
+             * Pixel coordinate along X axis where to start writing the `values` or `intValues`
array.
+             * This is usually the first column of the tile, and the number of pixels to
write is the
+             * tile width (i.e. we write a full tile row). However those values may be modified
below
+             * if we avoid writing pixels that are outside the source image.
              */
+            int posX = tileMinX;
             if (shortcut) {
+                /*
+                 * Special case for nearest-neighbor interpolation without the need to check
for min/max values.
+                 * In this case values will be copied as `int` or `double` type without further
processing.
+                 */
                 int ci = 0;     // Index in `coordinates` array.
                 int vi = 0;     // Index in `values` or `intValues` array.
                 for (int tx=tileMinX; tx<tileMaxX; tx++, ci+=tgtDim, vi+=numBands) {
@@ -743,7 +751,7 @@ public class ResampledImage extends ComputedImage {
                  */
                 int ci = 0;     // Index in `coordinates` array.
                 int vi = 0;     // Index in `values` or `intValues` array.
-                for (int tx=tileMinX; tx<tileMaxX; tx++, ci+=tgtDim, vi+=numBands) {
+                for (int tx=tileMinX; tx<tileMaxX; tx++, ci+=tgtDim) {
                     double x = coordinates[ci];
                     if (x <= xlim) {
                         // Separate integer and fractional parts with 0 ≤ xf < 1 except
on borders.
@@ -779,6 +787,7 @@ public class ResampledImage extends ComputedImage {
                                                                     Math.min(maxValues[b],
Math.round(values[b])));
                                         }
                                     }
+                                    vi += numBands;
                                     continue;       // Values have been set, move to next
pixel.
                                 }
                             }
@@ -788,18 +797,38 @@ public class ResampledImage extends ComputedImage {
                      * If we reach this point then any of the "if" conditions above failed
                      * (i.e. the point to interpolate is outside the source image bounds)
                      * and no values have been set in the `values` or `intValues` array.
+                     * If we are writing in an existing image, do not write anything
+                     * (i.e. keep the existing value). Otherwise write the fill values.
                      */
-                    System.arraycopy(fillValues, 0, valuesArray, vi, numBands);
+                    if (useFillValues) {
+                        System.arraycopy(fillValues, 0, valuesArray, vi, numBands);
+                        vi += numBands;
+                    } else {
+                        if (vi != 0) {
+                            final int numX = vi / numBands;
+                            if (isInteger) {
+                                tile.setPixels(posX, ty, numX, 1, intValues);
+                            } else {
+                                tile.setPixels(posX, ty, numX, 1, values);
+                            }
+                            posX += numX;
+                            vi = 0;
+                        }
+                        posX++;
+                    }
                 }
             }
             /*
              * At this point we finished to compute the value of a scanline.
              * Copy to its final destination then move to next line.
              */
-            if (isInteger) {
-                tile.setPixels(tileMinX, ty, scanline, 1, intValues);
-            } else {
-                tile.setPixels(tileMinX, ty, scanline, 1, values);
+            final int numX = scanline - (posX - tileMinX);
+            if (numX != 0) {
+                if (isInteger) {
+                    tile.setPixels(posX, ty, numX, 1, intValues);
+                } else {
+                    tile.setPixels(posX, ty, numX, 1, values);
+                }
             }
         }
         return tile;
diff --git a/core/sis-feature/src/test/java/org/apache/sis/image/ImageCombinerTest.java b/core/sis-feature/src/test/java/org/apache/sis/image/ImageCombinerTest.java
index 61dfefa..2e64157 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/image/ImageCombinerTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/image/ImageCombinerTest.java
@@ -92,7 +92,7 @@ public final strictfp class ImageCombinerTest extends ImageTestCase {
             {400, 401, 402, 403, 500, 501, 502, 503, 600, 601, 602, 603},
             {410, 411, 412, 413, 510, 511, 512, 513, 610, 611, 612, 613},
             {420, 421, 422, 423, 520, 521, 522, 523, 620, 621, 622, 623},
-            {430, 431, 432, 433, 530, 531, 532, 533, 630, 631, 632, 633},
+            {430, 431, 432, 433, 530, 531, 532, 533, 630, 631, 632, 633}
         });
         /*
          * Verify source image, before combine operation.
@@ -122,14 +122,14 @@ public final strictfp class ImageCombinerTest extends ImageTestCase
{
          */
         combiner.accept(toAdd);
         assertValuesEqual(image = combiner.result(), 0, new double[][] {
-            { 100,  101, +110, +111, +112, +210, +211, +212, +310, +311, +312, +303},
-            { 110,  111, +400, +401, +402, +500, +501, +502, +600, +601, +602, +313},
-            { 120,  121, +410, +411, +412, +510, +511, +512, +610, +611, +612, +323},
-            { 130,  131, +700, +701, +702, +800, +801, +802, +900, +901, +902, +333},
-            { 400,  401, +710, +711, +712, +810, +811, +812, +910, +911, +912, +603},
+            { 100,  101, +110, +111, +112, +210, +211, +212, +310, +311, +312,  303},
+            { 110,  111, +400, +401, +402, +500, +501, +502, +600, +601, +602,  313},
+            { 120,  121, +410, +411, +412, +510, +511, +512, +610, +611, +612,  323},
+            { 130,  131, +700, +701, +702, +800, +801, +802, +900, +901, +902,  333},
+            { 400,  401, +710, +711, +712, +810, +811, +812, +910, +911, +912,  603},
             { 410,  411,  412,  413,  510,  511,  512,  513,  610,  611,  612,  613},
             { 420,  421,  422,  423,  520,  521,  522,  523,  620,  621,  622,  623},
-            { 430,  431,  432,  433,  530,  531,  532,  533,  630,  631,  632,  633},
+            { 430,  431,  432,  433,  530,  531,  532,  533,  630,  631,  632,  633}
         });
     }
 
@@ -138,24 +138,53 @@ public final strictfp class ImageCombinerTest extends ImageTestCase
{
      * The transform used in this test is a simple translation. The expected result is
      * similar to the {@link #testAccept()} one, with the new pixel values (identified
      * by a + sign in source code) shifted by 2 rows and 2 columns.
+     *
+     * <p>In this test, the X coordinate of the first pixel to write is at the beginning
of a tile.
+     * This alignment creates a situation where each row in {@link #toAdd} is either copied
in full
+     * or not copied at all. This characteristics help to isolate the problem if a test fails.</p>
      */
     @Test
-    public void testResample() {
+    public void testResampleAligned() {
         final ImageCombiner combiner = initialize();
         final Rectangle bounds = toAdd.getBounds();
         bounds.translate(2, 2);
         final MathTransform toSource = MathTransforms.translation(-2, -2);
         combiner.resample(toAdd, bounds, toSource);
         assertValuesEqual(image = combiner.result(), 0, new double[][] {
-            { 100,  101,  102,  103,    0,    0,    0,    0,    0,    0,    0,    0},
+            { 100,  101,  102,  103,  200,  201,  202,  203,  300,  301,  302,  303},
             { 110,  111,  112,  113, +100, +101, +102, +200, +201, +202, +300, +301},
             { 120,  121,  122,  123, +110, +111, +112, +210, +211, +212, +310, +311},
             { 130,  131,  132,  133, +400, +401, +402, +500, +501, +502, +600, +601},
             { 400,  401,  402,  403, +410, +411, +412, +510, +511, +512, +610, +611},
             { 410,  411,  412,  413, +700, +701, +702, +800, +801, +802, +900, +901},
             { 420,  421,  422,  423, +710, +711, +712, +810, +811, +812, +910, +911},
-            { 430,  431,  432,  433,    0,    0,    0,    0,    0,    0,    0,    0},
+            { 430,  431,  432,  433,  530,  531,  532,  533,  630,  631,  632,  633}
+        });
+    }
+
+    /**
+     * Same as {@link #testResampleAligned()}, but with a "more difficult" translation.
+     * In this test, {@link #toAdd} rows are only partially copied.
+     *
+     * <p><b>Tip:</b> if this test fails, it is easier to first make sure
that
+     * {@link #testResampleAligned()} pass before to debug this test.</p>
+     */
+    @Test
+    public void testResample() {
+        final ImageCombiner combiner = initialize();
+        final Rectangle bounds = toAdd.getBounds();
+        bounds.translate(-1, 2);
+        final MathTransform toSource = MathTransforms.translation(1, -2);
+        combiner.resample(toAdd, bounds, toSource);
+        assertValuesEqual(image = combiner.result(), 0, new double[][] {
+            { 100,  101,  102,  103,  200,  201,  202,  203,  300,  301,  302,  303},
+            { 110, +100, +101, +102, +200, +201, +202, +300, +301, +302,  312,  313},
+            { 120, +110, +111, +112, +210, +211, +212, +310, +311, +312,  322,  323},
+            { 130, +400, +401, +402, +500, +501, +502, +600, +601, +602,  332,  333},
+            { 400, +410, +411, +412, +510, +511, +512, +610, +611, +612,  602,  603},
+            { 410, +700, +701, +702, +800, +801, +802, +900, +901, +902,  612,  613},
+            { 420, +710, +711, +712, +810, +811, +812, +910, +911, +912,  622,  623},
+            { 430,  431,  432,  433,  530,  531,  532,  533,  630,  631,  632,  633}
         });
-        // TODO: value 0 above should not overwrite previous values.
     }
 }


Mime
View raw message