sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jso...@apache.org
Subject [sis] branch geoapi-4.0 updated: Coverage : add GridCoverage implementation based on a RenderedImage
Date Thu, 14 Nov 2019 10:39:07 GMT
This is an automated email from the ASF dual-hosted git repository.

jsorel 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 adafeb6  Coverage : add GridCoverage implementation based on a RenderedImage
adafeb6 is described below

commit adafeb67371ae6c19acbc47bf678824996d12590
Author: jsorel <johann.sorel@geomatys.com>
AuthorDate: Thu Nov 14 11:38:50 2019 +0100

    Coverage : add GridCoverage implementation based on a RenderedImage
---
 .../sis/internal/coverage/GridCoverage2D.java      | 117 +++++++++++++++++++
 .../sis/internal/coverage/GridCoverage2DTest.java  | 126 +++++++++++++++++++++
 .../apache/sis/test/suite/FeatureTestSuite.java    |   3 +-
 3 files changed, 245 insertions(+), 1 deletion(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java
b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java
new file mode 100644
index 0000000..842ca9d
--- /dev/null
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/coverage/GridCoverage2D.java
@@ -0,0 +1,117 @@
+/*
+ * 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.internal.coverage;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.util.Collection;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.util.ArgumentChecks;
+import org.opengis.coverage.CannotEvaluateException;
+
+/**
+ * A {@link GridCoverage} with data stored in a {@link RenderedImage}.
+ *
+ * @author Johann Sorel (Geomatys)
+ * @version 2.0
+ * @since   2.0
+ * @module
+ */
+public class GridCoverage2D extends GridCoverage {
+    /**
+     * The sample values, stored as a RenderedImage.
+     */
+    protected final RenderedImage image;
+
+    /**
+     * Result of the call to {@link #forConvertedValues(boolean)}, created when first needed.
+     */
+    private GridCoverage converted;
+
+    /**
+     *
+     * @param grid  the grid extent, CRS and conversion from cell indices to CRS.
+     * @param bands sample dimensions for each image band.
+     * @param image the sample values as a RenderedImage, potentially multi-banded in packed
view.
+     */
+    public GridCoverage2D(final GridGeometry grid, final Collection<? extends SampleDimension>
bands, final RenderedImage image) {
+        super(grid, bands);
+        this.image = image;
+        ArgumentChecks.ensureNonNull("image", image);
+    }
+
+    /**
+     * Returns a grid coverage that contains real values or sample values, depending if {@code
converted} is {@code true}
+     * or {@code false} respectively.
+     *
+     * If the given value is {@code false}, then the default implementation returns a grid
coverage which produces
+     * {@link RenderedImage} views. Those views convert each sample value on the fly. This
is known to be very slow
+     * if an entire raster needs to be processed, but this is temporary until another implementation
is provided in
+     * a future SIS release.
+     *
+     * @return a coverage containing converted or packed values, depending on {@code converted}
argument value.
+     */
+    @Override
+    public GridCoverage forConvertedValues(final boolean converted) {
+        if (converted) {
+            synchronized (this) {
+                if (this.converted == null) {
+                    this.converted = BufferedGridCoverage.convert(this);
+                }
+                return this.converted;
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Returns a two-dimensional slice of grid data as a rendered image.
+     * This method may return a view or a copy.
+     *
+     * @return the grid slice as a rendered image.
+     */
+    @Override
+    public RenderedImage render(GridExtent sliceExtent) throws CannotEvaluateException {
+        if (sliceExtent == null || sliceExtent.equals(getGridGeometry().getExtent())) {
+            return image;
+        } else {
+            final int[] imgAxes = sliceExtent.getSubspaceDimensions(2);
+            final int subX = Math.toIntExact(sliceExtent.getLow(imgAxes[0]));
+            final int subY = Math.toIntExact(sliceExtent.getLow(imgAxes[1]));
+            final int subWidth = Math.toIntExact(Math.round(sliceExtent.getSize(imgAxes[0])));
+            final int subHeight = Math.toIntExact(Math.round(sliceExtent.getSize(imgAxes[1])));
+
+            if (image instanceof BufferedImage) {
+                final BufferedImage bi = (BufferedImage) image;
+                return bi.getSubimage(subX, subY, subWidth, subHeight);
+            } else {
+                //todo : current approach makes a copy of the datas, a better solution should
be found
+                final WritableRaster raster = image.getTile(image.getMinTileX(), image.getMinTileY()).createCompatibleWritableRaster(subWidth,
subHeight);
+                final WritableRaster derivate = raster.createWritableTranslatedChild(subX,
subY);
+                image.copyData(derivate);
+                ColorModel cm = image.getColorModel();
+                return new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
+            }
+        }
+    }
+
+}
diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java
b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java
new file mode 100644
index 0000000..ed6d759
--- /dev/null
+++ b/core/sis-feature/src/test/java/org/apache/sis/internal/coverage/GridCoverage2DTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.internal.coverage;
+
+import java.awt.Point;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.util.Arrays;
+import java.util.Hashtable;
+import org.apache.sis.coverage.SampleDimension;
+import org.apache.sis.coverage.grid.GridCoverage;
+import org.apache.sis.coverage.grid.GridExtent;
+import org.apache.sis.coverage.grid.GridGeometry;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.measure.Units;
+import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.test.TestCase;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opengis.referencing.datum.PixelInCell;
+import org.opengis.referencing.operation.MathTransform1D;
+
+
+/**
+ * Tests the {@link GridCoverage2D} implementation.
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @version 2.0
+ * @since   2.0
+ * @module
+ */
+public class GridCoverage2DTest extends TestCase {
+    /**
+     * Tests with a two-dimensional coverage.
+     */
+    @Test
+    public void testCoverage2D() {
+        /*
+         * Create coverage of 2×2 pixels with an identity "grid to CRS" transform.
+         * The range of sample values will be [-10 … +10]°C.
+         */
+        final GridGeometry grid = new GridGeometry(new GridExtent(2, 2),
+                PixelInCell.CELL_CENTER, MathTransforms.identity(2), HardCodedCRS.WGS84);
+
+        final MathTransform1D toUnits = (MathTransform1D) MathTransforms.linear(0.5, 100);
+        final SampleDimension sd = new SampleDimension.Builder().setName("t")
+                .addQuantitative("data", NumberRange.create(-10, true, 10, true), toUnits,
Units.CELSIUS)
+                .build();
+        /*
+         * Create the grid coverage, make an image and set values directly as integers.
+         */
+        WritableRaster raster = WritableRaster.createBandedRaster(DataBuffer.TYPE_INT, 2,
2, 1, new Point(0,0));
+        final ColorSpace colors = ColorModelFactory.createColorSpace(1, 0, -10, 10);
+        final ColorModel cm = new ComponentColorModel(colors, false, false, Transparency.OPAQUE,
DataBuffer.TYPE_INT);
+        BufferedImage image = new BufferedImage(cm, raster, false, new Hashtable<>());
+        GridCoverage   coverage = new GridCoverage2D(grid, Arrays.asList(sd), image);
+        raster.setSample(0, 0, 0,   0);
+        raster.setSample(1, 0, 0,   5);
+        raster.setSample(0, 1, 0,  -5);
+        raster.setSample(1, 1, 0, -10);
+        /*
+         * Verify packed values.
+         */
+        assertSamplesEqual(coverage, new double[][] {
+            { 0,   5},
+            {-5, -10}
+        });
+        /*
+         * Verify converted values.
+         */
+        coverage = coverage.forConvertedValues(true);
+        assertSamplesEqual(coverage, new double[][] {
+            {100.0, 102.5},
+            { 97.5,  95.0}
+        });
+        /*
+         * Test writing converted values and verify the result in the packed coverage.
+         * For example for the sample value at (0,0), we have (x is the packed value):
+         *
+         *   70 = x * 0.5 + 100   →   (70-100)/0.5 = x   →   x = -60
+         */
+        raster = ((BufferedImage) coverage.render(null)).getRaster();
+        raster.setSample(0, 0, 0,  70);
+        raster.setSample(1, 0, 0,   2.5);
+        raster.setSample(0, 1, 0,  -8);
+        raster.setSample(1, 1, 0, -90);
+        assertSamplesEqual(coverage.forConvertedValues(false), new double[][] {
+            { -60, -195},
+            {-216, -380}
+        });
+    }
+
+    /**
+     * assert that the sample values in the given coverage are equal to the expected values.
+     */
+    private static void assertSamplesEqual(final GridCoverage coverage, final double[][]
expected) {
+        final Raster raster = coverage.render(null).getData();
+        for (int y=0; y<expected.length; y++) {
+            for (int x=0; x<expected[y].length; x++) {
+                double value = raster.getSampleDouble(x, y, 0);
+                Assert.assertEquals(expected[y][x], value, STRICT);
+            }
+        }
+    }
+}
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 12cf52e..9bf8ffa 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
@@ -85,7 +85,8 @@ import org.junit.runners.Suite;
     org.apache.sis.coverage.SampleDimensionTest.class,
     org.apache.sis.coverage.SampleRangeFormatTest.class,
     org.apache.sis.internal.coverage.ScaledColorSpaceTest.class,
-    org.apache.sis.internal.coverage.BufferedGridCoverageTest.class
+    org.apache.sis.internal.coverage.BufferedGridCoverageTest.class,
+    org.apache.sis.internal.coverage.GridCoverage2DTest.class
 })
 public final strictfp class FeatureTestSuite extends TestSuite {
     /**


Mime
View raw message