/* * 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.core.image; import boofcv.alg.misc.GImageMiscOps; import boofcv.struct.image.*; import boofcv.testing.BoofTesting; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Random; import static org.junit.Assert.*; /** * @author Peter Abeles */ @SuppressWarnings("Duplicates") public class TestConvertImage { Random rand = new Random(34); int imgWidth = 10; int imgHeight = 20; @Test public void checkAllConvert() { int count = 0; Method methods[] = ConvertImage.class.getMethods(); for (Method m : methods) { Class[] inputTypes = m.getParameterTypes(); if( inputTypes.length < 2) continue; Class<?> outputType = inputTypes[inputTypes.length-1]; if( (inputTypes.length != 5 && inputTypes.length != 2) || !ImageBase.class.isAssignableFrom(outputType)) continue; Class<?> inputType = inputTypes[0]; // System.out.println(m.getName()+" "+inputType.getSimpleName()+" "+outputType.getSimpleName()+" "+m.getReturnType()); // make sure the return type equals the output type assertTrue(outputType == m.getReturnType()); if( m.getName().contains("convert") ) { if( inputTypes.length == 5 ) { checkConvertIntegerRange(m,inputTypes); } else { checkConvert(m, inputType, outputType); } } else { if( inputType == Planar.class ) checkMultiAverage(m, inputType, outputType); else checkInterleavedAverage(m, inputType, outputType); } count++; } assertEquals(8*7 + 8*7 +8+8+8+8+8,count); } private void checkConvert( Method m , Class inputType , Class outputType ) { if( ImageGray.class.isAssignableFrom(inputType) ) { checkConvertSingle(m, inputType, outputType); } else if( ImageInterleaved.class.isAssignableFrom(inputType)) { if( ImageInterleaved.class.isAssignableFrom(outputType) ) checkConvertInterleaved(m, inputType, outputType); else checkConvertInterleavedToMulti(m, inputType, outputType); } else { checkConvertMultiToInterleaved(m,inputType,outputType); } } private void checkConvertIntegerRange( Method m , Class[] types ) { Class inputType = types[0]; ImageGray input = GeneralizedImageOps.createSingleBand(inputType, imgWidth, imgHeight); GrayU8 output = new GrayU8(imgWidth,imgHeight); boolean inputSigned = true; if( GrayI.class.isAssignableFrom(inputType) ) inputSigned = input.getDataType().isSigned(); // only provide signed numbers of both data types can handle them if( inputSigned ) { GImageMiscOps.fillUniform(input, rand, -10, 10); } else { GImageMiscOps.fillUniform(input, rand, 0, 20); } BoofTesting.checkSubImage(this,"checkConvertIntegerRange",true,m,input,output); } public void checkConvertIntegerRange(Method m , ImageGray<?> input , GrayU8 output ) { try { GrayU8 ret; double tol = selectTolerance(input,output); // check it with a non-null output ret = invokeConvertIntegerRange(m, input, output); assertTrue(ret == output); checkResultsIntegerRange(ret); // check it with a null output ret = invokeConvertIntegerRange(m, input, null); checkResultsIntegerRange(ret); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } private GrayU8 invokeConvertIntegerRange(Method m, ImageGray<?> input, GrayU8 output) throws IllegalAccessException, InvocationTargetException { GrayU8 ret; if( input.getDataType().isInteger() ) ret = (GrayU8)m.invoke(null,input,-10,20,8,output); else if( input.getDataType().getNumBits() == 32 ) ret = (GrayU8)m.invoke(null,input,-10.0f,20.0f,8,output); else ret = (GrayU8)m.invoke(null,input,-10.0,20.0,8,output); return ret; } private void checkResultsIntegerRange( GrayU8 output ) { int notZero = 0; for (int y = 0; y < output.height; y++) { for (int x = 0; x < output.width; x++) { int found = output.get(x,y); assertTrue(found>=0 && found < 8); if( found != 0 ) notZero++; } } assertTrue(notZero>0); } private void checkConvertSingle( Method m , Class inputType , Class outputType ) { ImageGray input = GeneralizedImageOps.createSingleBand(inputType, imgWidth, imgHeight); ImageGray output = GeneralizedImageOps.createSingleBand(outputType, imgWidth, imgHeight); boolean inputSigned = true; boolean outputSigned = true; if( GrayI.class.isAssignableFrom(inputType) ) inputSigned = input.getDataType().isSigned(); if( GrayI.class.isAssignableFrom(outputType) ) outputSigned = output.getDataType().isSigned(); // only provide signed numbers of both data types can handle them if( inputSigned && outputSigned ) { GImageMiscOps.fillUniform(input, rand, -10, 10); } else { GImageMiscOps.fillUniform(input, rand, 0, 20); } BoofTesting.checkSubImage(this,"checkConvertSingle",true,m,input,output); } private void checkConvertInterleaved( Method m , Class inputType , Class outputType ) { ImageInterleaved input = GeneralizedImageOps.createInterleaved(inputType, imgWidth, imgHeight,2); ImageInterleaved output = GeneralizedImageOps.createInterleaved(outputType, imgWidth, imgHeight, 2); boolean inputSigned = true; boolean outputSigned = true; if( input.getImageType().getDataType().isInteger() ) inputSigned = input.getDataType().isSigned(); if( output.getImageType().getDataType().isInteger() ) outputSigned = output.getDataType().isSigned(); // only provide signed numbers of both data types can handle them if( inputSigned && outputSigned ) { GImageMiscOps.fillUniform(input, rand, -10, 10); } else { GImageMiscOps.fillUniform(input, rand, 0, 20); } BoofTesting.checkSubImage(this, "checkConvertInterleaved", true, m, input, output); } public void checkConvertSingle(Method m , ImageGray<?> input , ImageGray<?> output ) { try { double tol = selectTolerance(input,output); // check it with a non-null output ImageGray<?> ret = (ImageGray<?>)m.invoke(null,input,output); assertTrue(ret == output); BoofTesting.assertEquals(input, ret, tol); // check it with a null output ret = (ImageGray<?>)m.invoke(null,input,null); BoofTesting.assertEquals(input, ret, tol); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } public void checkConvertInterleaved( Method m , ImageInterleaved<?> input , ImageInterleaved<?> output ) { try { double tol = selectTolerance(input,output); // check it with a non-null output ImageInterleaved<?> ret = (ImageInterleaved<?>)m.invoke(null,input,output); assertTrue(ret == output); BoofTesting.assertEquals(input, ret, tol); // check it with a null output ret = (ImageInterleaved<?>)m.invoke(null,input,null); BoofTesting.assertEquals(input, ret, tol); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } private void checkConvertInterleavedToMulti( Method m , Class inputType , Class outputType ) { ImageInterleaved input = GeneralizedImageOps.createInterleaved(inputType, imgWidth, imgHeight,2); Class bandType = ImageDataType.typeToSingleClass(input.getDataType()); Planar output = new Planar(bandType,imgWidth, imgHeight, 2); boolean inputSigned = true; if( input.getImageType().getDataType().isInteger() ) inputSigned = input.getDataType().isSigned(); // only provide signed numbers of both data types can handle them if( inputSigned ) { GImageMiscOps.fillUniform(input, rand, -10, 10); } BoofTesting.checkSubImage(this, "checkConvertInterleavedToMulti", true, m, input, output); } public void checkConvertInterleavedToMulti( Method m , ImageInterleaved<?> input , Planar<?> output ) { try { double tol = 1e-4; // check it with a non-null output Planar<?> ret = (Planar<?>)m.invoke(null,input,output); assertTrue(ret == output); BoofTesting.assertEquals(input, ret, tol); // check it with a null output ret = (Planar<?>)m.invoke(null,input,null); BoofTesting.assertEquals(input, ret, tol); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } private void checkConvertMultiToInterleaved( Method m , Class inputType , Class outputType ) { ImageInterleaved output = GeneralizedImageOps.createInterleaved(outputType, imgWidth, imgHeight,2); Class bandType = ImageDataType.typeToSingleClass(output.getDataType()); Planar input = new Planar(bandType,imgWidth, imgHeight, 2); boolean signed = true; if( input.getImageType().getDataType().isInteger() ) signed = output.getDataType().isSigned(); // only provide signed numbers of both data types can handle them if( signed ) { GImageMiscOps.fillUniform(input, rand, -10, 10); } BoofTesting.checkSubImage(this, "checkConvertMultiToInterleaved", true, m, input, output); } public void checkConvertMultiToInterleaved(Method m , Planar<?> input , ImageInterleaved<?> output ) { try { double tol = 1e-4; // check it with a non-null output ImageInterleaved<?> ret = (ImageInterleaved<?>)m.invoke(null,input,output); assertTrue(ret == output); BoofTesting.assertEquals(input, ret, tol); // check it with a null output ret = (ImageInterleaved<?>)m.invoke(null,input,null); BoofTesting.assertEquals(input, ret, tol); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } private void checkMultiAverage(Method m, Class inputType, Class outputType) { if( inputType != Planar.class ) fail("Expected Planar image"); ImageGray output = GeneralizedImageOps.createSingleBand(outputType, imgWidth, imgHeight); boolean signed = true; if( GrayI.class.isAssignableFrom(outputType) ) signed = output.getDataType().isSigned(); for( int numBands = 1; numBands <= 3; numBands++ ) { Planar input = new Planar(outputType,imgWidth,imgHeight,numBands); // only provide signed numbers of both data types can handle them if( signed ) { GImageMiscOps.fillUniform(input, rand, -10, 10); } else { GImageMiscOps.fillUniform(input, rand, 0, 20); } BoofTesting.checkSubImage(this,"checkMultiAverage",true,m,input,output); } } public void checkMultiAverage(Method m, Planar<?> input, ImageGray<?> output) { try { // check it with a non-null output ImageGray<?> ret = (ImageGray<?>)m.invoke(null,input,output); assertTrue(ret == output); checkMultiAverage(input, ret); // check it with a null output ret = (ImageGray<?>)m.invoke(null,input,null); checkMultiAverage(input, ret); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } private void checkMultiAverage(Planar<?> input, ImageGray<?> found) { int numBands = input.getNumBands(); for( int y = 0; y < imgHeight; y++ ){ for( int x = 0; x < imgWidth; x++ ) { double sum = 0; for( int b = 0; b < numBands; b++ ) { sum += GeneralizedImageOps.get(input.getBand(b),x,y); } assertEquals(sum/numBands,GeneralizedImageOps.get(found, x, y),1); } } } private void checkInterleavedAverage(Method m, Class inputType, Class outputType) { if( inputType.isAssignableFrom(ImageInterleaved.class) ) fail("Expected ImageInterleaved image"); ImageGray output = GeneralizedImageOps.createSingleBand(outputType, imgWidth, imgHeight); boolean signed = true; if( GrayI.class.isAssignableFrom(outputType) ) signed = output.getDataType().isSigned(); for( int numBands = 1; numBands <= 3; numBands++ ) { ImageInterleaved input = GeneralizedImageOps.createInterleaved(inputType,imgWidth,imgHeight,numBands); // only provide signed numbers of both data types can handle them if( signed ) { GImageMiscOps.fillUniform(input, rand, -10, 10); } else { GImageMiscOps.fillUniform(input, rand, 0, 20); } BoofTesting.checkSubImage(this,"checkInterleavedAverage",true,m,input,output); } } public void checkInterleavedAverage(Method m, ImageInterleaved input, ImageGray<?> output) { try { // check it with a non-null output ImageGray<?> ret = (ImageGray<?>)m.invoke(null,input,output); assertTrue(ret == output); checkInterleavedAverage(input, ret); // check it with a null output ret = (ImageGray<?>)m.invoke(null,input,null); checkInterleavedAverage(input, ret); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } private void checkInterleavedAverage(ImageInterleaved input, ImageGray<?> found) { int numBands = input.getNumBands(); for( int y = 0; y < imgHeight; y++ ){ for( int x = 0; x < imgWidth; x++ ) { double sum = 0; for( int b = 0; b < numBands; b++ ) { sum += GeneralizedImageOps.get(input,x,y,b); } assertEquals(sum/numBands,GeneralizedImageOps.get(found, x, y),1); } } } /** * If the two images are both int or float then set a low tolerance, otherwise set the tolerance to one pixel */ private double selectTolerance(ImageGray a , ImageGray b ) { if( a.getDataType().isInteger() == b.getDataType().isInteger() ) return 1e-4; else return 1; } /** * If the two images are both int or float then set a low tolerance, otherwise set the tolerance to one pixel */ private double selectTolerance( ImageInterleaved a , ImageInterleaved b ) { if( a.getDataType().isInteger() == b.getDataType().isInteger() ) return 1e-4; else return 1; } }