/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 GeoSolutions
* Licensed 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 it.geosolutions.jaiext.errordiffusion;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import it.geosolutions.jaiext.iterators.RandomIterFactory;
import it.geosolutions.jaiext.range.Range;
import it.geosolutions.jaiext.range.RangeFactory;
import it.geosolutions.jaiext.stats.Statistics;
import it.geosolutions.jaiext.stats.Statistics.StatsType;
import it.geosolutions.jaiext.stats.StatisticsDescriptor;
import it.geosolutions.jaiext.testclasses.TestBase;
import it.geosolutions.jaiext.testclasses.TestData;
import it.geosolutions.rendered.viewer.RenderedImageBrowser;
import java.awt.Rectangle;
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.RenderedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.media.jai.ColorCube;
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import javax.media.jai.LookupTableJAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.ROI;
import javax.media.jai.ROIShape;
import javax.media.jai.RasterFactory;
import javax.media.jai.RenderedOp;
import javax.media.jai.iterator.RandomIter;
import org.junit.Test;
/**
* Test class for the ErrorDiffusion operation
*
* @author Nicola Lagomarsini geosolutions
*
*/
public class ErrorDiffusionTest extends TestBase {
private static final double TOLERANCE = 0.01d;
/**
* Synthetic with Short Sample Model
*
* @throws IOException
*/
@Test
public void testSyntheticShort() throws IOException {
// Create simple lookuptable
float[] data = new float[256];
for (int i = 0; i < 256; i++) {
data[i] = i;
}
LookupTableJAI lt = new LookupTableJAI(data);
// Create the Kernel
KernelJAI k = KernelJAI.GRADIENT_MASK_SOBEL_VERTICAL;
final BufferedImage image = getSyntheticShortImage();
ParameterBlockJAI pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
RenderedOp finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, null, null);
finalimage.dispose();
// ROI creation
ROI roi = new ROIShape(new Rectangle(image.getMinX() + 5, image.getMinY() + 5,
image.getWidth() / 4, image.getHeight() / 4));
Range nodata = RangeFactory.create((short) 5, (short) 5);
// ROI
pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
pbj.setParameter("roi", roi);
finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, roi, null);
finalimage.dispose();
// NODATA
pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
pbj.setParameter("nodata", nodata);
finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, null, nodata);
finalimage.dispose();
// NODATA AND ROI
pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
pbj.setParameter("roi", roi);
pbj.setParameter("nodata", nodata);
finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, roi, nodata);
finalimage.dispose();
}
/**
* Method for checking if ROI and NoData are properly set
*
* @param finalimage
* @param image
* @param roi
* @param nodata
*/
private void checkNoDataROI(RenderedOp finalimage, RenderedImage image, ROI roi, Range nodata) {
// Ensure the dimensions are the same
assertEquals(finalimage.getMinX(), image.getMinX());
assertEquals(finalimage.getMinY(), image.getMinY());
assertEquals(finalimage.getWidth(), image.getWidth());
assertEquals(finalimage.getHeight(), image.getHeight());
boolean roiExists = roi != null;
boolean nodataExists = nodata != null;
// If ROI and NoData are not present we only check that maximum and minimum are not equals
if (!roiExists && !nodataExists) {
StatsType[] stats = new StatsType[] { StatsType.EXTREMA };
RenderedOp calculated = StatisticsDescriptor.create(finalimage, 1, 1, null, null,
false, new int[] { 0 }, stats, null);
Statistics stat = ((Statistics[][]) calculated.getProperty(Statistics.STATS_PROPERTY))[0][0];
double[] result = (double[]) stat.getResult();
final double minimum = result[0];
final double maximum = result[1];
assertTrue(minimum < maximum);
return;
}
if (nodataExists) {
nodata = RangeFactory.convertToDoubleRange(nodata);
}
RandomIter roiIter = null;
Rectangle roiBounds = null;
if (roiExists) {
PlanarImage roiIMG = roi.getAsImage();
roiIter = RandomIterFactory.create(roiIMG, finalimage.getBounds(), true, true);
roiBounds = roi.getBounds();
}
// Else check ROI and NoData
RandomIter sourceIter = RandomIterFactory.create(image, null, true, true);
RandomIter destIter = RandomIterFactory.create(finalimage, null, true, true);
// Start the iteration (we iterate only the first band)
int w = image.getWidth();
int h = image.getHeight();
int minX = image.getMinX();
int minY = image.getMinY();
int maxX = minX + w;
int maxY = minY + h;
for (int y = minY; y < maxY; y++) {
for (int x = minX; x < maxX; x++) {
double src = sourceIter.getSampleDouble(x, y, 0);
double dest = destIter.getSampleDouble(x, y, 0);
boolean valid = true;
// ROI Check
if (roiExists && !(roiBounds.contains(x, y) && roiIter.getSample(x, y, 0) > 0)) {
valid = false;
}
// NoData Check
if (nodataExists && nodata.contains(src)) {
valid = false;
}
if (!valid) {
assertEquals(0d, dest, TOLERANCE);
}
}
}
}
/**
* Synthetic image with Short Sample Model
*
* @return {@linkplain BufferedImage}
*/
private BufferedImage getSyntheticShortImage() {
final int width = 256;
final int height = 256;
final WritableRaster raster = RasterFactory.createBandedRaster(DataBuffer.TYPE_USHORT,
width, height, 1, null);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
raster.setSample(x, y, 0, (x + y));
}
}
final ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
final BufferedImage image = new BufferedImage(cm, raster, false, null);
return image;
}
/**
* Spearfish test-case.
*
* @throws IOException
*/
@Test
public void testTiff() throws IOException {
ColorCube lt = ColorCube.BYTE_496;
KernelJAI k = KernelJAI.ERROR_FILTER_FLOYD_STEINBERG;
final RenderedImage image = getTestTiff();
ParameterBlockJAI pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
RenderedOp finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, null, null);
finalimage.dispose();
// ROI creation
ROI roi = new ROIShape(new Rectangle(image.getMinX() + 5, image.getMinY() + 5,
image.getWidth() / 4, image.getHeight() / 4));
Range nodata = RangeFactory.create((byte) 5, (byte) 5);
// ROI
pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
pbj.setParameter("roi", roi);
finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, roi, null);
finalimage.dispose();
// NODATA
pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
pbj.setParameter("nodata", nodata);
finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, null, nodata);
finalimage.dispose();
// NODATA AND ROI
pbj = new ParameterBlockJAI("ErrorDiffusion");
pbj.addSource(image);
pbj.setParameter("errorKernel", k);
pbj.setParameter("colorMap", lt);
pbj.setParameter("roi", roi);
pbj.setParameter("nodata", nodata);
finalimage = JAI.create("ErrorDiffusion", pbj);
if (INTERACTIVE)
RenderedImageBrowser.showChain(finalimage, false, false, null);
else
finalimage.getTiles();
// Check NoData and ROI
checkNoDataROI(finalimage, image, roi, nodata);
finalimage.dispose();
}
/**
* Building an image based on Spearfish data.
*
* @return {@linkplain BufferedImage}
*
* @throws IOException
* @throws FileNotFoundException
*/
private RenderedImage getTestTiff() throws IOException, FileNotFoundException {
File spearfish = TestData.file(this, "test.tif");
RenderedOp image = JAI.create("ImageRead", spearfish);
return image;
}
}