/* * 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.misc.AutoTypeImage; import boofcv.misc.CodeGeneratorBase; import java.io.FileNotFoundException; /** * @author Peter Abeles */ public class GenerateWaveletTransformOps extends CodeGeneratorBase { String className = "WaveletTransformOps"; AutoTypeImage imageIn; AutoTypeImage imageOut; String genName; String sumType; String bitWise; String outputCast; String MIN_VALUE,MAX_VALUE; public GenerateWaveletTransformOps() throws FileNotFoundException { setOutputFile(className); } @Override public void generate() throws FileNotFoundException { printPreamble(); printFuncs(AutoTypeImage.F32, AutoTypeImage.F32); printFuncs(AutoTypeImage.S32, AutoTypeImage.S32); out.print("\n" + "}\n"); } private void printPreamble() { out.print("import boofcv.alg.InputSanityCheck;\n" + "import boofcv.alg.misc.PixelMath;\n" + "import boofcv.alg.transform.wavelet.impl.ImplWaveletTransformBorder;\n" + "import boofcv.alg.transform.wavelet.impl.ImplWaveletTransformInner;\n" + "import boofcv.alg.transform.wavelet.impl.ImplWaveletTransformNaive;\n" + "import boofcv.struct.image.GrayF32;\n" + "import boofcv.struct.image.GrayS32;\n" + "import boofcv.struct.wavelet.WaveletDescription;\n" + "import boofcv.struct.wavelet.WlCoef_F32;\n" + "import boofcv.struct.wavelet.WlCoef_I32;\n" + "\n" + "/**\n" + " * <p>\n" + " * Functional interface for applying general purpose wavelet and inverse wavelet transforms.\n" + " * </p>\n" + " *\n" + " * <p>\n" + " * A single level wavelet transform breaks the image up into four regions:\n" + " * <table border=\"1\">\n" + " * <tr><td>a</td><td>h</td></tr>\n" + " * <tr><td>v</td><td>d</td></tr>\n" + " * </table>\n" + " * Each region has M/2,N/2 rows and columns. Region 'a' is the scaling image, 'h' and 'v' are\n" + " * a combination of scaling and wavelet, and 'd' is a combination of horizontal and vertical wavelets.\n" + " * When a multiple level transform is performed then the input to the next level is the 'a' from the previous\n" + " * level.\n" + " * </p>\n" + " *\n" + " * <p>\n" + " * DO NOT MODIFY: This class was automatically generated by {@link "+getClass().getName()+"}\n" + " * </p>\n" + " *\n" + " * @author Peter Abeles\n" + " */\n" + "public class "+className+" {\n\n"); } private void printFuncs( AutoTypeImage imageIn , AutoTypeImage imageOut ) { this.imageIn = imageIn; this.imageOut = imageOut; if( imageIn.isInteger() ) genName = "I32"; else genName = "F"+imageIn.getNumBits(); sumType = imageIn.getSumType(); bitWise = imageIn.getBitWise(); if( sumType.compareTo(imageOut.getDataType()) == 0 ) { outputCast = ""; } else { outputCast = "("+imageOut.getDataType()+")"; } if( imageOut.isInteger() ) { MIN_VALUE = "Integer.MIN_VALUE"; MAX_VALUE = "Integer.MAX_VALUE"; } else { MIN_VALUE = "-Float.MAX_VALUE"; MAX_VALUE = "Float.MAX_VALUE"; } printTransform1(); printTransformN(); printInvert1(); printInvertN(); } private void printTransform1() { out.print("\t/**\n" + "\t * <p>\n" + "\t * Performs a single level wavelet transform.\n" + "\t * </p>\n" + "\t *\n" + "\t * @param desc Description of the wavelet.\n" + "\t * @param input Input image. Not modified.\n" + "\t * @param output Where the wavelet transform is written to. Modified.\n" + "\t * @param storage Optional storage image. Should be the same size as output image. If null then\n" + "\t * an image is declared internally.\n" + "\t */\n" + "\tpublic static void transform1( WaveletDescription<WlCoef_"+genName+"> desc ,\n" + "\t\t\t\t\t\t\t\t "+imageIn.getSingleBandName()+" input , "+imageOut.getSingleBandName()+" output ,\n" + "\t\t\t\t\t\t\t\t "+imageOut.getSingleBandName()+" storage )\n" + "\t{\n" + "\t\tUtilWavelet.checkShape(input,output);\n" + "\n" + "\t\tWlCoef_"+genName+" coef = desc.getForward();\n" + "\n" + "\t\tif( output.width < coef.scaling.length || output.width < coef.wavelet.length )\n" + "\t\t\tthrow new IllegalArgumentException(\"Wavelet is too large for provided image.\");\n" + "\t\tif( output.height < coef.scaling.length || output.height < coef.wavelet.length )\n" + "\t\t\tthrow new IllegalArgumentException(\"Wavelet is too large for provided image.\");\n" + "\t\tstorage = InputSanityCheck.checkDeclare(output, storage);\n" + "\n" + "\t\t// the faster routines can only be run on images which are not too small\n" + "\t\tint minSize = Math.max(coef.getScalingLength(),coef.getWaveletLength())*3;\n" + "\n" + "\t\tif( input.getWidth() <= minSize || input.getHeight() <= minSize ) {\n" + "\t\t\tImplWaveletTransformNaive.horizontal(desc.getBorder(),coef,input,storage);\n" + "\t\t\tImplWaveletTransformNaive.vertical(desc.getBorder(),coef,storage,output);\n" + "\t\t} else {\n" + "\t\t\tImplWaveletTransformInner.horizontal(coef,input,storage);\n" + "\t\t\tImplWaveletTransformBorder.horizontal(desc.getBorder(),coef,input,storage);\n" + "\t\t\tImplWaveletTransformInner.vertical(coef,storage,output);\n" + "\t\t\tImplWaveletTransformBorder.vertical(desc.getBorder(),coef,storage,output);\n" + "\t\t}\n" + "\t}\n\n"); } private void printTransformN() { out.print("\t/**\n" + "\t * <p>\n" + "\t * Performs a level N wavelet transform using the fast wavelet transform (FWT).\n" + "\t * </p>\n" + "\t *\n" + "\t * <p>To save memory the input image is used to store intermediate results and is modified.</p>\n" + "\t *\n" + "\t * @param desc Description of the wavelet.\n" + "\t * @param input Input image and is used as internal workspace. Modified.\n" + "\t * @param output Where the multilevel wavelet transform is written to. Modified.\n" + "\t * @param storage Optional storage image. Should be the same size as output image. If null then\n" + "\t * an image is declared internally.\n" + "\t * @param numLevels Number of levels which should be computed in the transform.\n" + "\t */\n" + "\tpublic static void transformN( WaveletDescription<WlCoef_"+genName+"> desc ,\n" + "\t\t\t\t\t\t\t\t "+imageIn.getSingleBandName()+" input , "+imageOut.getSingleBandName()+" output ,\n" + "\t\t\t\t\t\t\t\t "+imageOut.getSingleBandName()+" storage ,\n" + "\t\t\t\t\t\t\t\t int numLevels )\n" + "\t{\n" + "\t\tif( numLevels == 1 ) {\n" + "\t\t\ttransform1(desc,input,output, storage);\n" + "\t\t\treturn;\n" + "\t\t}\n" + "\n" + "\t\tUtilWavelet.checkShape(desc.getForward(),input,output,numLevels);\n" + "\t\tstorage = InputSanityCheck.checkDeclare(output, storage);\n" + "\t\t// modify the shape of a temporary image not the original\n" + "\t\tstorage = storage.subimage(0,0,output.width,output.height);\n" + "\t\tstorage.subImage = false;\n" + "\n" + "\t\ttransform1(desc,input,output, storage);\n" + "\n" + "\t\tfor( int i = 2; i <= numLevels; i++ ) {\n" + "\t\t\tint width = output.width/2;\n" + "\t\t\tint height = output.height/2;\n" + "\t\t\twidth += width%2;\n" + "\t\t\theight += height%2;\n" + "\n" + "\t\t\tinput = input.subimage(0,0,width,height);\n" + "\t\t\toutput = output.subimage(0,0,width,height);\n" + "\t\t\tinput.setTo(output);\n" + "\n" + "\t\t\t// transform the scaling image and save the results in the output image\n" + "\t\t\tstorage.reshape(width,height);\n" + "\t\t\ttransform1(desc,input,output,storage);\n" + "\t\t}\n" + "\t}\n\n"); } private void printInvert1() { String primitive = imageOut.getDataType(); out.print("\t/**\n" + "\t * <p>\n" + "\t * Performs a single level inverse wavelet transform. Do not pass in a whole image which has been\n" + "\t * transformed by a multilevel transform. Just the relevant sub-image.\n" + "\t * </p>\n" + "\t *\n" + "\t * @param desc Description of the inverse wavelet.\n" + "\t * @param input Input wavelet transform. Not modified.\n" + "\t * @param output Reconstruction of original image. Modified.\n" + "\t * @param storage Optional storage image. Should be the same size as the input image. If null then\n" + "\t * an image is declared internally.\n" + "\t * @param minValue Minimum allowed pixel value\n" + "\t * @param maxValue Maximum allowed pixel value\n" + "\t */\n" + "\tpublic static void inverse1( WaveletDescription<WlCoef_"+genName+"> desc ,\n" + "\t\t\t\t\t\t\t\t "+imageOut.getSingleBandName()+" input , "+imageIn.getSingleBandName()+" output ,\n" + "\t\t\t\t\t\t\t\t "+imageIn.getSingleBandName()+" storage , "+primitive+" minValue , "+primitive+" maxValue )\n" + "\t{\n" + "\t\tUtilWavelet.checkShape(output,input);\n" + "\t\tWlCoef_"+genName+" coef = desc.getForward();\n" + "\t\tif( output.width < coef.scaling.length || output.width < coef.wavelet.length )\n" + "\t\t\tthrow new IllegalArgumentException(\"Wavelet is too large for provided image.\");\n" + "\t\tif( output.height < coef.scaling.length || output.height < coef.wavelet.length )\n" + "\t\t\tthrow new IllegalArgumentException(\"Wavelet is too large for provided image.\");\n" + "\t\tstorage = InputSanityCheck.checkDeclare(input, storage);\n" + "\n" + "\t\t// the faster routines can only be run on images which are not too small\n" + "\t\tint minSize = Math.max(coef.getScalingLength(),coef.getWaveletLength())*3;\n" + "\n" + "\t\tif( output.getWidth() <= minSize || output.getHeight() <= minSize ) {\n" + "\t\t\tImplWaveletTransformNaive.verticalInverse(desc.getBorder(),desc.getInverse(),input,storage);\n" + "\t\t\tImplWaveletTransformNaive.horizontalInverse(desc.getBorder(),desc.getInverse(),storage,output);\n" + "\t\t} else {\n" + "\t\t\tImplWaveletTransformInner.verticalInverse(desc.getInverse().getInnerCoefficients(),input,storage);\n" + "\t\t\tImplWaveletTransformBorder.verticalInverse(desc.getBorder(),desc.getInverse(),input,storage);\n" + "\t\t\tImplWaveletTransformInner.horizontalInverse(desc.getInverse().getInnerCoefficients(),storage,output);\n" + "\t\t\tImplWaveletTransformBorder.horizontalInverse(desc.getBorder(),desc.getInverse(),storage,output);\n" + "\t\t}\n" + "\n" + "\t\tif( minValue != "+MIN_VALUE+" && maxValue != "+MAX_VALUE+" )\n" + "\t\t\tPixelMath.boundImage(output,minValue,maxValue);\n" + "\t}\n\n"); } private void printInvertN() { String primitive = imageOut.getDataType(); out.print("\t/**\n" + "\t * <p>Performs a level N inverse fast wavelet transform (FWT).</p>\n" + "\t *\n" + "\t * <p>To save memory the input image is used to store intermediate results and is modified.</p>\n" + "\t *\n" + "\t * @param desc Description of the inverse wavelet.\n" + "\t * @param input Input wavelet transform and is used as internal workspace. Modified.\n" + "\t * @param output Reconstruction of original image. Modified.\n" + "\t * @param storage Optional storage image. Should be the same size as the input image. If null then\n" + "\t * an image is declared internally.\n" + "\t * @param numLevels Number of levels in the transform.\n" + "\t * @param minValue Minimum allowed pixel value\n" + "\t * @param maxValue Maximum allowed pixel value\n" + "\t */\n" + "\tpublic static void inverseN( WaveletDescription<WlCoef_"+genName+"> desc ,\n" + "\t\t\t\t\t\t\t\t "+imageOut.getSingleBandName()+" input , "+imageIn.getSingleBandName()+" output ,\n" + "\t\t\t\t\t\t\t\t "+imageOut.getSingleBandName()+" storage,\n" + "\t\t\t\t\t\t\t\t int numLevels ,\n" + "\t\t\t\t\t\t\t\t "+primitive+" minValue , "+primitive+" maxValue)\n" + "\t{\n" + "\t\tif( numLevels == 1 ) {\n" + "\t\t\tinverse1(desc,input,output, storage,minValue,maxValue);\n" + "\t\t\tPixelMath.boundImage(output,minValue,maxValue);\n" + "\t\t\treturn;\n" + "\t\t}\n" + "\n" + "\t\tUtilWavelet.checkShape(desc.getForward(),output,input,numLevels);\n" + "\t\tstorage = InputSanityCheck.checkDeclare(input, storage);\n" + "\t\t// modify the shape of a temporary image not the original\n" + "\t\tstorage = storage.subimage(0,0,input.width,input.height);\n" + "\t\tstorage.subImage = false;\n" + "\n" + "\t\tint width,height;\n" + "\n" + "\t\tint scale = UtilWavelet.computeScale(numLevels);\n" + "\t\twidth = input.width/scale;\n" + "\t\theight = input.height/scale;\n" + "\t\twidth += width%2;\n" + "\t\theight += height%2;\n" + "\n" + "\t\t"+imageOut.getSingleBandName()+" levelIn = input.subimage(0,0,width,height);\n" + "\t\t"+imageIn.getSingleBandName()+" levelOut = output.subimage(0,0,width,height);\n" + "\t\tstorage.reshape(width,height);\n" + "\t\tinverse1(desc,levelIn,levelOut, storage,"+MIN_VALUE+","+MAX_VALUE+");\n" + "\n" + "\t\tfor( int i = numLevels-1; i >= 1; i-- ) {\n" + "\t\t\t// copy the decoded segment into the input\n" + "\t\t\tlevelIn.setTo(levelOut);\n" + "\t\t\tif( i > 1 ) {\n" + "\t\t\t\tscale /= 2;\n" + "\t\t\t\twidth = input.width/scale;\n" + "\t\t\t\theight = input.height/scale;\n" + "\t\t\t\twidth += width%2;\n" + "\t\t\t\theight += height%2;\n" + "\n" + "\t\t\t\tstorage.reshape(width,height);\n" + "\t\t\t\tlevelIn = input.subimage(0,0,width,height);\n" + "\t\t\t\tlevelOut = output.subimage(0,0,width,height);\n" + "\t\t\t} else {\n" + "\t\t\t\tlevelIn = input;\n" + "\t\t\t\tlevelOut = output;\n" + "\t\t\t}\n" + "\n" + "\t\t\tstorage.reshape(levelIn.width,levelIn.height);\n" + "\t\t\tinverse1(desc,levelIn,levelOut, storage,"+MIN_VALUE+","+MAX_VALUE+");\n" + "\t\t}\n" + "\n" + "\t\tif( minValue != "+MIN_VALUE+" && maxValue != "+MAX_VALUE+" )\n" + "\t\t\tPixelMath.boundImage(output, minValue, maxValue);\n" + "\t}\n\n"); } public static void main( String args[] ) throws FileNotFoundException { GenerateWaveletTransformOps app = new GenerateWaveletTransformOps(); app.generate(); } }