Search in sources :

Example 1 with PixelIterator

use of org.apache.sis.image.PixelIterator in project sis by apache.

the class FeatureAssert method assertPixelsEqual.

/**
 * Verifies that sample values in the given image are equal to the expected values.
 * Sample values are compared using floating point {@code double} precision.
 * NaN values must be strictly equals (same bit pattern).
 *
 * @param  expected       the expected sample values.
 * @param  boundsExpected bounds of the expected region, or {@code null} for the whole image.
 * @param  actual         the image to verify.
 * @param  boundsActual   bounds of the actual region, or {@code null} for the whole image.
 */
public static void assertPixelsEqual(final RenderedImage expected, final Rectangle boundsExpected, final RenderedImage actual, final Rectangle boundsActual) {
    if (boundsExpected != null && boundsActual != null) {
        assertEquals("width", boundsExpected.width, boundsActual.width);
        assertEquals("height", boundsExpected.height, boundsActual.height);
    }
    final PixelIterator ie = new PixelIterator.Builder().setIteratorOrder(SequenceType.LINEAR).setRegionOfInterest(boundsExpected).create(expected);
    final PixelIterator ia = new PixelIterator.Builder().setIteratorOrder(SequenceType.LINEAR).setRegionOfInterest(boundsActual).create(actual);
    double[] ev = null;
    double[] av = null;
    while (ie.next()) {
        assertTrue(ia.next());
        ev = ie.getPixel(ev);
        av = ia.getPixel(av);
        assertEquals(ev.length, av.length);
        for (int band = 0; band < ev.length; band++) {
            final double e = ev[band];
            final double a = av[band];
            if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(e)) {
                final Point p = ia.getPosition();
                fail(mismatchedSampleValue(p.x, p.y, p.x - actual.getMinX(), p.y - actual.getMinY(), band, e, a));
            }
        }
    }
    assertFalse(ia.next());
}
Also used : PixelIterator(org.apache.sis.image.PixelIterator) Point(java.awt.Point) Point(java.awt.Point)

Example 2 with PixelIterator

use of org.apache.sis.image.PixelIterator in project sis by apache.

the class RasterWriter method write.

/**
 * Encodes the given raster to the specified output.
 *
 * @param  raster  the raster to encode.
 * @param  output  where to write the bytes.
 * @throws RasterFormatException if the raster to write is not supported.
 * @throws IOException in an error occurred while writing to the given output.
 */
