/******************************************************************************* * Copyright (c) 2016 Weasis Team and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Nicolas Roduit - initial API and implementation *******************************************************************************/ package org.weasis.core.api.image.op; import java.awt.Rectangle; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.util.LinkedList; import java.util.ListIterator; import javax.media.jai.PixelAccessor; import javax.media.jai.ROI; import javax.media.jai.StatisticsOpImage; import javax.media.jai.UnpackedImageData; public class ImageStatisticsOpImage extends StatisticsOpImage { private double[][] results; private final Double excludedMin; private final Double excludedMax; private boolean isInitialized = false; private PixelAccessor srcPA; private int srcSampleType; private long totalPixelCount; public ImageStatisticsOpImage(RenderedImage source, ROI roi, int xStart, int yStart, int xPeriod, int yPeriod, Double excludedMin, Double excludedMax) { super(source, roi, xStart, yStart, xPeriod, yPeriod); results = null; this.excludedMin = excludedMin; this.excludedMax = excludedMax; } private final boolean tileIntersectsROI(int tileX, int tileY) { if (roi == null) { // ROI is entire tile return true; } else { return roi.intersects(tileXToX(tileX), tileYToY(tileY), tileWidth, tileHeight); } } private final int startPosition(int pos, int start, int period) { int t = (pos - start) % period; if (t == 0) { return pos; } else { return (pos + (period - t)); } } @Override protected String[] getStatisticsNames() { return new String[] { "statistics" }; //$NON-NLS-1$ } @Override protected Object createStatistics(String name) { int numBands = sampleModel.getNumBands(); Object stats = null; if (name.equalsIgnoreCase("statistics")) { //$NON-NLS-1$ stats = new double[3][numBands]; } else { stats = java.awt.Image.UndefinedProperty; } return stats; } @Override protected void accumulateStatistics(String name, Raster source, Object stats) { if (!isInitialized) { srcPA = new PixelAccessor(getSourceImage(0)); srcSampleType = srcPA.sampleType == PixelAccessor.TYPE_BIT ? DataBuffer.TYPE_BYTE : srcPA.sampleType; results = new double[3][srcPA.numBands]; for (int i = 0; i < results[0].length; i++) { results[0][i] = Double.MAX_VALUE; results[1][i] = -Double.MAX_VALUE; results[2][i] = 0.0; } totalPixelCount = 0; isInitialized = true; } Rectangle srcBounds = getSourceImage(0).getBounds().intersection(source.getBounds()); LinkedList rectList; if (roi == null) { // ROI is the whole Raster rectList = new LinkedList(); rectList.addLast(srcBounds); } else { rectList = roi.getAsRectangleList(srcBounds.x, srcBounds.y, srcBounds.width, srcBounds.height); if (rectList == null) { return; // ROI does not intersect with Raster boundary. } } ListIterator iterator = rectList.listIterator(0); while (iterator.hasNext()) { Rectangle rect = srcBounds.intersection((Rectangle) iterator.next()); int tx = rect.x; int ty = rect.y; // Find the actual ROI based on start and period. rect.x = startPosition(tx, xStart, xPeriod); rect.y = startPosition(ty, yStart, yPeriod); rect.width = tx + rect.width - rect.x; rect.height = ty + rect.height - rect.y; if (rect.isEmpty()) { continue; // no pixel to count in this rectangle } UnpackedImageData uid = srcPA.getPixels(source, rect, srcSampleType, false); switch (uid.type) { case DataBuffer.TYPE_BYTE: accumulateStatisticsByte(uid); break; case DataBuffer.TYPE_USHORT: accumulateStatisticsUShort(uid); break; case DataBuffer.TYPE_SHORT: accumulateStatisticsShort(uid); break; case DataBuffer.TYPE_INT: accumulateStatisticsInt(uid); break; case DataBuffer.TYPE_FLOAT: accumulateStatisticsFloat(uid); break; case DataBuffer.TYPE_DOUBLE: accumulateStatisticsDouble(uid); break; } } if (name.equalsIgnoreCase("statistics")) { //$NON-NLS-1$ double[][] ext = (double[][]) stats; for (int i = 0; i < srcPA.numBands; i++) { ext[0][i] = results[0][i]; ext[1][i] = results[1][i]; if (totalPixelCount <= 0) { ext[0][i] = Double.NaN; ext[1][i] = Double.NaN; ext[2][i] = Double.NaN; } else { ext[0][i] = results[0][i]; ext[1][i] = results[1][i]; ext[2][i] = results[2][i] / totalPixelCount; } } } } private void accumulateStatisticsByte(UnpackedImageData uid) { Rectangle rect = uid.rect; byte[][] data = uid.getByteData(); int lineStride = uid.lineStride; int pixelStride = uid.pixelStride; int lineInc = lineStride * yPeriod; int pixelInc = pixelStride * xPeriod; boolean noBound = excludedMin == null || excludedMax == null; int exMin = noBound ? 0 : excludedMin.intValue(); int exMax = noBound ? 0 : excludedMax.intValue(); for (int b = 0; b < srcPA.numBands; b++) { int min = (int) results[0][b]; // minimum int max = (int) results[1][b]; // maximum long totalValues = 0; int outRange = 0; byte[] d = data[b]; int lastLine = uid.bandOffsets[b] + rect.height * lineStride; for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) { int lastPixel = lo + rect.width * pixelStride; for (int po = lo; po < lastPixel; po += pixelInc) { int p = d[po] & 0xff; boolean inRange = noBound || (p < exMin || p > exMax); if (inRange) { if (p < min) { min = p; } if (p > max) { max = p; } totalValues += p; } else { outRange++; } } } totalPixelCount -= outRange; results[0][b] = min; results[1][b] = max; results[2][b] += totalValues; } totalPixelCount += (int) Math.ceil((double) rect.height / yPeriod) * (int) Math.ceil((double) rect.width / xPeriod); } private void accumulateStatisticsUShort(UnpackedImageData uid) { Rectangle rect = uid.rect; short[][] data = uid.getShortData(); int lineStride = uid.lineStride; int pixelStride = uid.pixelStride; int lineInc = lineStride * yPeriod; int pixelInc = pixelStride * xPeriod; boolean noBound = excludedMin == null || excludedMax == null; int exMin = noBound ? 0 : excludedMin.intValue(); int exMax = noBound ? 0 : excludedMax.intValue(); for (int b = 0; b < srcPA.numBands; b++) { int min = (int) results[0][b]; // minimum int max = (int) results[1][b]; // maximum long totalValues = 0; int outRange = 0; short[] d = data[b]; int lastLine = uid.bandOffsets[b] + rect.height * lineStride; for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) { int lastPixel = lo + rect.width * pixelStride; for (int po = lo; po < lastPixel; po += pixelInc) { int p = d[po] & 0xffff; boolean inRange = noBound || (p < exMin || p > exMax); if (inRange) { if (p < min) { min = p; } if (p > max) { max = p; } totalValues += p; } else { outRange++; } } } totalPixelCount -= outRange; results[0][b] = min; results[1][b] = max; results[2][b] += totalValues; } totalPixelCount += (int) Math.ceil((double) rect.height / yPeriod) * (int) Math.ceil((double) rect.width / xPeriod); } private void accumulateStatisticsShort(UnpackedImageData uid) { Rectangle rect = uid.rect; short[][] data = uid.getShortData(); int lineStride = uid.lineStride; int pixelStride = uid.pixelStride; int lineInc = lineStride * yPeriod; int pixelInc = pixelStride * xPeriod; boolean noBound = excludedMin == null || excludedMax == null; int exMin = noBound ? 0 : excludedMin.intValue(); int exMax = noBound ? 0 : excludedMax.intValue(); for (int b = 0; b < srcPA.numBands; b++) { int min = (int) results[0][b]; // minimum int max = (int) results[1][b]; // maximum long totalValues = 0; int outRange = 0; short[] d = data[b]; int lastLine = uid.bandOffsets[b] + rect.height * lineStride; for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) { int lastPixel = lo + rect.width * pixelStride; for (int po = lo; po < lastPixel; po += pixelInc) { int p = d[po]; boolean inRange = noBound || (p < exMin || p > exMax); if (inRange) { if (p < min) { min = p; } if (p > max) { max = p; } totalValues += p; } else { outRange++; } } } totalPixelCount -= outRange; results[0][b] = min; results[1][b] = max; results[2][b] += totalValues; } totalPixelCount += (int) Math.ceil((double) rect.height / yPeriod) * (int) Math.ceil((double) rect.width / xPeriod); } private void accumulateStatisticsInt(UnpackedImageData uid) { Rectangle rect = uid.rect; int[][] data = uid.getIntData(); int lineStride = uid.lineStride; int pixelStride = uid.pixelStride; int lineInc = lineStride * yPeriod; int pixelInc = pixelStride * xPeriod; boolean noBound = excludedMin == null || excludedMax == null; float exMin = noBound ? 0 : excludedMin.floatValue(); float exMax = noBound ? 0 : excludedMax.floatValue(); for (int b = 0; b < srcPA.numBands; b++) { int min = (int) results[0][b]; // minimum int max = (int) results[1][b]; // maximum long totalValues = 0; int outRange = 0; int[] d = data[b]; int lastLine = uid.bandOffsets[b] + rect.height * lineStride; for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) { int lastPixel = lo + rect.width * pixelStride; for (int po = lo; po < lastPixel; po += pixelInc) { int p = d[po]; boolean inRange = noBound || (p < exMin || p > exMax); if (inRange) { if (p < min) { min = p; } if (p > max) { max = p; } totalValues += p; } else { outRange++; } } } totalPixelCount -= outRange; results[0][b] = min; results[1][b] = max; results[2][b] += totalValues; } totalPixelCount += (int) Math.ceil((double) rect.height / yPeriod) * (int) Math.ceil((double) rect.width / xPeriod); } private void accumulateStatisticsFloat(UnpackedImageData uid) { Rectangle rect = uid.rect; float[][] data = uid.getFloatData(); int lineStride = uid.lineStride; int pixelStride = uid.pixelStride; int lineInc = lineStride * yPeriod; int pixelInc = pixelStride * xPeriod; boolean noBound = excludedMin == null || excludedMax == null; float exMin = noBound ? 0 : excludedMin.floatValue(); float exMax = noBound ? 0 : excludedMax.floatValue(); for (int b = 0; b < srcPA.numBands; b++) { float min = (float) results[0][b]; // minimum float max = (float) results[1][b]; // maximum long totalValues = 0; int outRange = 0; float[] d = data[b]; int lastLine = uid.bandOffsets[b] + rect.height * lineStride; for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) { int lastPixel = lo + rect.width * pixelStride; for (int po = lo; po < lastPixel; po += pixelInc) { float p = d[po]; boolean inRange = noBound || (p < exMin || p > exMax); if (inRange) { if (p < min) { min = p; } if (p > max) { max = p; } totalValues += p; } else { outRange++; } } } totalPixelCount -= outRange; results[0][b] = min; results[1][b] = max; results[2][b] += totalValues; } totalPixelCount += (int) Math.ceil((double) rect.height / yPeriod) * (int) Math.ceil((double) rect.width / xPeriod); } private void accumulateStatisticsDouble(UnpackedImageData uid) { Rectangle rect = uid.rect; double[][] data = uid.getDoubleData(); int lineStride = uid.lineStride; int pixelStride = uid.pixelStride; int lineInc = lineStride * yPeriod; int pixelInc = pixelStride * xPeriod; boolean noBound = excludedMin == null || excludedMax == null; double exMin = noBound ? 0 : excludedMin; double exMax = noBound ? 0 : excludedMax; for (int b = 0; b < srcPA.numBands; b++) { double min = results[0][b]; // minimum double max = results[1][b]; // maximum long totalValues = 0; int outRange = 0; double[] d = data[b]; int lastLine = uid.bandOffsets[b] + rect.height * lineStride; for (int lo = uid.bandOffsets[b]; lo < lastLine; lo += lineInc) { int lastPixel = lo + rect.width * pixelStride; for (int po = lo; po < lastPixel; po += pixelInc) { double p = d[po]; boolean inRange = noBound || (p < exMin || p > exMax); if (inRange) { if (p < min) { min = p; } if (p > max) { max = p; } totalValues += p; } else { outRange++; } } } totalPixelCount -= outRange; results[0][b] = min; results[1][b] = max; results[2][b] += totalValues; } totalPixelCount += (int) Math.ceil((double) rect.height / yPeriod) * (int) Math.ceil((double) rect.width / xPeriod); } }