/*
* 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.impl;
import boofcv.misc.AutoTypeImage;
import boofcv.misc.CodeGeneratorBase;
import boofcv.misc.CodeGeneratorUtil;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
/**
* @author Peter Abeles
*/
public class GenerateImplWaveletTransformNaive extends CodeGeneratorBase {
String className = "ImplWaveletTransformNaive";
PrintStream out;
AutoTypeImage imageIn;
AutoTypeImage imageOut;
String genName;
String sumType;
public GenerateImplWaveletTransformNaive() throws FileNotFoundException {
out = new PrintStream(new FileOutputStream(className + ".java"));
}
@Override
public void generate() throws FileNotFoundException {
printPreamble();
printFuncs(AutoTypeImage.F32, AutoTypeImage.F32);
printFuncs(AutoTypeImage.I, AutoTypeImage.I);
out.print("\n" +
"}\n");
}
private void printPreamble() {
out.print(CodeGeneratorUtil.copyright);
out.print("package boofcv.alg.wavelet.impl;\n" +
"\n" +
"import boofcv.alg.wavelet.UtilWavelet;\n" +
"import boofcv.struct.wavelet.WlBorderCoef;\n"+
"import boofcv.struct.wavelet.WlCoef_F32;\n" +
"import boofcv.struct.wavelet.WlCoef_I32;\n" +
"import boofcv.core.image.border.BorderIndex1D;\n" +
"import boofcv.struct.image.GrayF32;\n" +
"import boofcv.struct.image.ImageInteger;\n" +
"\n" +
"\n" +
"/**\n" +
" * <p>\n" +
" * Unoptimized and simplistic implementation of a forward and inverse wavelet transform across one\n" +
" * level. Primary used for validation testing.\n" +
" * </p>\n" +
" *\n" +
" * <p>\n" +
" * DO NOT MODIFY: This class was automatically generated by {@link GenerateImplWaveletTransformNaive}.\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();
printHorizontal();
printVertical();
printHorizontalInverse();
printVerticalInverse();
}
private void printHorizontal() {
out.print("\t/**\n" +
"\t * Performs a single level wavelet transform along the horizontal axis.\n" +
"\t *\n" +
"\t * @param coefficients Description of wavelet coefficients.\n" +
"\t * @param input Input image which is being transform. Not modified.\n" +
"\t * @param output where the output is written to. Modified\n" +
"\t */\n" +
"\tpublic static void horizontal( BorderIndex1D border , WlCoef_"+genName+" coefficients ,\n" +
"\t\t\t\t\t\t\t\t "+imageIn.getSingleBandName()+" input , "+imageIn.getSingleBandName()+" output ) {\n" +
"\n" +
"\t\tUtilWavelet.checkShape(input,output);\n" +
"\n" +
"\t\tfinal int offsetA = coefficients.offsetScaling;\n" +
"\t\tfinal int offsetB = coefficients.offsetWavelet;\n" +
"\t\tfinal "+sumType+"[] alpha = coefficients.scaling;\n" +
"\t\tfinal "+sumType+"[] beta = coefficients.wavelet;\n" +
"\n" +
"\t\tborder.setLength(input.width+input.width%2);\n" +
"\n" +
"\t\tfinal boolean isLarger = output.width > input.width;\n" +
"\n" +
"\t\tfor( int y = 0; y < input.height; y++ ) {\n" +
"\t\t\tfor( int x = 0; x < input.width; x += 2 ) {\n" +
"\n" +
"\t\t\t\t"+sumType+" scale = 0;\n" +
"\t\t\t\t"+sumType+" wavelet = 0;\n" +
"\n" +
"\t\t\t\tfor( int i = 0; i < alpha.length; i++ ) {\n" +
"\t\t\t\t\tint xx = border.getIndex(x+i+offsetA);\n" +
"\t\t\t\t\tif( isLarger && xx >= input.width )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\tscale += input.get(xx,y)*alpha[i];\n" +
"\t\t\t\t}\n" +
"\t\t\t\tfor( int i = 0; i < beta.length; i++ ) {\n" +
"\t\t\t\t\tint xx = border.getIndex(x+i+offsetB);\n" +
"\t\t\t\t\tif( isLarger && xx >= input.width )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\twavelet += input.get(xx,y)*beta[i];\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\tint outX = x/2;\n" +
"\n");
if( imageIn.isInteger() ) {
out.print("\t\t\t\tscale = 2*scale/coefficients.denominatorScaling;\n" +
"\t\t\t\twavelet = 2*wavelet/coefficients.denominatorWavelet;\n" +
"\n");
}
out.print("\t\t\t\toutput.set(outX,y,scale);\n" +
"\t\t\t\toutput.set(output.width/2 + outX , y , wavelet );\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void printVertical() {
out.print("\t/**\n" +
"\t * Performs a single level wavelet transform along the vertical axis.\n" +
"\t *\n" +
"\t * @param coefficients Description of wavelet coefficients.\n" +
"\t * @param input Input image which is being transform. Not modified.\n" +
"\t * @param output where the output is written to. Modified\n" +
"\t */\n" +
"\tpublic static void vertical( BorderIndex1D border , WlCoef_"+genName+" coefficients ,\n" +
"\t\t\t\t\t\t\t\t "+imageIn.getSingleBandName()+" input , "+imageIn.getSingleBandName()+" output ) {\n" +
"\n" +
"\t\tUtilWavelet.checkShape(input,output);\n" +
"\n" +
"\t\tfinal int offsetA = coefficients.offsetScaling;\n" +
"\t\tfinal int offsetB = coefficients.offsetWavelet;\n" +
"\t\tfinal "+sumType+"[] alpha = coefficients.scaling;\n" +
"\t\tfinal "+sumType+"[] beta = coefficients.wavelet;\n" +
"\n" +
"\t\tborder.setLength(input.height+input.height%2);\n" +
"\n" +
"\t\tboolean isLarger = output.height > input.height;\n" +
"\n" +
"\t\tfor( int x = 0; x < input.width; x++) {\n" +
"\t\t\tfor( int y = 0; y < input.height; y += 2 ) {\n" +
"\t\t\t\t"+sumType+" scale = 0;\n" +
"\t\t\t\t"+sumType+" wavelet = 0;\n" +
"\n" +
"\t\t\t\tfor( int i = 0; i < alpha.length; i++ ) {\n" +
"\t\t\t\t\tint yy = border.getIndex(y+i+offsetA);\n" +
"\t\t\t\t\tif( isLarger && yy >= input.height )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\tscale += input.get(x,yy)*alpha[i];\n" +
"\t\t\t\t}\n" +
"\t\t\t\tfor( int i = 0; i < beta.length; i++ ) {\n" +
"\t\t\t\t\tint yy = border.getIndex(y+i+offsetB);\n" +
"\t\t\t\t\tif( isLarger && yy >= input.height )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\twavelet += input.get(x,yy)*beta[i];\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\tint outY = y/2;\n" +
"\n");
if( imageIn.isInteger() ) {
out.print("\t\t\t\tscale = 2*scale/coefficients.denominatorScaling;\n" +
"\t\t\t\twavelet = 2*wavelet/coefficients.denominatorWavelet;\n" +
"\n");
}
out.print("\t\t\t\toutput.set(x , outY,scale);\n" +
"\t\t\t\toutput.set(x , output.height/2 + outY , wavelet );\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void printHorizontalInverse() {
out.print("\t/**\n" +
"\t * Performs a single level inverse wavelet transform along the horizontal axis.\n" +
"\t *\n" +
"\t * @param inverseCoef Description of wavelet coefficients.\n" +
"\t * @param input Transformed image. Not modified.\n" +
"\t * @param output Reconstruction of original image. Modified\n" +
"\t */\n" +
"\tpublic static void horizontalInverse( BorderIndex1D border , WlBorderCoef<WlCoef_"+genName+"> inverseCoef , "+imageIn.getSingleBandName()+" input , "+imageIn.getSingleBandName()+" output ) {\n" +
"\n" +
"\t\tUtilWavelet.checkShape(output,input);\n" +
"\n" +
"\t\t"+sumType+" []trends = new "+sumType+"[ output.width ];\n" +
"\t\t"+sumType+" []details = new "+sumType+"[ output.width ];\n" +
"\n" +
"\t\tboolean isLarger = input.width >= output.width;\n" +
"\t\tint paddedWidth = output.width + output.width%2;\n" +
"\n" +
"\t\tfinal int lowerBorder = inverseCoef.getLowerLength()*2;\n" +
"\t\tfinal int upperBorder = output.width - inverseCoef.getUpperLength()*2;\n" +
"\n" +
"\t\tborder.setLength(output.width+output.width%2);\n" +
"\n");
if( imageIn.isInteger() ) {
out.print("\t\tWlCoef_"+genName+" coefficients = inverseCoef.getInnerCoefficients();\n");
out.print("\t\tfinal int e = coefficients.denominatorScaling*2;\n" +
"\t\tfinal int f = coefficients.denominatorWavelet*2;\n" +
"\t\tfinal int ef = e*f;\n" +
"\t\tfinal int ef2 = ef/2;\n");
} else {
out.print("\t\tWlCoef_"+genName+" coefficients;\n");
}
out.print("\n");
out.print("\t\tfor( int y = 0; y < output.height; y++ ) {\n" +
"\n" +
"\t\t\tfor( int i = 0; i < details.length; i++ ) {\n" +
"\t\t\t\tdetails[i] = 0;\n" +
"\t\t\t\ttrends[i] = 0;\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\tfor( int x = 0; x < output.width; x += 2 ) {\n" +
"\t\t\t\t"+sumType+" a = input.get(x/2,y);\n" +
"\t\t\t\t"+sumType+" d = input.get(input.width/2+x/2,y);\n" +
"\n" +
"\t\t\t\tif( x < lowerBorder ) {\n" +
"\t\t\t\t\tcoefficients = inverseCoef.getBorderCoefficients(x);\n" +
"\t\t\t\t} else if( x >= upperBorder ) {\n" +
"\t\t\t\t\tcoefficients = inverseCoef.getBorderCoefficients(x-paddedWidth);\n" +
"\t\t\t\t} else {\n" +
"\t\t\t\t\tcoefficients = inverseCoef.getInnerCoefficients();\n" +
"\t\t\t\t}\n"+
"\n"+
"\t\t\t\tfinal int offsetA = coefficients.offsetScaling;\n" +
"\t\t\t\tfinal int offsetB = coefficients.offsetWavelet;\n" +
"\t\t\t\tfinal "+sumType+"[] alpha = coefficients.scaling;\n" +
"\t\t\t\tfinal "+sumType+"[] beta = coefficients.wavelet;\n" +
"\n" +
"\t\t\t\t// add the trend\n" +
"\t\t\t\tfor( int i = 0; i < alpha.length; i++ ) {\n" +
"\t\t\t\t\t// if an odd image don't update the outer edge\n" +
"\t\t\t\t\tint xx = border.getIndex(x+offsetA+i);\n" +
"\t\t\t\t\tif( isLarger && xx >= output.width )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\ttrends[xx] += a*alpha[i];\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\t// add the detail signal\n" +
"\t\t\t\tfor( int i = 0; i < beta.length; i++ ) {\n" +
"\t\t\t\t\tint xx = border.getIndex(x+offsetB+i);\n" +
"\t\t\t\t\tif( isLarger && xx >= output.width )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\tdetails[xx] += d*beta[i];\n" +
"\t\t\t\t}\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\tfor( int x = 0; x < output.width; x++ ) {\n");
if( imageIn.isInteger() ) {
out.print("\t\t\t\toutput.set(x,y, UtilWavelet.round(trends[x]*f + details[x]*e ,ef2,ef));\n");
} else {
out.print("\t\t\t\toutput.set(x,y, trends[x] + details[x]);\n");
}
out.print("\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
private void printVerticalInverse() {
out.print("\t/**\n" +
"\t * Performs a single level inverse wavelet transform along the vertical axis.\n" +
"\t *\n" +
"\t * @param inverseCoef Description of wavelet coefficients.\n" +
"\t * @param input Transformed image. Not modified.\n" +
"\t * @param output Reconstruction of original image. Modified\n" +
"\t */\n" +
"\tpublic static void verticalInverse( BorderIndex1D border , WlBorderCoef<WlCoef_"+genName+"> inverseCoef , "+imageIn.getSingleBandName()+" input , "+imageIn.getSingleBandName()+" output ) {\n" +
"\n" +
"\t\tUtilWavelet.checkShape(output,input);\n" +
"\n" +
"\t\t"+sumType+" []trends = new "+sumType+"[ output.height ];\n" +
"\t\t"+sumType+" []details = new "+sumType+"[ output.height ];\n" +
"\n" +
"\t\tboolean isLarger = input.height > output.height;\n" +
"\t\tint paddedHeight = output.height + output.height%2;\n" +
"\n" +
"\t\tfinal int lowerBorder = inverseCoef.getLowerLength()*2;\n" +
"\t\tfinal int upperBorder = output.height - inverseCoef.getUpperLength()*2;\n" +
"\n" +
"\t\tborder.setLength(output.height+output.height%2);\n" +
"\n");
if( imageIn.isInteger() ) {
out.print("\t\tWlCoef_"+genName+" coefficients = inverseCoef.getInnerCoefficients();\n");
out.print("\t\tfinal int e = coefficients.denominatorScaling*2;\n" +
"\t\tfinal int f = coefficients.denominatorWavelet*2;\n" +
"\t\tfinal int ef = e*f;\n" +
"\t\tfinal int ef2 = ef/2;\n");
} else {
out.print("\t\tWlCoef_"+genName+" coefficients;\n");
}
out.print("\n");
out.print("\t\tfor( int x = 0; x < output.width; x++) {\n" +
"\n" +
"\t\t\tfor( int i = 0; i < details.length; i++ ) {\n" +
"\t\t\t\tdetails[i] = 0;\n" +
"\t\t\t\ttrends[i] = 0;\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\tfor( int y = 0; y < output.height; y += 2 ) {\n" +
"\t\t\t\t"+sumType+" a = input.get(x,y/2);\n" +
"\t\t\t\t"+sumType+" d = input.get(x,y/2+input.height/2);\n" +
"\n" +
"\t\t\t\tif( y < lowerBorder ) {\n" +
"\t\t\t\t\tcoefficients = inverseCoef.getBorderCoefficients(y);\n" +
"\t\t\t\t} else if( y >= upperBorder ) {\n" +
"\t\t\t\t\tcoefficients = inverseCoef.getBorderCoefficients(y-paddedHeight);\n" +
"\t\t\t\t} else {\n" +
"\t\t\t\t\tcoefficients = inverseCoef.getInnerCoefficients();\n" +
"\t\t\t\t}\n"+
"\n" +
"\t\t\t\tfinal int offsetA = coefficients.offsetScaling;\n" +
"\t\t\t\tfinal int offsetB = coefficients.offsetWavelet;\n" +
"\t\t\t\tfinal "+sumType+"[] alpha = coefficients.scaling;\n" +
"\t\t\t\tfinal "+sumType+"[] beta = coefficients.wavelet;\n" +
"\n" +
"\t\t\t\t// add the 'average' signal\n" +
"\t\t\t\tfor( int i = 0; i < alpha.length; i++ ) {\n" +
"\t\t\t\t\t// if an odd image don't update the outer edge\n" +
"\t\t\t\t\tint yy = border.getIndex(y+offsetA+i);\n" +
"\t\t\t\t\tif( isLarger && yy >= output.height )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\ttrends[yy] += a*alpha[i];\n" +
"\t\t\t\t}\n" +
"\n" +
"\t\t\t\t// add the detail signal\n" +
"\t\t\t\tfor( int i = 0; i < beta.length; i++ ) {\n" +
"\t\t\t\t\tint yy = border.getIndex(y+offsetB+i);\n" +
"\t\t\t\t\tif( isLarger && yy >= output.height )\n" +
"\t\t\t\t\t\tcontinue;\n" +
"\t\t\t\t\tdetails[yy] += d*beta[i];\n" +
"\t\t\t\t}\n" +
"\t\t\t}\n" +
"\n" +
"\t\t\tfor( int y = 0; y < output.height; y++ ) {\n");
if( imageIn.isInteger() ) {
out.print("\t\t\t\toutput.set(x,y, UtilWavelet.round(trends[y]*f + details[y]*e,ef2,ef));\n");
} else {
out.print("\t\t\t\toutput.set(x,y, trends[y] + details[y]);\n");
}
out.print("\t\t\t}\n" +
"\t\t}\n" +
"\t}\n\n");
}
public static void main( String args[] ) throws FileNotFoundException {
GenerateImplWaveletTransformNaive app = new GenerateImplWaveletTransformNaive();
app.generate();
}
}