public void write(final Raster raster, final ChannelDataOutput output) throws IOException {
    if (gridToCRS == null) {
        gridToCRS = new AffineTransform();
    }
    final SampleModel sm = raster.getSampleModel();
    final int numBands = sm.getNumBands();
    final int width = raster.getWidth();
    final int height = raster.getHeight();
    /*
         * The `direct` flag tells whether we can write the backing array directly or whether we need
         * to use the pixel iterator because of sample model complexity. We can write arrays directly
         * if each array contains a single band and the scanline stride is equal to the raster width.
         */
    // Default value for sample models of unknown type.
    boolean direct = false;
    int dataType = sm.getDataType();
    int pixelType = Band.bufferToPixelType(dataType);
    if (sm instanceof SinglePixelPackedSampleModel) {
        if (numBands == 1) {
            direct = ((SinglePixelPackedSampleModel) sm).getScanlineStride() == width;
        } else {
            final int sampleSize = Arrays.stream(sm.getSampleSize()).max().orElse(0);
            if (sampleSize >= 1 && sampleSize <= Short.SIZE) {
                dataType = (sampleSize <= Byte.SIZE ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT);
                pixelType = Band.bufferToPixelType(dataType);
            }
        }
    } else if (sm instanceof MultiPixelPackedSampleModel) {
        if (dataType == DataBuffer.TYPE_BYTE) {
            final MultiPixelPackedSampleModel mp = (MultiPixelPackedSampleModel) sm;
            final int sampleSize = mp.getPixelBitStride();
            direct = (mp.getScanlineStride() * Byte.SIZE == width * sampleSize);
            pixelType = Band.sizeToPixelType(sampleSize);
        }
    } else if (sm instanceof ComponentSampleModel) {
        direct = (((ComponentSampleModel) sm).getScanlineStride() == width);
    }
    /*
         * Write the header followed by all bands.
         */
    output.buffer.order(byteOrder);
    output.writeByte(ByteOrder.LITTLE_ENDIAN.equals(byteOrder) ? 1 : 0);
    // WKB version number.
    output.writeShort(0);
    output.writeShort(ensureUnsignedShort("numBands", numBands));
    output.writeDouble(gridToCRS.getScaleX());
    output.writeDouble(gridToCRS.getScaleY());
    output.writeDouble(gridToCRS.getTranslateX());
    output.writeDouble(gridToCRS.getTranslateY());
    output.writeDouble(gridToCRS.getShearX());
    output.writeDouble(gridToCRS.getShearY());
    output.writeInt(srid);
    output.writeShort(ensureUnsignedShort("width", width));
    output.writeShort(ensureUnsignedShort("height", height));
    for (int b = 0; b < numBands; b++) {
        final Number fill = (noDataValues != null && b < noDataValues.length) ? noDataValues[b] : null;
        final Band band = new Band(pixelType, fill);
        output.writeByte(band.header);
        switch(dataType) {
            // Fall through
            case DataBuffer.TYPE_USHORT:
            case DataBuffer.TYPE_SHORT:
                output.writeShort(fill != null ? fill.intValue() : 0);
                break;
            case DataBuffer.TYPE_BYTE:
                output.writeByte(fill != null ? fill.intValue() : 0);
                break;
            case DataBuffer.TYPE_INT:
                output.writeInt(fill != null ? fill.intValue() : 0);
                break;
            case DataBuffer.TYPE_FLOAT:
                output.writeFloat(fill != null ? fill.floatValue() : Float.NaN);
                break;
            case DataBuffer.TYPE_DOUBLE:
                output.writeDouble(fill != null ? fill.doubleValue() : Double.NaN);
                break;
            default:
                throw new RasterFormatException(Errors.format(Errors.Keys.UnsupportedType_1, dataType));
        }
        if (direct) {
            final DataBuffer buffer = raster.getDataBuffer();
            final int offset = buffer.getOffsets()[b];
            final int length = width * height;
            switch(dataType) {
                case DataBuffer.TYPE_BYTE:
                    output.write(((DataBufferByte) buffer).getData(b), offset, length);
                    break;
                case DataBuffer.TYPE_USHORT:
                    output.writeShorts(((DataBufferUShort) buffer).getData(b), offset, length);
                    break;
                case DataBuffer.TYPE_SHORT:
                    output.writeShorts(((DataBufferShort) buffer).getData(b), offset, length);
                    break;
                case DataBuffer.TYPE_INT:
                    output.writeInts(((DataBufferInt) buffer).getData(b), offset, length);
                    break;
                case DataBuffer.TYPE_FLOAT:
                    output.writeFloats(((DataBufferFloat) buffer).getData(b), offset, length);
                    break;
                case DataBuffer.TYPE_DOUBLE:
                    output.writeDoubles(((DataBufferDouble) buffer).getData(b), offset, length);
                    break;
            }
        } else {
            final PixelIterator it = new PixelIterator.Builder().create(raster);
            while (it.next()) {
                switch(dataType) {
                    // Fall through
                    case DataBuffer.TYPE_USHORT:
                    case DataBuffer.TYPE_SHORT:
                        output.writeShort(it.getSample(b));
                        break;
                    case DataBuffer.TYPE_BYTE:
                        output.writeByte(it.getSample(b));
                        break;
                    case DataBuffer.TYPE_INT:
                        output.writeInt(it.getSample(b));
                        break;
                    case DataBuffer.TYPE_FLOAT:
                        output.writeFloat(it.getSample(b));
                        break;
                    case DataBuffer.TYPE_DOUBLE:
                        output.writeDouble(it.getSample(b));
                        break;
                }
            }
        }
    }
}
Also used : PixelIterator(org.apache.sis.image.PixelIterator) SinglePixelPackedSampleModel(java.awt.image.SinglePixelPackedSampleModel) MultiPixelPackedSampleModel(java.awt.image.MultiPixelPackedSampleModel) ComponentSampleModel(java.awt.image.ComponentSampleModel) ComponentSampleModel(java.awt.image.ComponentSampleModel) SampleModel(java.awt.image.SampleModel) MultiPixelPackedSampleModel(java.awt.image.MultiPixelPackedSampleModel) SinglePixelPackedSampleModel(java.awt.image.SinglePixelPackedSampleModel) AffineTransform(java.awt.geom.AffineTransform) RasterFormatException(java.awt.image.RasterFormatException) DataBuffer(java.awt.image.DataBuffer)

Example 3 with PixelIterator

use of org.apache.sis.image.PixelIterator in project sis by apache.

the class CoverageReadConsistency method readAndCompareRandomRegions.

