All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.testing.BoofTesting Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

There is a newer version: 0.26
Show newest version
/*
 * Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * 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 boofcv.testing;

import boofcv.core.image.*;
import boofcv.struct.image.*;
import sun.awt.image.ByteInterleavedRaster;
import sun.awt.image.IntegerInterleavedRaster;
import sun.awt.image.ShortInterleavedRaster;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Functions to aid in unit testing code for correctly handling sub-images
 *
 * @author Peter Abeles
 */
// todo remove all comwapare with border functions and use sub-images instead
@SuppressWarnings({"unchecked"})
public class BoofTesting {

	public static  T convertToGenericType(Class type) {
		if (type == ImageSInt8.class || type == ImageUInt8.class)
			return (T) ImageInt8.class;
		if (type == ImageSInt16.class || type == ImageUInt16.class)
			return (T) ImageInt16.class;
		return (T) type;
	}

	public static ImageDataType convertToGenericType(ImageDataType type) {
		if (type.isInteger()) {
			if (type.getNumBits() == 8)
				return ImageDataType.I8;
			else if (type.getNumBits() == 16)
				return ImageDataType.I16;
		}

		return type;
	}

	/**
	 * If an image is to be created then the generic type can't be used a specific one needs to be.  An arbitrary
	 * specific image type is returned here.
	 */
	public static  T convertGenericToSpecificType(Class type) {
		if (type == ImageInt8.class)
			return (T) ImageUInt8.class;
		if (type == ImageInt16.class)
			return (T) ImageSInt16.class;
		if (type == InterleavedI8.class)
			return (T) InterleavedU8.class;
		if (type == InterleavedI16.class)
			return (T) InterleavedS16.class;
		return (T) type;
	}

