boofcv.alg.transform.wavelet.WaveletTransformOps Maven / Gradle / Ivy
Show all versions of ip Show documentation
/*
* 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.InputSanityCheck;
import boofcv.alg.misc.PixelMath;
import boofcv.alg.transform.wavelet.impl.ImplWaveletTransformBorder;
import boofcv.alg.transform.wavelet.impl.ImplWaveletTransformInner;
import boofcv.alg.transform.wavelet.impl.ImplWaveletTransformNaive;
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;
/**
*
* Functional interface for applying general purpose wavelet and inverse wavelet transforms.
*
*
*
* A single level wavelet transform breaks the image up into four regions:
*
* a h
* v d
*
* Each region has M/2,N/2 rows and columns. Region 'a' is the scaling image, 'h' and 'v' are
* a combination of scaling and wavelet, and 'd' is a combination of horizontal and vertical wavelets.
* When a multiple level transform is performed then the input to the next level is the 'a' from the previous
* level.
*
*
*
* DO NOT MODIFY: This class was automatically generated by {@link boofcv.alg.transform.wavelet.GenerateWaveletTransformOps}
*
*
* @author Peter Abeles
*/
public class WaveletTransformOps {
/**
*
* Performs a single level wavelet transform.
*
*
* @param desc Description of the wavelet.
* @param input Input image. Not modified.
* @param output Where the wavelet transform is written to. Modified.
* @param storage Optional storage image. Should be the same size as output image. If null then
* an image is declared internally.
*/
public static void transform1(WaveletDescription desc ,
GrayF32 input , GrayF32 output ,
GrayF32 storage )
{
UtilWavelet.checkShape(input,output);
WlCoef_F32 coef = desc.getForward();
if( output.width < coef.scaling.length || output.width < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
if( output.height < coef.scaling.length || output.height < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
storage = InputSanityCheck.checkDeclare(output, storage);
// the faster routines can only be run on images which are not too small
int minSize = Math.max(coef.getScalingLength(),coef.getWaveletLength())*3;
if( input.getWidth() <= minSize || input.getHeight() <= minSize ) {
ImplWaveletTransformNaive.horizontal(desc.getBorder(),coef,input,storage);
ImplWaveletTransformNaive.vertical(desc.getBorder(),coef,storage,output);
} else {
ImplWaveletTransformInner.horizontal(coef,input,storage);
ImplWaveletTransformBorder.horizontal(desc.getBorder(),coef,input,storage);
ImplWaveletTransformInner.vertical(coef,storage,output);
ImplWaveletTransformBorder.vertical(desc.getBorder(),coef,storage,output);
}
}
/**
*
* Performs a level N wavelet transform using the fast wavelet transform (FWT).
*
*
* To save memory the input image is used to store intermediate results and is modified.
*
* @param desc Description of the wavelet.
* @param input Input image and is used as internal workspace. Modified.
* @param output Where the multilevel wavelet transform is written to. Modified.
* @param storage Optional storage image. Should be the same size as output image. If null then
* an image is declared internally.
* @param numLevels Number of levels which should be computed in the transform.
*/
public static void transformN(WaveletDescription desc ,
GrayF32 input , GrayF32 output ,
GrayF32 storage ,
int numLevels )
{
if( numLevels == 1 ) {
transform1(desc,input,output, storage);
return;
}
UtilWavelet.checkShape(desc.getForward(),input,output,numLevels);
storage = InputSanityCheck.checkDeclare(output, storage);
// modify the shape of a temporary image not the original
storage = storage.subimage(0,0,output.width,output.height, null);
storage.subImage = false;
transform1(desc,input,output, storage);
for( int i = 2; i <= numLevels; i++ ) {
int width = output.width/2;
int height = output.height/2;
width += width%2;
height += height%2;
input = input.subimage(0,0,width,height, null);
output = output.subimage(0,0,width,height, null);
input.setTo(output);
// transform the scaling image and save the results in the output image
storage.reshape(width,height);
transform1(desc,input,output,storage);
}
}
/**
*
* Performs a single level inverse wavelet transform. Do not pass in a whole image which has been
* transformed by a multilevel transform. Just the relevant sub-image.
*
*
* @param desc Description of the inverse wavelet.
* @param input Input wavelet transform. Not modified.
* @param output Reconstruction of original image. Modified.
* @param storage Optional storage image. Should be the same size as the input image. If null then
* an image is declared internally.
* @param minValue Minimum allowed pixel value
* @param maxValue Maximum allowed pixel value
*/
public static void inverse1(WaveletDescription desc ,
GrayF32 input , GrayF32 output ,
GrayF32 storage , float minValue , float maxValue )
{
UtilWavelet.checkShape(output,input);
WlCoef_F32 coef = desc.getForward();
if( output.width < coef.scaling.length || output.width < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
if( output.height < coef.scaling.length || output.height < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
storage = InputSanityCheck.checkDeclare(input, storage);
// the faster routines can only be run on images which are not too small
int minSize = Math.max(coef.getScalingLength(),coef.getWaveletLength())*3;
if( output.getWidth() <= minSize || output.getHeight() <= minSize ) {
ImplWaveletTransformNaive.verticalInverse(desc.getBorder(),desc.getInverse(),input,storage);
ImplWaveletTransformNaive.horizontalInverse(desc.getBorder(),desc.getInverse(),storage,output);
} else {
ImplWaveletTransformInner.verticalInverse(desc.getInverse().getInnerCoefficients(),input,storage);
ImplWaveletTransformBorder.verticalInverse(desc.getBorder(),desc.getInverse(),input,storage);
ImplWaveletTransformInner.horizontalInverse(desc.getInverse().getInnerCoefficients(),storage,output);
ImplWaveletTransformBorder.horizontalInverse(desc.getBorder(),desc.getInverse(),storage,output);
}
if( minValue != -Float.MAX_VALUE && maxValue != Float.MAX_VALUE )
PixelMath.boundImage(output,minValue,maxValue);
}
/**
* Performs a level N inverse fast wavelet transform (FWT).
*
* To save memory the input image is used to store intermediate results and is modified.
*
* @param desc Description of the inverse wavelet.
* @param input Input wavelet transform and is used as internal workspace. Modified.
* @param output Reconstruction of original image. Modified.
* @param storage Optional storage image. Should be the same size as the input image. If null then
* an image is declared internally.
* @param numLevels Number of levels in the transform.
* @param minValue Minimum allowed pixel value
* @param maxValue Maximum allowed pixel value
*/
public static void inverseN(WaveletDescription desc ,
GrayF32 input , GrayF32 output ,
GrayF32 storage,
int numLevels ,
float minValue , float maxValue)
{
if( numLevels == 1 ) {
inverse1(desc,input,output, storage,minValue,maxValue);
PixelMath.boundImage(output, minValue, maxValue);
return;
}
UtilWavelet.checkShape(desc.getForward(),output,input,numLevels);
storage = InputSanityCheck.checkDeclare(input, storage);
// modify the shape of a temporary image not the original
storage = storage.subimage(0,0,input.width,input.height, null);
storage.subImage = false;
int width,height;
int scale = UtilWavelet.computeScale(numLevels);
width = input.width/scale;
height = input.height/scale;
width += width%2;
height += height%2;
GrayF32 levelIn = input.subimage(0,0,width,height, null);
GrayF32 levelOut = output.subimage(0,0,width,height, null);
storage.reshape(width,height);
inverse1(desc,levelIn,levelOut, storage,-Float.MAX_VALUE,Float.MAX_VALUE);
for( int i = numLevels-1; i >= 1; i-- ) {
// copy the decoded segment into the input
levelIn.setTo(levelOut);
if( i > 1 ) {
scale /= 2;
width = input.width/scale;
height = input.height/scale;
width += width%2;
height += height%2;
storage.reshape(width,height);
levelIn = input.subimage(0,0,width,height, null);
levelOut = output.subimage(0,0,width,height, null);
} else {
levelIn = input;
levelOut = output;
}
storage.reshape(levelIn.width,levelIn.height);
inverse1(desc,levelIn,levelOut, storage,-Float.MAX_VALUE,Float.MAX_VALUE);
}
if( minValue != -Float.MAX_VALUE && maxValue != Float.MAX_VALUE )
PixelMath.boundImage(output, minValue, maxValue);
}
/**
*
* Performs a single level wavelet transform.
*
*
* @param desc Description of the wavelet.
* @param input Input image. Not modified.
* @param output Where the wavelet transform is written to. Modified.
* @param storage Optional storage image. Should be the same size as output image. If null then
* an image is declared internally.
*/
public static void transform1(WaveletDescription desc ,
GrayS32 input , GrayS32 output ,
GrayS32 storage )
{
UtilWavelet.checkShape(input,output);
WlCoef_I32 coef = desc.getForward();
if( output.width < coef.scaling.length || output.width < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
if( output.height < coef.scaling.length || output.height < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
storage = InputSanityCheck.checkDeclare(output, storage);
// the faster routines can only be run on images which are not too small
int minSize = Math.max(coef.getScalingLength(),coef.getWaveletLength())*3;
if( input.getWidth() <= minSize || input.getHeight() <= minSize ) {
ImplWaveletTransformNaive.horizontal(desc.getBorder(),coef,input,storage);
ImplWaveletTransformNaive.vertical(desc.getBorder(),coef,storage,output);
} else {
ImplWaveletTransformInner.horizontal(coef,input,storage);
ImplWaveletTransformBorder.horizontal(desc.getBorder(),coef,input,storage);
ImplWaveletTransformInner.vertical(coef,storage,output);
ImplWaveletTransformBorder.vertical(desc.getBorder(),coef,storage,output);
}
}
/**
*
* Performs a level N wavelet transform using the fast wavelet transform (FWT).
*
*
* To save memory the input image is used to store intermediate results and is modified.
*
* @param desc Description of the wavelet.
* @param input Input image and is used as internal workspace. Modified.
* @param output Where the multilevel wavelet transform is written to. Modified.
* @param storage Optional storage image. Should be the same size as output image. If null then
* an image is declared internally.
* @param numLevels Number of levels which should be computed in the transform.
*/
public static void transformN(WaveletDescription desc ,
GrayS32 input , GrayS32 output ,
GrayS32 storage ,
int numLevels )
{
if( numLevels == 1 ) {
transform1(desc,input,output, storage);
return;
}
UtilWavelet.checkShape(desc.getForward(),input,output,numLevels);
storage = InputSanityCheck.checkDeclare(output, storage);
// modify the shape of a temporary image not the original
storage = storage.subimage(0,0,output.width,output.height, null);
storage.subImage = false;
transform1(desc,input,output, storage);
for( int i = 2; i <= numLevels; i++ ) {
int width = output.width/2;
int height = output.height/2;
width += width%2;
height += height%2;
input = input.subimage(0,0,width,height, null);
output = output.subimage(0,0,width,height, null);
input.setTo(output);
// transform the scaling image and save the results in the output image
storage.reshape(width,height);
transform1(desc,input,output,storage);
}
}
/**
*
* Performs a single level inverse wavelet transform. Do not pass in a whole image which has been
* transformed by a multilevel transform. Just the relevant sub-image.
*
*
* @param desc Description of the inverse wavelet.
* @param input Input wavelet transform. Not modified.
* @param output Reconstruction of original image. Modified.
* @param storage Optional storage image. Should be the same size as the input image. If null then
* an image is declared internally.
* @param minValue Minimum allowed pixel value
* @param maxValue Maximum allowed pixel value
*/
public static void inverse1(WaveletDescription desc ,
GrayS32 input , GrayS32 output ,
GrayS32 storage , int minValue , int maxValue )
{
UtilWavelet.checkShape(output,input);
WlCoef_I32 coef = desc.getForward();
if( output.width < coef.scaling.length || output.width < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
if( output.height < coef.scaling.length || output.height < coef.wavelet.length )
throw new IllegalArgumentException("Wavelet is too large for provided image.");
storage = InputSanityCheck.checkDeclare(input, storage);
// the faster routines can only be run on images which are not too small
int minSize = Math.max(coef.getScalingLength(),coef.getWaveletLength())*3;
if( output.getWidth() <= minSize || output.getHeight() <= minSize ) {
ImplWaveletTransformNaive.verticalInverse(desc.getBorder(),desc.getInverse(),input,storage);
ImplWaveletTransformNaive.horizontalInverse(desc.getBorder(),desc.getInverse(),storage,output);
} else {
ImplWaveletTransformInner.verticalInverse(desc.getInverse().getInnerCoefficients(),input,storage);
ImplWaveletTransformBorder.verticalInverse(desc.getBorder(),desc.getInverse(),input,storage);
ImplWaveletTransformInner.horizontalInverse(desc.getInverse().getInnerCoefficients(),storage,output);
ImplWaveletTransformBorder.horizontalInverse(desc.getBorder(),desc.getInverse(),storage,output);
}
if( minValue != Integer.MIN_VALUE && maxValue != Integer.MAX_VALUE )
PixelMath.boundImage(output,minValue,maxValue);
}
/**
* Performs a level N inverse fast wavelet transform (FWT).
*
* To save memory the input image is used to store intermediate results and is modified.
*
* @param desc Description of the inverse wavelet.
* @param input Input wavelet transform and is used as internal workspace. Modified.
* @param output Reconstruction of original image. Modified.
* @param storage Optional storage image. Should be the same size as the input image. If null then
* an image is declared internally.
* @param numLevels Number of levels in the transform.
* @param minValue Minimum allowed pixel value
* @param maxValue Maximum allowed pixel value
*/
public static void inverseN(WaveletDescription desc ,
GrayS32 input , GrayS32 output ,
GrayS32 storage,
int numLevels ,
int minValue , int maxValue)
{
if( numLevels == 1 ) {
inverse1(desc,input,output, storage,minValue,maxValue);
PixelMath.boundImage(output, minValue, maxValue);
return;
}
UtilWavelet.checkShape(desc.getForward(),output,input,numLevels);
storage = InputSanityCheck.checkDeclare(input, storage);
// modify the shape of a temporary image not the original
storage = storage.subimage(0,0,input.width,input.height, null);
storage.subImage = false;
int width,height;
int scale = UtilWavelet.computeScale(numLevels);
width = input.width/scale;
height = input.height/scale;
width += width%2;
height += height%2;
GrayS32 levelIn = input.subimage(0,0,width,height, null);
GrayS32 levelOut = output.subimage(0,0,width,height, null);
storage.reshape(width,height);
inverse1(desc,levelIn,levelOut, storage,Integer.MIN_VALUE,Integer.MAX_VALUE);
for( int i = numLevels-1; i >= 1; i-- ) {
// copy the decoded segment into the input
levelIn.setTo(levelOut);
if( i > 1 ) {
scale /= 2;
width = input.width/scale;
height = input.height/scale;
width += width%2;
height += height%2;
storage.reshape(width,height);
levelIn = input.subimage(0,0,width,height, null);
levelOut = output.subimage(0,0,width,height, null);
} else {
levelIn = input;
levelOut = output;
}
storage.reshape(levelIn.width,levelIn.height);
inverse1(desc,levelIn,levelOut, storage,Integer.MIN_VALUE,Integer.MAX_VALUE);
}
if( minValue != Integer.MIN_VALUE && maxValue != Integer.MAX_VALUE )
PixelMath.boundImage(output, minValue, maxValue);
}
}