/**
 * Implementation of methods testing reading in random sub-regions with random sub-samplings.
 *
 * @param  label  a label for the test being run.
 * @throws DataStoreException if an error occurred while using the resource.
 */
private void readAndCompareRandomRegions(final String label) throws DataStoreException {
    randomConfigureResource();
    final GridGeometry gg = resource.getGridGeometry();
    final int dimension = gg.getDimension();
    final long[] low = new long[dimension];
    final long[] high = new long[dimension];
    final int[] subsampling = new int[dimension];
    final int[] subOffsets = new int[dimension];
    final int numBands = resource.getSampleDimensions().size();
    /*
         * We will collect statistics on execution time only if the
         * test is executed in a more verbose mode than the default.
         */
    final Statistics durations = (VERBOSE || !failOnMismatch) ? new Statistics(label) : null;
    int failuresCount = 0;
    for (int it = 0; it < numIterations; it++) {
        final GridGeometry domain = randomDomain(gg, low, high, subsampling);
        final int[] selectedBands = randomRange(numBands);
        /*
             * Read a coverage containing the requested sub-domain. Note that the reader is free to read
             * more data than requested. The extent actually read is `actualReadExtent`. It shall contain
             * fully the requested `domain`.
             */
        final long startTime = System.nanoTime();
        final GridCoverage subset = resource.read(domain, selectedBands);
        final GridExtent actualReadExtent = subset.getGridGeometry().getExtent();
        if (failOnMismatch) {
            assertEquals("Unexpected number of dimensions.", dimension, actualReadExtent.getDimension());
            for (int d = 0; d < dimension; d++) {
                if (subsampling[d] == 1) {
                    assertTrue("Actual extent is too small.", actualReadExtent.getSize(d) > high[d] - low[d]);
                    assertTrue("Actual extent is too small.", actualReadExtent.getLow(d) <= low[d]);
                    assertTrue("Actual extent is too small.", actualReadExtent.getHigh(d) >= high[d]);
                }
            }
        }
        /*
             * If subsampling was enabled, the factors selected by the reader may be different than
             * the subsampling factors that we specified. The following block updates those values.
             */
        if (allowSubsampling && full != null) {
            final GridDerivation change = full.getGridGeometry().derive().subgrid(subset.getGridGeometry());
            System.arraycopy(change.getSubsampling(), 0, subsampling, 0, dimension);
            System.arraycopy(change.getSubsamplingOffsets(), 0, subOffsets, 0, dimension);
        }
        /*
             * Iterate over all dimensions greater than 2. In the common case where we are reading a
             * two-dimensional image, the following loop will be executed only once. If reading a 3D
             * or 4D image, the loop is executed for all possible two-dimensional slices in the cube.
             */
        final int sd = actualReadExtent.getDimension();
        final long[] sliceMin = new long[sd];
        final long[] sliceMax = new long[sd];
        for (int i = 0; i < sd; i++) {
            sliceMin[i] = actualReadExtent.getLow(i);
            sliceMax[i] = actualReadExtent.getHigh(i);
        }
        nextSlice: for (; ; ) {
            System.arraycopy(sliceMin, BIDIMENSIONAL, sliceMax, BIDIMENSIONAL, dimension - BIDIMENSIONAL);
            final PixelIterator itr = iterator(full, sliceMin, sliceMax, subsampling, subOffsets, allowSubsampling);
            final PixelIterator itc = iterator(subset, sliceMin, sliceMax, subsampling, subOffsets, false);
            if (itr != null) {
                assertEquals(itr.getDomain().getSize(), itc.getDomain().getSize());
                final double[] expected = new double[selectedBands.length];
                double[] reference = null, actual = null;
                while (itr.next()) {
                    assertTrue(itc.next());
                    reference = itr.getPixel(reference);
                    actual = itc.getPixel(actual);
                    for (int i = 0; i < selectedBands.length; i++) {
                        expected[i] = reference[selectedBands[i]];
                    }
                    if (!Arrays.equals(expected, actual)) {
                        failuresCount++;
                        if (!failOnMismatch)
                            break;
                        final Point pr = itr.getPosition();
                        final Point pc = itc.getPosition();
                        final StringBuilder message = new StringBuilder(100).append("Mismatch at position (").append(pr.x).append(", ").append(pr.y).append(") in full image and (").append(pc.x).append(", ").append(pc.y).append(") in tested sub-image");
                        findMatchPosition(itr, pr, selectedBands, actual, message);
                        assertArrayEquals(message.toString(), expected, actual, STRICT);
                    /*
                             * POSSIBLE CAUSES FOR TEST FAILURE (known issues):
                             *
                             *   - If the `GridGeometry` has no `gridToCRS` transform, then `GridDerivation` manages
                             *     to save the scales (subsampling factors) anyway but the translations (subsampling
                             *     offsets) are lost. It causes an image shift if the offsets were not zero. Because
                             *     `gridToCRS` should never be null with spatial data, we do not complexify the code
                             *     for what may be a non-issue.
                             */
                    }
                }
                assertFalse(itc.next());
            } else {
                // Unable to create a reference image. Just check that no exception is thrown.
                double[] actual = null;
                while (itc.next()) {
                    actual = itc.getPixel(actual);
                }
            }
            /*
                 * Move to the next two-dimensional slice and read again.
                 * We stop the loop after we have read all 2D slices.
                 */
            for (int d = dimension; --d >= BIDIMENSIONAL; ) {
                if (sliceMin[d]++ <= actualReadExtent.getHigh(d))
                    continue nextSlice;
                sliceMin[d] = actualReadExtent.getLow(d);
            }
            break;
        }
        if (durations != null) {
            durations.accept((System.nanoTime() - startTime) / (double) StandardDateFormat.NANOS_PER_MILLISECOND);
        }
    }
    /*
         * Show statistics only if the test are executed with the `VERBOSE` flag set,
         * or if this `CoverageReadConsistency` is used for benchmark.
         */
    if (durations != null) {
        if (statistics == null) {
            statistics = new ArrayList<>();
        }
        statistics.add(durations);
        final int totalCount = durations.count();
        out.println("Number of failures: " + failuresCount + " / " + totalCount + " (" + (failuresCount / (totalCount / 100f)) + "%)");
    }
}
Also used : GridGeometry(org.apache.sis.coverage.grid.GridGeometry) GridExtent(org.apache.sis.coverage.grid.GridExtent) PixelIterator(org.apache.sis.image.PixelIterator) Point(java.awt.Point) Statistics(org.apache.sis.math.Statistics) Point(java.awt.Point) GridDerivation(org.apache.sis.coverage.grid.GridDerivation) GridCoverage(org.apache.sis.coverage.grid.GridCoverage)