	/**
	 * 

* Returns an image which is a sub-image but contains the same values of the input image. Use for * testing compliance with sub-images. The subimage is created by creating a larger image, * copying over the input image into the inner portion, then creating a subimage of the copied part. *

*/ @SuppressWarnings({"unchecked"}) public static T createSubImageOf(T input) { if( input instanceof ImageSingleBand ) { return (T)createSubImageOf_S((ImageSingleBand)input); } else if( input instanceof MultiSpectral ) { return (T)createSubImageOf_MS((MultiSpectral) input); } else if( input instanceof ImageInterleaved ) { return (T)createSubImageOf_I((ImageInterleaved) input); } else { throw new IllegalArgumentException("Add support for this image type"); } } public static T createSubImageOf_S(T input) { // create the larger image T ret = (T) input._createNew(input.width + 10, input.height + 12); // create a sub-image of the inner portion ret = (T) ret.subimage(5, 7, input.width + 5, input.height + 7, null); // copy input image into the subimage ret.setTo(input); return ret; } public static T createSubImageOf_I(T input) { // create the larger image T ret = (T) input._createNew(input.width + 10, input.height + 12); // create a sub-image of the inner portion ret = (T) ret.subimage(5, 7, input.width + 5, input.height + 7, null); // copy input image into the subimage ret.setTo(input); return ret; } public static T createSubImageOf_MS(T input) { T ret = (T)new MultiSpectral(input.type,input.width,input.height,input.getNumBands()); for( int i = 0; i < input.getNumBands(); i++ ) { ret.bands[i] = createSubImageOf_S(input.getBand(i)); } ret.stride = ret.bands[0].stride; ret.startIndex = ret.bands[0].startIndex; return ret; } /** * Searches for functions that accept only images and makes sure they only accept * images which have he same width and height. * * @param testClass Instance of the class being tested */ public static void checkImageDimensionValidation(Object testClass, int numFunctions) { int count = 0; Method methods[] = testClass.getClass().getMethods(); for (Method m : methods) { // see if the inputs are all images if (!areAllInputsImages(m)) continue; // test a positive case Class params[] = m.getParameterTypes(); Object[] inputs = new Object[params.length]; for (int i = 0; i < params.length; i++) { inputs[i] = GeneralizedImageOps.createSingleBand(params[i], 10, 20); } try { m.invoke(testClass, inputs); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } // test negative cases for (int target = 0; target < params.length; target++) { for (int i = 0; i < params.length; i++) { if (i != target) inputs[i] = GeneralizedImageOps.createSingleBand(params[i], 10, 20); else inputs[i] = GeneralizedImageOps.createSingleBand(params[i], 11, 22); } try { m.invoke(testClass, inputs); throw new RuntimeException("Expected an exception here"); } catch (InvocationTargetException e) { if (e.getTargetException().getClass() != IllegalArgumentException.class) throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } count++; } if (count != numFunctions) throw new RuntimeException("Unexpected number of functions"); } private static boolean areAllInputsImages(Method m) { Class params[] = m.getParameterTypes(); if (params.length == 0) return false; for (Class p : params) { if (!ImageSingleBand.class.isAssignableFrom(p)) { return false; } } return true; } /** * Tests the specified function with the original image provided and with an equivalent * sub-image. The two results are then compared. The function being tested must only * have one input parameter of type {@link boofcv.struct.image.ImageUInt8}. * * @param testClass Instance of the class that contains the function being tested. * @param function The name of the function being tested. * @param checkEquals Checks to see if the two images have been modified the same way on output * @param inputParam The original input parameters */ // TODO make sure pixels outside are not modified of sub-matrix // todo have the submatrices be from different shaped inputs @SuppressWarnings({"unchecked"}) public static void checkSubImage(Object testClass, String function, boolean checkEquals, Object... inputParam) { try { ImageBase[] larger = new ImageBase[inputParam.length]; ImageBase[] subImg = new ImageBase[inputParam.length]; Class paramDesc[] = new Class[inputParam.length]; Object[] inputModified = new Object[inputParam.length]; for (int i = 0; i < inputParam.length; i++) { if (ImageBase.class.isAssignableFrom(inputParam[i].getClass())) { ImageBase img = (ImageBase) inputParam[i]; // copy the original image inside of a larger image larger[i] = img._createNew(img.getWidth() + 10, img.getHeight() + 12); // extract a sub-image and make it equivalent to the original image. subImg[i] = larger[i].subimage(5, 6, 5 + img.getWidth(), 6 + img.getHeight(), null); subImg[i].setTo(img); } // the first time it is called use the original inputs inputModified[i] = inputParam[i]; paramDesc[i] = inputParam[i].getClass(); } // first try it with the original image Method m = findMethod(testClass.getClass(), function, paramDesc); m.invoke(testClass, inputModified); // now try it with the sub-image for (int i = 0; i < inputModified.length; i++) { if (subImg[i] != null) inputModified[i] = subImg[i]; } m.invoke(testClass, inputModified); // the result should be the identical if (checkEquals) { for (int i = 0; i < inputParam.length; i++) { if (subImg[i] == null) continue; assertEquals((ImageBase)inputModified[i], subImg[i], 0); } } } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * Searches for a function which is a perfect match. if none it exists it checks * to see if any matches that could accept an input of the specified type. If there * is only one such match that is returned. */ public static Method findMethod(Class type, String name, Class... params) { Method methods[] = type.getMethods(); List found = new ArrayList(); for (Method m : methods) { if (m.getName().compareTo(name) != 0) continue; Class a[] = m.getParameterTypes(); if (a.length != params.length) continue; boolean match = true; for (int i = 0; i < a.length; i++) { if (a[i] != params[i]) { match = false; break; } } if (match) { // its a perfect match return m; } // see if it could be called with these parameters match = true; for (int i = 0; i < a.length; i++) { if (params[i] == a[i]) continue; if (a[i].isPrimitive()) { if (a[i] == Boolean.TYPE && params[i] == Boolean.class) continue; if (a[i] == Byte.TYPE && params[i] == Byte.class) continue; if (a[i] == Short.TYPE && params[i] == Short.class) continue; if (a[i] == Integer.TYPE && params[i] == Integer.class) continue; if (a[i] == Long.TYPE && params[i] == Long.class) continue; if (a[i] == Float.TYPE && params[i] == Float.class) continue; if (a[i] == Double.TYPE && params[i] == Double.class) continue; } if (!a[i].isAssignableFrom(params[i])) { match = false; break; } } if (match) { found.add(m); } } if (found.size() == 1) { return found.get(0); } throw new RuntimeException("Couldn't find matching *public* function to " + name); } /** * Looks up the static method then passes in the specified inputs. */ public static void callStaticMethod(Class classType, String name, Object... inputs) { Class params[] = new Class[inputs.length]; for( int i = 0; i < inputs.length; i++ ) { params[i] = inputs[i].getClass(); } Method m = findMethod(classType,name,params); if( m == null ) { for( int i = 0; i < inputs.length; i++ ) { if( params[i] == Integer.class ) { params[i] = int.class; } else if( params[i] == Float.class ) { params[i] = float.class; } else if( params[i] == Double.class ) { params[i] = double.class; } } m = findMethod(classType,name,params); } if( m == null ) throw new IllegalArgumentException("Method not found"); try { m.invoke(null,inputs); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } /** * Searches for all functions with the specified name in the target class. Once it finds * that function it invokes the specified function in the owner class. That function must * take in a Method as its one and only parameter. The method will be one of the matching * ones in the target class. * * @param owner * @param ownerMethod * @param target * @param targetMethod * @return The number of times 'targetMethod' was found and called. */ public static int findMethodThenCall(Object owner, String ownerMethod, Class target, String targetMethod) { int total = 0; Method[] list = target.getMethods(); try { Method om = owner.getClass().getMethod(ownerMethod, Method.class); for (Method m : list) { if (!m.getName().equals(targetMethod)) continue; om.invoke(owner, m); total++; } } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } return total; } public static void assertEquals(double a[], double b[], double tol) { for (int i = 0; i < a.length; i++) { double diff = Math.abs(a[i] - b[i]); if (diff > tol) throw new RuntimeException("Element " + i + " not equals. " + a[i] + " " + b[i]); } } public static void assertEquals(double a[], float b[], double tol) { for (int i = 0; i < a.length; i++) { double diff = Math.abs(a[i] - b[i]); if (diff > tol) throw new RuntimeException("Element " + i + " not equals. " + a[i] + " " + b[i]); } } public static void assertEquals(double a[], int b[]) { for (int i = 0; i < a.length; i++) { double diff = Math.abs((int) a[i] - b[i]); if (diff != 0) throw new RuntimeException("Element " + i + " not equals. " + a[i] + " " + b[i]); } } public static void assertEquals(float a[], float b[], float tol) { for (int i = 0; i < a.length; i++) { double diff = Math.abs(a[i] - b[i]); if (diff > tol) throw new RuntimeException("Element " + i + " not equals. " + a[i] + " " + b[i]); } } public static void assertEquals(ImageBase imgA, ImageBase imgB, double tol ) { // if no specialized check exists, use a slower generalized approach if( imgA instanceof ImageSingleBand ) { GImageSingleBand a = FactoryGImageSingleBand.wrap((ImageSingleBand)imgA); GImageSingleBand b = FactoryGImageSingleBand.wrap((ImageSingleBand)imgB); for( int y = 0; y < imgA.height; y++ ) { for( int x = 0; x < imgA.width; x++ ) { double valA = a.get(x,y).doubleValue(); double valB = b.get(x,y).doubleValue(); double difference = valA - valB; if( Math.abs(difference) > tol ) throw new RuntimeException("Values not equal at ("+x+","+y+") "+valA+" "+valB); } } } else if( imgA instanceof MultiSpectral && imgB instanceof MultiSpectral ){ MultiSpectral a = (MultiSpectral)imgA; MultiSpectral b = (MultiSpectral)imgB; if( a.getNumBands() != b.getNumBands() ) throw new RuntimeException("Number of bands not equal"); for( int band = 0; band < a.getNumBands(); band++ ) { assertEquals(a.getBand(band), b.getBand(band), tol); } } else if( imgA instanceof ImageMultiBand && imgB instanceof ImageMultiBand) { ImageMultiBand a = (ImageMultiBand)imgA; ImageMultiBand b = (ImageMultiBand)imgB; if( a.getNumBands() != b.getNumBands() ) throw new RuntimeException("Number of bands not equal"); int numBands = a.getNumBands(); for( int y = 0; y < imgA.height; y++ ) { for( int x = 0; x < imgA.width; x++ ) { for( int band = 0; band < numBands; band++ ) { double valA = GeneralizedImageOps.get( a, x, y, band); double valB = GeneralizedImageOps.get( b, x, y, band); double difference = valA - valB; if( Math.abs(difference) > tol ) throw new RuntimeException("Values not equal at ("+x+","+y+") "+valA+" "+valB); } } } } else { throw new RuntimeException("Unknown image type"); } } public static void assertEqualsInner(ImageBase imgA, ImageBase imgB, double tol , int borderX , int borderY , boolean relative ) { // if no specialized check exists, use a slower generalized approach if( imgA instanceof ImageSingleBand ) { GImageSingleBand a = FactoryGImageSingleBand.wrap((ImageSingleBand)imgA); GImageSingleBand b = FactoryGImageSingleBand.wrap((ImageSingleBand)imgB); for( int y = borderY; y < imgA.height-borderY; y++ ) { for( int x = borderX; x < imgA.width-borderX; x++ ) { double valA = a.get(x,y).doubleValue(); double valB = b.get(x,y).doubleValue(); double error = Math.abs(valA - valB); if( relative ) { double denominator = Math.abs(valA) + Math.abs(valB); if( denominator == 0 ) denominator = 1; error /= denominator; } if( error > tol ) throw new RuntimeException("Values not equal at ("+x+","+y+") "+valA+" "+valB); } } } else if( imgA instanceof MultiSpectral ){ MultiSpectral a = (MultiSpectral)imgA; MultiSpectral b = (MultiSpectral)imgB; if( a.getNumBands() != b.getNumBands() ) throw new RuntimeException("Number of bands not equal"); for( int band = 0; band < a.getNumBands(); band++ ) { assertEqualsInner(a.getBand(band), b.getBand(band), tol, borderX, borderY, relative); } } else { throw new RuntimeException("Unknown image type"); } } public static void assertEqualsInner(ImageBase imgA, ImageBase imgB, double tol , int borderX0 , int borderY0 , int borderX1 , int borderY1 , boolean relative ) { // if no specialized check exists, use a slower generalized approach if( imgA instanceof ImageSingleBand ) { GImageSingleBand a = FactoryGImageSingleBand.wrap((ImageSingleBand)imgA); GImageSingleBand b = FactoryGImageSingleBand.wrap((ImageSingleBand)imgB); for( int y = borderY0; y < imgA.height-borderY1; y++ ) { for( int x = borderX0; x < imgA.width-borderX1; x++ ) { double valA = a.get(x,y).doubleValue(); double valB = b.get(x,y).doubleValue(); double error = Math.abs(valA - valB); if( relative ) { double denominator = Math.abs(valA) + Math.abs(valB); if( denominator == 0 ) denominator = 1; error /= denominator; } if( error > tol ) throw new RuntimeException("Values not equal at ("+x+","+y+") "+valA+" "+valB); } } } else if( imgA instanceof MultiSpectral ){ MultiSpectral a = (MultiSpectral)imgA; MultiSpectral b = (MultiSpectral)imgB; if( a.getNumBands() != b.getNumBands() ) throw new RuntimeException("Number of bands not equal"); for( int band = 0; band < a.getNumBands(); band++ ) { assertEqualsInner(a.getBand(band), b.getBand(band), tol, borderX0, borderY0, borderX1, borderY1, relative); } } else { throw new RuntimeException("Unknown image type"); } } public static void assertEqualsRelative(ImageBase imgA, ImageBase imgB, double tolFrac ) { // if no specialized check exists, use a slower generalized approach if( imgA instanceof ImageSingleBand ) { GImageSingleBand a = FactoryGImageSingleBand.wrap((ImageSingleBand)imgA); GImageSingleBand b = FactoryGImageSingleBand.wrap((ImageSingleBand)imgB); for( int y = 0; y < imgA.height; y++ ) { for( int x = 0; x < imgA.width; x++ ) { double valA = a.get(x,y).doubleValue(); double valB = b.get(x,y).doubleValue(); double difference = valA - valB; double max = Math.max( Math.abs(valA), Math.abs(valB)); if( max == 0 ) max = 1; if( Math.abs(difference)/max > tolFrac ) throw new RuntimeException("Values not equal at ("+x+","+y+") "+valA+" "+valB); } } } else if( imgA instanceof MultiSpectral ){ MultiSpectral a = (MultiSpectral)imgA; MultiSpectral b = (MultiSpectral)imgB; if( a.getNumBands() != b.getNumBands() ) throw new RuntimeException("Number of bands not equal"); for( int band = 0; band < a.getNumBands(); band++ ) { assertEqualsRelative(a.getBand(band),b.getBand(band),tolFrac ); } } else { throw new RuntimeException("Unknown image type"); } } /** * Checks to see if only the image borders are equal to each other within tolerance */ public static void assertEqualsBorder(ImageSingleBand imgA, ImageSingleBand imgB, double tol, int borderX, int borderY) { if (imgA.getWidth() != imgB.getWidth()) throw new RuntimeException("Widths are not equals"); if (imgA.getHeight() != imgB.getHeight()) throw new RuntimeException("Heights are not equals"); GImageSingleBand a = FactoryGImageSingleBand.wrap(imgA); GImageSingleBand b = FactoryGImageSingleBand.wrap(imgB); for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < borderX; x++) { compareValues(tol, a, b, x, y); } for (int x = imgA.getWidth() - borderX; x < imgA.getWidth(); x++) { compareValues(tol, a, b, x, y); } } for (int x = borderX; x < imgA.getWidth() - borderX; x++) { for (int y = 0; y < borderY; y++) { compareValues(tol, a, b, x, y); } for (int y = imgA.getHeight() - borderY; y < imgA.getHeight(); y++) { compareValues(tol, a, b, x, y); } } } private static void compareValues(double tol, GImageSingleBand a, GImageSingleBand b, int x, int y) { double normalizer = Math.abs(a.get(x, y).doubleValue()) + Math.abs(b.get(x, y).doubleValue()); if (normalizer < 1.0) normalizer = 1.0; if (Math.abs(a.get(x, y).doubleValue() - b.get(x, y).doubleValue()) / normalizer > tol) throw new RuntimeException("values not equal at (" + x + " " + y + ") " + a.get(x, y) + " " + b.get(x, y)); } public static void checkEquals(BufferedImage imgA, ImageBase imgB, boolean boofcvBandOrder,double tol ) { if (ImageUInt8.class == imgB.getClass()) { checkEquals(imgA, (ImageUInt8) imgB); } else if (ImageInt16.class.isAssignableFrom(imgB.getClass())) { checkEquals( imgA, (ImageInt16) imgB ); } else if (ImageFloat32.class == imgB.getClass()) { checkEquals(imgA, (ImageFloat32) imgB, (float) tol); } else if (ImageInterleaved.class.isInstance(imgB) ) { checkEquals(imgA, (ImageMultiBand) imgB, boofcvBandOrder, (float)tol ); } else if (MultiSpectral.class == imgB.getClass()) { checkEquals(imgA, (ImageMultiBand) imgB, boofcvBandOrder,(float) tol); } else { throw new IllegalArgumentException("Unknown"); } } /** * Checks to see if the BufferedImage has the same intensity values as the ImageUInt8 * * @param imgA BufferedImage * @param imgB ImageUInt8 */ public static void checkEquals(BufferedImage imgA, ImageUInt8 imgB) { if (imgA.getRaster() instanceof ByteInterleavedRaster && imgA.getType() != BufferedImage.TYPE_BYTE_INDEXED) { ByteInterleavedRaster raster = (ByteInterleavedRaster) imgA.getRaster(); if (raster.getNumBands() == 1) { int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0)-raster.getNumBands()+1; // handle a special case where the RGB conversion is screwed for (int i = 0; i < imgA.getHeight(); i++) { for (int j = 0; j < imgA.getWidth(); j++) { int valB = imgB.get(j, i); int valA = raster.getDataStorage()[ offsetA + i*strideA + j]; if (!imgB.getDataType().isSigned()) valA &= 0xFF; if (valA != valB) throw new RuntimeException("Images are not equal: "+valA+" "+valB); } } return; } } for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < imgA.getWidth(); x++) { int rgb = imgA.getRGB(x, y); int gray = (byte) ((((rgb >>> 16) & 0xFF) + ((rgb >>> 8) & 0xFF) + (rgb & 0xFF)) / 3); int grayB = imgB.get(x, y); if (!imgB.getDataType().isSigned()) gray &= 0xFF; if (Math.abs(gray - grayB) != 0) { throw new RuntimeException("images are not equal: (" + x + " , " + y + ") A = " + gray + " B = " + grayB); } } } } /** * Checks to see if the BufferedImage has the same intensity values as the ImageUInt8 * * @param imgA BufferedImage * @param imgB ImageUInt8 */ public static void checkEquals(BufferedImage imgA, ImageInt16 imgB) { if (imgA.getRaster() instanceof ByteInterleavedRaster && imgA.getType() != BufferedImage.TYPE_BYTE_INDEXED) { ByteInterleavedRaster raster = (ByteInterleavedRaster) imgA.getRaster(); if (raster.getNumBands() == 1) { int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0)-raster.getNumBands()+1; // handle a special case where the RGB conversion is screwed for (int i = 0; i < imgA.getHeight(); i++) { for (int j = 0; j < imgA.getWidth(); j++) { int valB = imgB.get(j, i); int valA = raster.getDataStorage()[ offsetA + i*strideA + j]; if (!imgB.getDataType().isSigned()) valA &= 0xFFFF; if (valA != valB) throw new RuntimeException("Images are not equal: "+valA+" "+valB); } } return; } } else if (imgA.getRaster() instanceof ShortInterleavedRaster) { ShortInterleavedRaster raster = (ShortInterleavedRaster) imgA.getRaster(); if (raster.getNumBands() == 1) { int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0)-raster.getNumBands()+1; // handle a special case where the RGB conversion is screwed for (int i = 0; i < imgA.getHeight(); i++) { for (int j = 0; j < imgA.getWidth(); j++) { int valB = imgB.get(j, i); int valA = raster.getDataStorage()[ offsetA + i*strideA + j]; if (!imgB.getDataType().isSigned()) valA &= 0xFFFF; if (valA != valB) throw new RuntimeException("Images are not equal: "+valA+" "+valB); } } } } else { for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < imgA.getWidth(); x++) { int rgb = imgA.getRGB(x, y); int gray = ((((rgb >>> 16) & 0xFF) + ((rgb >>> 8) & 0xFF) + (rgb & 0xFF)) / 3); int grayB = imgB.get(x, y); if (!imgB.getDataType().isSigned()) gray &= 0xFFFF; if (Math.abs(gray - grayB) != 0) { throw new RuntimeException("images are not equal: (" + x + " , " + y + ") A = " + gray + " B = " + grayB); } } } } } /** * Checks to see if the BufferedImage has the same intensity values as the ImageUInt8 * * @param imgA BufferedImage * @param imgB ImageUInt8 */ public static void checkEquals(BufferedImage imgA, ImageFloat32 imgB, float tol) { if (imgA.getRaster() instanceof ByteInterleavedRaster && imgA.getType() != BufferedImage.TYPE_BYTE_INDEXED ) { ByteInterleavedRaster raster = (ByteInterleavedRaster) imgA.getRaster(); if (raster.getNumBands() == 1) { int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0)-raster.getNumBands()+1; // handle a special case where the RGB conversion is screwed for (int i = 0; i < imgA.getHeight(); i++) { for (int j = 0; j < imgA.getWidth(); j++) { float valB = imgB.get(j, i); int valA = raster.getDataStorage()[offsetA + i * strideA + j]; valA &= 0xFF; if (Math.abs(valA - valB) > tol) throw new RuntimeException("Images are not equal: A = " + valA + " B = " + valB); } } return; } } for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < imgA.getWidth(); x++) { int rgb = imgA.getRGB(x, y); float gray = (((rgb >>> 16) & 0xFF) + ((rgb >>> 8) & 0xFF) + (rgb & 0xFF)) / 3.0f; float grayB = imgB.get(x, y); if (Math.abs(gray - grayB) > tol) { throw new RuntimeException("images are not equal: A = " + gray + " B = " + grayB); } } } } public static void checkEquals(WritableRaster imgA, ImageMultiBand imgB, float tol) { GImageMultiBand genericB = FactoryGImageMultiBand.wrap(imgB); float pixelB[] = new float[ imgB.getNumBands() ]; if( imgA.getNumBands() != imgB.getNumBands()) { throw new RuntimeException("Number of bands not equals"); } if( imgA instanceof ByteInterleavedRaster ) { ByteInterleavedRaster raster = (ByteInterleavedRaster) imgA; byte dataA[] = raster.getDataStorage(); int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0)-raster.getPixelStride()+1; // handle a special case where the RGB conversion is screwed for (int y = 0; y < imgA.getHeight(); y++) { int indexA = offsetA + strideA * y; for (int x = 0; x < imgA.getWidth(); x++) { genericB.get(x,y,pixelB); for( int k = 0; k < imgB.getNumBands(); k++ ) { int valueA = dataA[indexA++] & 0xFF; double valueB = pixelB[k]; if( Math.abs(valueA- valueB) > tol ) throw new RuntimeException("Images are not equal: A = " + valueA + " B = " + valueB); } } } } else if( imgA instanceof IntegerInterleavedRaster) { IntegerInterleavedRaster raster = (IntegerInterleavedRaster) imgA; int dataA[] = raster.getDataStorage(); int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0)-raster.getPixelStride()+1; // handle a special case where the RGB conversion is screwed for (int y = 0; y < imgA.getHeight(); y++) { int indexA = offsetA + strideA * y; for (int x = 0; x < imgA.getWidth(); x++) { genericB.get(x,y,pixelB); int valueA = dataA[indexA++]; if( imgB.getNumBands() == 4 ) { int found0 = (valueA >> 24) & 0xFF; int found1 = (valueA >> 16) & 0xFF; int found2 = (valueA >> 8) & 0xFF; int found3 = valueA & 0xFF; if( Math.abs(found0-pixelB[0]) > tol ) throw new RuntimeException("Images are not equal"); if( Math.abs(found1-pixelB[1]) > tol ) throw new RuntimeException("Images are not equal"); if( Math.abs(found2-pixelB[2]) > tol ) throw new RuntimeException("Images are not equal"); if( Math.abs(found3-pixelB[3]) > tol ) throw new RuntimeException("Images are not equal"); } else if( imgB.getNumBands() == 3 ) { int found0 = (valueA >> 16) & 0xFF; int found1 = (valueA >> 8) & 0xFF; int found2 = valueA & 0xFF; if( Math.abs(found0-pixelB[0]) > tol ) throw new RuntimeException("Images are not equal"); if( Math.abs(found1-pixelB[1]) > tol ) throw new RuntimeException("Images are not equal"); if( Math.abs(found2-pixelB[2]) > tol ) throw new RuntimeException("Images are not equal"); } else { throw new RuntimeException("Unexpectd number of bands"); } } } } else { throw new RuntimeException("Add support for raster type "+imgA.getClass().getSimpleName()); } } public static void checkEquals(BufferedImage imgA, ImageMultiBand imgB, boolean boofcvBandOrder , float tol) { GImageMultiBand genericB = FactoryGImageMultiBand.wrap(imgB); float pixelB[] = new float[ imgB.getNumBands() ]; if (imgA.getRaster() instanceof ByteInterleavedRaster && imgA.getType() != BufferedImage.TYPE_BYTE_INDEXED ) { ByteInterleavedRaster raster = (ByteInterleavedRaster) imgA.getRaster(); if (raster.getNumBands() == 1) { int strideA = raster.getScanlineStride(); int offsetA = raster.getDataOffset(0)-raster.getPixelStride()+1; // handle a special case where the RGB conversion is screwed for (int i = 0; i < imgA.getHeight(); i++) { for (int j = 0; j < imgA.getWidth(); j++) { genericB.get(j,i,pixelB); double valB = pixelB[0]; int valA = raster.getDataStorage()[offsetA + i * strideA + j]; valA &= 0xFF; if (Math.abs(valA - valB) > tol) throw new RuntimeException("Images are not equal: A = " + valA + " B = " + valB); } } return; } } int bandOrder[]; if( boofcvBandOrder ) { if( imgB.getNumBands() == 4 ) { bandOrder = new int[]{1,2,3,0}; } else { bandOrder = new int[]{0,1,2}; } } else { if( imgA.getType() == BufferedImage.TYPE_INT_RGB ) { bandOrder = new int[]{0,1,2}; } else if( imgA.getType() == BufferedImage.TYPE_INT_BGR || imgA.getType() == BufferedImage.TYPE_3BYTE_BGR ) { bandOrder = new int[]{2,1,0}; } else if( imgA.getType() == BufferedImage.TYPE_4BYTE_ABGR ) { bandOrder = new int[]{0,3,2,1}; } else if( imgA.getType() == BufferedImage.TYPE_INT_ARGB ) { bandOrder = new int[]{0,1,2,3}; } else { bandOrder = new int[]{0,1,2}; } } int expected[] = new int[4]; for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < imgA.getWidth(); x++) { // getRGB() automatically converts the band order to ARGB int rgb = imgA.getRGB(x, y); expected[0] = ((rgb >>> 24) & 0xFF); // alpha expected[1] = ((rgb >>> 16) & 0xFF); // red expected[2] = ((rgb >>> 8) & 0xFF); // green expected[3] = (rgb & 0xFF); // blue if( imgB.getNumBands() == 4 ) { genericB.get(x,y,pixelB); for( int i = 0; i < 4; i++ ) { double found = pixelB[bandOrder[i]]; if( Math.abs(Math.exp(expected[i]- found)) > tol ) { for( int j = 0; j < 4; j++ ) { System.out.println(expected[j]+" "+pixelB[bandOrder[j]]); } throw new RuntimeException("Images are not equal: band - "+i+" type "+imgA.getType()); } } } else if( imgB.getNumBands() == 3 ) { genericB.get(x, y, pixelB); for (int i = 0; i < 3; i++) { double found = pixelB[bandOrder[i]]; if (Math.abs(expected[i + 1] - found) > tol) { for (int j = 0; j < 3; j++) { System.out.println(expected[j + 1] + " " + pixelB[bandOrder[j]]); } throw new RuntimeException("Images are not equal: band - " + i + " type " + imgA.getType()); } } } else if( imgB.getNumBands() == 1 ) { genericB.get(x, y, pixelB); double expectedGray = (expected[1]+expected[2]+expected[3])/3.0; if (Math.abs(expectedGray - pixelB[0]) > tol) { throw new RuntimeException("Images are not equal: "+imgA.getType()+" single band multi banded"); } } else { throw new RuntimeException("Unexpected number of bands"); } } } } public static void checkBorderZero(ImageSingleBand outputImage, int border) { GImageSingleBand img = FactoryGImageSingleBand.wrap(outputImage); for (int y = 0; y < img.getHeight(); y++) { if (y >= border && y < img.getHeight() - border) continue; for (int x = 0; x < img.getWidth(); x++) { if (x >= border && x < img.getWidth() - border) continue; if (img.get(x, y).intValue() != 0) throw new RuntimeException("The border is not zero: "+x+" "+y); } } } public static void checkBorderZero(ImageSingleBand outputImage, int borderX0 , int borderY0 , int borderX1 , int borderY1 ) { GImageSingleBand img = FactoryGImageSingleBand.wrap(outputImage); for (int y = 0; y < img.getHeight(); y++) { if (y >= borderY0 && y < img.getHeight() - borderY1) continue; for (int x = 0; x < img.getWidth(); x++) { if (x >= borderX0 && x < img.getWidth() - borderX1) continue; if (img.get(x, y).intValue() != 0) throw new RuntimeException("The border is not zero: "+x+" "+y); } } } public static void printDiff(ImageSingleBand imgA, ImageSingleBand imgB) { GImageSingleBand a = FactoryGImageSingleBand.wrap(imgA); GImageSingleBand b = FactoryGImageSingleBand.wrap(imgB); System.out.println("------- Difference -----------"); for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < imgA.getWidth(); x++) { double diff = Math.abs(a.get(x, y).doubleValue() - b.get(x, y).doubleValue()); System.out.printf("%2d ", (int) diff); } System.out.println(); } } public static void printDiffBinary(ImageUInt8 imgA, ImageUInt8 imgB) { System.out.println("------- Difference -----------"); for (int y = 0; y < imgA.getHeight(); y++) { for (int x = 0; x < imgA.getWidth(); x++) { if( imgA.unsafe_get(x,y) != imgB.unsafe_get(x,y)) System.out.print(" x"); else System.out.print(" ."); } System.out.println(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy