/* * 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.transform.wavelet; import boofcv.alg.misc.ImageMiscOps; import boofcv.alg.transform.wavelet.impl.ImplWaveletTransformNaive; import boofcv.core.image.border.BorderIndex1D; import boofcv.struct.image.GrayF32; import boofcv.struct.image.GrayS32; import boofcv.struct.wavelet.WaveletDescription; import boofcv.struct.wavelet.WlCoef_F32; import boofcv.struct.wavelet.WlCoef_I32; import boofcv.testing.BoofTesting; import org.ejml.data.DenseMatrix64F; import org.ejml.ops.CommonOps; import org.ejml.ops.MatrixFeatures; import java.util.Random; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * Common testing functions for wavelet factories * * @author Peter Abeles */ public class CommonFactoryWavelet { Random rand = new Random(234); int width = 20; int height = 30; /** * See if the provided wavelets can be used to transform the image and change it back without error * * @param waveletDesc The wavelet being tested */ public void checkEncodeDecode_F32( WaveletDescription<WlCoef_F32> waveletDesc ) { // test both even and odd images for( int makeOdd = 0; makeOdd <= 1; makeOdd++ ) { GrayF32 orig = new GrayF32(width-makeOdd,height-makeOdd); GrayF32 tran = new GrayF32(width,height); GrayF32 rev = new GrayF32(width-makeOdd,height-makeOdd); ImageMiscOps.fillUniform(orig,rand,0,50); BorderIndex1D border = waveletDesc.getBorder(); // First test again naive transform operations, which are the standard implementation ImplWaveletTransformNaive.horizontal(border,waveletDesc.forward,orig,tran); ImplWaveletTransformNaive.horizontalInverse(border,waveletDesc.inverse,tran,rev); BoofTesting.assertEquals(orig,rev,1e-4f); ImplWaveletTransformNaive.vertical(border,waveletDesc.forward,orig,tran); ImplWaveletTransformNaive.verticalInverse(border,waveletDesc.inverse,tran,rev); BoofTesting.assertEquals(orig,rev,1e-4f); // quick sanity check to make sure that WaveletTransformOps // also correctly does a transform with these wavelets // more of a robustness test of WaveletTransformOps than anything else WaveletTransformOps.transform1(waveletDesc,orig,tran,null); WaveletTransformOps.inverse1(waveletDesc,tran,rev,null,0,255); // BoofTesting.printDiff(orig,rev); BoofTesting.assertEquals(orig,rev,1e-4f); } } /** * See if the provided wavelets can be used to transform the image and change it back without error * * @param waveletDesc The wavelet being tested */ public void checkEncodeDecode_I32(WaveletDescription<WlCoef_I32> waveletDesc ) { // test both even and odd images for( int makeOdd = 0; makeOdd <= 1; makeOdd++ ) { GrayS32 orig = new GrayS32(width-makeOdd,height-makeOdd); GrayS32 tran = new GrayS32(width,height); GrayS32 rev = new GrayS32(width-makeOdd,height-makeOdd); ImageMiscOps.fillUniform(orig,rand,-50,50); BorderIndex1D border = waveletDesc.getBorder(); ImplWaveletTransformNaive.horizontal(border,waveletDesc.forward,orig,tran); ImplWaveletTransformNaive.horizontalInverse(border,waveletDesc.inverse,tran,rev); BoofTesting.assertEquals(orig,rev,0); // quick sanity check to make sure that WaveletTransformOps // also correctly does a transform with these wavelets // more of a robustness test of WaveletTransformOps than anything else WaveletTransformOps.transform1(waveletDesc,orig,tran,null); WaveletTransformOps.inverse1(waveletDesc,tran,rev,null,Integer.MIN_VALUE,Integer.MAX_VALUE); BoofTesting.assertEquals(orig,rev,0); } } /** * Computes the dot product of two wavelets separated by different offsets. If * the offset is zero and they have an orthogonal/biorothogonal relationship then * the dot product should be one. Otherwise it will be zero. */ public static void checkBiorthogonal_F32( WaveletDescription<WlCoef_F32> desc ) { WlCoef_F32 forward = desc.getForward(); BorderIndex1D border = desc.getBorder(); int N = Math.max(forward.getScalingLength(),forward.getWaveletLength()); N += N%2; N *= 2; border.setLength(N); DenseMatrix64F A = new DenseMatrix64F(N,N); DenseMatrix64F B = new DenseMatrix64F(N,N); // using the provided wrapping rule to construct a matrix with the coefficients for( int i = 0; i < N; i += 2 ) { for( int j = 0; j < forward.scaling.length; j++ ) { int index = border.getIndex(i+j+forward.offsetScaling); A.add(i,index,forward.scaling[j]); } for( int j = 0; j < forward.wavelet.length; j++ ) { int index = border.getIndex(i+j+forward.offsetWavelet); A.add(i+1,index,forward.wavelet[j]); } } // the inverse coefficients should create a matrix that is the inverse of the forward coefficients final int lowerBorder = desc.getInverse().getLowerLength()*2; final int upperBorder = N-desc.getInverse().getUpperLength()*2; for( int i = 0; i < N; i += 2 ) { WlCoef_F32 inverse; if( i < lowerBorder ) { inverse = desc.getInverse().getBorderCoefficients(i); } else if( i >= upperBorder ) { inverse = desc.getInverse().getBorderCoefficients(i-N); } else { inverse = desc.getInverse().getInnerCoefficients(); } for( int j = 0; j < inverse.scaling.length; j++ ) { int index = border.getIndex(i+j+inverse.offsetScaling); B.add(index,i,inverse.scaling[j]); } for( int j = 0; j < inverse.wavelet.length; j++ ) { int index = border.getIndex(i+j+inverse.offsetWavelet); B.add(index,i+1,inverse.wavelet[j]); } } DenseMatrix64F C = new DenseMatrix64F(N,N); CommonOps.mult(A,B,C); // A.print(); // B.print(); // C.print(); assertTrue(MatrixFeatures.isIdentity(C,1e-4)); } public static void checkBiorthogonal_I32( WaveletDescription<WlCoef_I32> desc ) { WlCoef_I32 forward = desc.getForward(); BorderIndex1D border = desc.getBorder(); int N = Math.max(forward.getScalingLength(),forward.getWaveletLength()); N += N%2; N *= 2; border.setLength(N); DenseMatrix64F A = new DenseMatrix64F(N,N); DenseMatrix64F B = new DenseMatrix64F(N,N); // using the wrapping rule construct a matrix with the coefficients for( int i = 0; i < N; i += 2 ) { for( int j = 0; j < forward.scaling.length; j++ ) { int index = border.getIndex(i+j+forward.offsetScaling); A.add(i,index,(double)forward.scaling[j]/forward.denominatorScaling); } for( int j = 0; j < forward.wavelet.length; j++ ) { int index = border.getIndex(i+j+forward.offsetWavelet); A.add(i+1,index,(double)forward.wavelet[j]/forward.denominatorWavelet); } } // the inverse coefficients should be a matrix which is the inverse of the forward coefficients final int lowerBorder = desc.getInverse().getLowerLength()*2; final int upperBorder = N-desc.getInverse().getUpperLength()*2; for( int i = 0; i < N; i += 2 ) { WlCoef_I32 inverse; if( i < lowerBorder ) { inverse = desc.getInverse().getBorderCoefficients(i); } else if( i >= upperBorder ) { inverse = desc.getInverse().getBorderCoefficients(i-N); } else { inverse = desc.getInverse().getInnerCoefficients(); } for( int j = 0; j < inverse.scaling.length; j++ ) { int index = border.getIndex(i+j+inverse.offsetScaling); B.add(index,i,(double)inverse.scaling[j]/inverse.denominatorScaling); } for( int j = 0; j < inverse.wavelet.length; j++ ) { int index = border.getIndex(i+j+inverse.offsetWavelet); B.add(index,i+1,(double)inverse.wavelet[j]/inverse.denominatorWavelet); } } DenseMatrix64F C = new DenseMatrix64F(N,N); CommonOps.mult(A,B,C); assertTrue(MatrixFeatures.isIdentity(C,1e-4)); } public static void checkPolySumToZero(float support[], int polyOrder, int offset ) { for( int o = 1; o <= polyOrder; o++ ) { double total = 0; for( int j = 0; j < support.length; j++ ) { double coef = Math.pow(j+offset,o); total += coef*support[j]; } assertEquals("Failed poly test at order "+o,0,total,1e-4); } } public static void checkPolySumToZero(int support[], int polyOrder, int offset ) { for( int o = 1; o <= polyOrder; o++ ) { double total = 0; for( int j = 0; j < support.length; j++ ) { double coef = Math.pow(j+offset,o); total += coef*support[j]; } assertEquals("Failed poly test at order "+o,0,total,1e-4); } } }