Example 4 with PixelIterator

use of org.apache.sis.image.PixelIterator in project sis by apache.

the class FeatureAssert method assertValuesEqual.

/**
 * Verifies that sample values in the given image are equal to the expected floating point values.
 * NaN values are compared using {@link Double#doubleToRawLongBits(double)} (i.e. different NaNs
 * are <em>not</em> collapsed in a canonical NaN value).
 *
 * @param  image     the image to verify.
 * @param  band      the band to verify.
 * @param  expected  the expected sample values.
 */
public static void assertValuesEqual(final RenderedImage image, final int band, final double[][] expected) {
    assertEquals("Height", expected.length, image.getHeight());
    final PixelIterator it = new PixelIterator.Builder().setIteratorOrder(SequenceType.LINEAR).create(image);
    for (int j = 0; j < expected.length; j++) {
        final double[] row = expected[j];
        assertEquals("Width", row.length, image.getWidth());
        for (int i = 0; i < row.length; i++) {
            assertTrue(it.next());
            final double a = it.getSampleDouble(band);
            final double e = row[i];
            if (Double.doubleToRawLongBits(a) != Double.doubleToRawLongBits(e)) {
                final Point p = it.getPosition();
                fail(mismatchedSampleValue(p.x, p.y, i, j, band, e, a));
            }
        }
    }
    assertFalse(it.next());
}
Also used : PixelIterator(org.apache.sis.image.PixelIterator) Point(java.awt.Point) Point(java.awt.Point)

Aggregations

PixelIterator (org.apache.sis.image.PixelIterator)4 Point (java.awt.Point)3 AffineTransform (java.awt.geom.AffineTransform)1 ComponentSampleModel (java.awt.image.ComponentSampleModel)1 DataBuffer (java.awt.image.DataBuffer)1 MultiPixelPackedSampleModel (java.awt.image.MultiPixelPackedSampleModel)1 RasterFormatException (java.awt.image.RasterFormatException)1 SampleModel (java.awt.image.SampleModel)1 SinglePixelPackedSampleModel (java.awt.image.SinglePixelPackedSampleModel)1 GridCoverage (org.apache.sis.coverage.grid.GridCoverage)1 GridDerivation (org.apache.sis.coverage.grid.GridDerivation)1 GridExtent (org.apache.sis.coverage.grid.GridExtent)1 GridGeometry (org.apache.sis.coverage.grid.GridGeometry)1 Statistics (org.apache.sis.math.Statistics)1