/* * 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.alg.misc; import boofcv.core.image.GeneralizedImageOps; import boofcv.struct.image.GrayF32; import boofcv.struct.image.ImageBase; import boofcv.struct.image.Planar; import boofcv.testing.BoofTesting; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestGPixelMath extends BaseGClassChecksInMisc { public TestGPixelMath() { super(GPixelMath.class, PixelMath.class); } @Test public void compareToPixelMath() { performTests(22); } @Override protected Object[][] createInputParam(Method candidate, Method validation) { Class<?> param[] = validation.getParameterTypes(); String name = candidate.getName(); ImageBase inputA = createImage(param[0],null); ImageBase inputB=null,output=null; Object[][] ret = new Object[1][param.length]; if( name.equals("abs")) { output = createImage(param[1],null); ret[0][0] = inputA; ret[0][1] = output; } else if( name.equals("invert")) { output = createImage(param[1],null); ret[0][0] = inputA; ret[0][1] = output; } else if( name.equals("divide") && param.length == 3) { output = createImage(param[param.length-1],null); if( ImageBase.class.isAssignableFrom(param[1]) ) { ret[0][0] = inputA; ret[0][1] = inputB = createImage(param[1],null); ret[0][2] = output; } else { ret[0][0] = inputA; ret[0][1] = 3; ret[0][2] = output; } } else if( name.equals("divide") && param.length == 5) { output = createImage(param[param.length - 1],null); ret[0][0] = inputA; ret[0][1] = 3; ret[0][2] = -1; ret[0][3] = 5; ret[0][4] = output; } else if( name.equals("multiply") && param.length == 3) { output = createImage(param[param.length-1],null); if( ImageBase.class.isAssignableFrom(param[1]) ) { ret[0][0] = inputA; ret[0][1] = inputB = createImage(param[1],null); ret[0][2] = output; } else { ret[0][0] = inputA; ret[0][1] = 3; ret[0][2] = output; } } else if( name.equals("multiply") && param.length == 5) { output = createImage(param[param.length - 1],null); ret[0][0] = inputA; ret[0][1] = 3; ret[0][2] = -20; ret[0][3] = 12; ret[0][4] = output; } else if( name.equals("plus") && param.length == 3) { output = createImage(param[param.length - 1],null); ret[0][0] = inputA; ret[0][1] = 3; ret[0][2] = output; } else if( name.equals("plus") && param.length == 5) { output = createImage(param[param.length-1],null); ret[0][0] = inputA; ret[0][1] = 3; ret[0][2] = -10; ret[0][3] = 12; ret[0][4] = output; } else if( name.equals("minus") && param.length == 3) { output = createImage(param[param.length - 1],null); boolean first = ImageBase.class.isAssignableFrom(param[0]); if( inputA == null ) inputA = createImage(param[1],null); ret[0][0] = first ? inputA : 3; ret[0][1] = first ? 3 : inputA; ret[0][2] = output; } else if( name.equals("minus") && param.length == 5) { output = createImage(param[param.length-1],null); boolean first = ImageBase.class.isAssignableFrom(param[0]); if( inputA == null ) inputA = createImage(param[1],null); ret[0][0] = first ? inputA : 3; ret[0][1] = first ? 3 : inputA; ret[0][2] = -10; ret[0][3] = 12; ret[0][4] = output; } else if( name.equals("log") ) { inputB = createImage(param[1],null); ret[0][0] = inputA; ret[0][1] = inputB; } else if( name.equals("pow2") ) { inputB = createImage(param[1],null); ret[0][0] = inputA; ret[0][1] = inputB; } else if( name.equals("sqrt") ) { inputB = createImage(param[1],null); ret[0][0] = inputA; ret[0][1] = inputB; } else if( name.equals("add") ) { inputB = createImage(param[1],null); output = createImage(param[2],null); ret[0][0] = inputA; ret[0][1] = inputB; ret[0][2] = output; } else if( name.equals("subtract") ) { inputB = createImage(param[1],null); output = createImage(param[2],null); ret[0][0] = inputA; ret[0][1] = inputB; ret[0][2] = output; } else if( name.equals("boundImage") ) { ret[0][0] = inputA; ret[0][1] = 2; ret[0][2] = 8; } else if( name.equals("diffAbs") ) { inputB = createImage(param[1],null); output = createImage(param[2],null); ret[0][0] = inputA; ret[0][1] = inputB; ret[0][2] = output; } else if( name.equals("averageBand") ) { inputA = createImage(param[0],param[1]); output = createImage(param[1],null); ret[0][0] = inputA; ret[0][1] = output; } fillRandom(inputA); fillRandom(inputB); fillRandom(output); return ret; } @Override protected void compareResults(Object targetResult, Object[] targetParam, Object validationResult, Object[] validationParam) { int which; if( targetParam[targetParam.length-1] instanceof ImageBase ) { which = targetParam.length-1; } else { which = 0; } ImageBase t = (ImageBase)targetParam[which]; ImageBase v = (ImageBase)validationParam[which]; // if it is full of zeros something went wrong boolean foundNotZero = false; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { if( GeneralizedImageOps.get(t,j,i,0) != 0 ) { foundNotZero = true; break; } } } assertTrue(foundNotZero); BoofTesting.assertEquals(t, v, 0); } /** * Tests all functions with inputs from planar images */ @Test public void all_planar_images() { int total = 0; Method[] methods = GPixelMath.class.getMethods(); for( Method m : methods ) { if(!Modifier.isStatic(m.getModifiers())) continue; Class[] param = m.getParameterTypes(); if( param.length < 1 ) continue; // create input arguments Object[] inputs = new Object[ param.length ]; for (int i = 0; i < inputs.length; i++) { if( param[i] == ImageBase.class) { inputs[i] = new Planar(GrayF32.class,width,height,2); GImageMiscOps.fillUniform((ImageBase)inputs[i],rand,-100,100); } } // specialized inputs for individual functions String name = m.getName(); if( name.equals("divide") && param.length == 3) { if( !ImageBase.class.isAssignableFrom(param[1]) ) { inputs[1] = 3; } } else if( name.equals("divide") && param.length == 5) { inputs[1] = 3; inputs[2] = -1; inputs[3] = 5; } else if( name.equals("multiply") && param.length == 3) { if( !ImageBase.class.isAssignableFrom(param[1]) ) { inputs[1] = 3; } } else if( name.equals("multiply") && param.length == 5) { inputs[1] = 3; inputs[2] = -20; inputs[3] = 12; } else if( name.equals("plus") && param.length == 3) { inputs[1] = 3; } else if( name.equals("plus") && param.length == 5) { inputs[1] = 3; inputs[2] = -10; inputs[3] = 12; } else if( name.equals("minus") && param.length == 3) { boolean first = ImageBase.class.isAssignableFrom(param[0]); inputs[first?1:0] = 3; } else if( name.equals("minus") && param.length == 5) { boolean first = ImageBase.class.isAssignableFrom(param[0]); inputs[first?1:0] = 3; inputs[2] = -10; inputs[3] = 12; } else if( name.equals("boundImage") ) { inputs[1] = 2; inputs[2] = 8; } else if( name.equals("averageBand")) { continue; } try { // create the expected results Object[] inputsByBand = copy(inputs); invokeByBand(m,inputsByBand); // invoke this function m.invoke(null,inputs ); // compare against each other for (int i = 0; i < inputs.length; i++) { if (Planar.class == inputs[i].getClass()) { BoofTesting.assertEquals((ImageBase)inputs[i],(ImageBase)inputsByBand[i], 1e-4); } } total++; } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } assertEquals(21,total); } private Object[] copy( Object inputs[] ) { Object copy[] = new Object[inputs.length]; for (int i = 0; i < inputs.length; i++) { if( Planar.class == inputs[i].getClass() ) { copy[i] = ((Planar)inputs[i]).createSameShape(); ((Planar)copy[i]).setTo((Planar)inputs[i]); } else { copy[i] = inputs[i]; } } return copy; } private void invokeByBand( Method m , Object inputs[] ) { Object modified[] = new Object[inputs.length]; for (int i = 0; i < 2; i++) { for (int j = 0; j < inputs.length; j++) { if( Planar.class == inputs[j].getClass() ) { modified[j] = ((Planar)inputs[j]).getBand(i); } else { modified[j] = inputs[j]; } } try { m.invoke(null, modified); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } } } @Test public void divide_planar_by_gray_3() { Planar<GrayF32> numerator = new Planar<>(GrayF32.class,width,height,2); GrayF32 denominator = new GrayF32(width,height); GImageMiscOps.fillUniform(numerator,rand,-10,10); GImageMiscOps.fillUniform(denominator,rand,1,2); Planar<GrayF32> output = new Planar<>(GrayF32.class,width,height,2); GPixelMath.divide(numerator,denominator,output); GrayF32 expected = denominator.createSameShape(); for (int i = 0; i < numerator.getNumBands(); i++) { GPixelMath.divide(numerator.getBand(i),denominator, expected); BoofTesting.assertEquals(output.getBand(i),expected, 1e-4); } } @Test public void multiply_planar_by_gray_3() { Planar<GrayF32> numerator = new Planar<>(GrayF32.class,width,height,2); GrayF32 denominator = new GrayF32(width,height); GImageMiscOps.fillUniform(numerator,rand,-10,10); GImageMiscOps.fillUniform(denominator,rand,1,2); Planar<GrayF32> output = new Planar<>(GrayF32.class,width,height,2); GPixelMath.multiply(numerator,denominator,output); GrayF32 expected = denominator.createSameShape(); for (int i = 0; i < numerator.getNumBands(); i++) { GPixelMath.multiply(numerator.getBand(i),denominator, expected); BoofTesting.assertEquals(output.getBand(i),expected, 1e-4); } } }