Wavelet1d
lastmod 2021-07-05created 2014-10-1015 edits
C++ 1D/2D DWT Implementation for Win32 and Linux
Wavelet2d / Wavelet2s Libraries
- 1D DWT and IDWT Implementation (Two Modes)
- 2D DWT and IDWT Implementation (Two Modes)
- 1D SWT and ISWT Implementation ( Stationary Wavelet Transform)
- 2D SWT Implementation
- Implemented using FFTW3 Library
- Shared(.so) and static(.a) libraries for Linux
- Shared(.dll) and static(.a) libraries for Win32 GCC (MinGW).
- Shared(.dll) libraries for Microsoft VC++
This implementation uses C++ vector objects to accept input, store and output data. This is done to overcome certain programming limitations associated with using arrays. Dynamic arrays were also an option but they require a lot of house-cleaning without having any advantages over vector objects. To learn more about vectors, please refer to excellent tutorial at CPLUSPLUS. Vectors and Arrays can be converted back and forth so even if you are more comfortable with arrays, using vectors should not really be a problem.
Documentation
Wavelet Filters
-
int filtcoef(string , vector<double>&, vector<double>&, vector<double>&, vector<double>&) - Gets the wavelet filters. Pass the wavelet name as the first argument (
nm) and the filters are obtained through thevector<double>&arguments.
The filter types are listed below.
- Daubechies: DB1, DB2, ...,, DB15
- Biorthogonal: bior1.1, bior1.3, bior1.5, bior2.2, bior2.4, bior2.6, bior2.8, bior3.1, bior3.3, bior3.5, bior3.7, bior3.9, bior4.4, bior5.5, bior6.8
- Coiflets: coif1, coif2, coif3, coif4, coif5
- Symmlets: SYM1, sym2, ........, sym10
2D DWT/IDWT Functions
As in 1D case, both periodic and symmetric extension methods for Decimated DWT take exactly same input arguments.The difference is that Output vector in periodic extension has usually the same size (~NXN) as the input vector(NXN) while output vector in symmetric extension case has redundancies with length/breadth depending on size of filter used.
Periodic Extension
-
void* dwt_2d(vector<vector<double>> &origsig, int J, string nm, vector<double>&dwt_output,vector<double>&flag, vector<int>&length) - The first argument (
origsig) is the input Image/Matrix.Jis the wavelet decomposition level andnmis the wavelet name.
Additional dwt_2d_sym Functions
-
void* dispDWT(vector<double>&,vector<vector<double>> &, vector<int>&, vector<int>&, int )void* dwt_output_dim_sym(vector<int>&,vector<int>&, int ) - The result of the 2D DWT is a one-dimensional Vector, a format unsuitable for display. It is therefore converted into the traditional layout (an image in which the square image is repeatedly split into four quarters) for display.
dwt_output_dim_sym()
The dwt_output_dim_sym() function returns the sizes of the sub-images for display in its second argument (length2). The last two values of this argument give the size of the DWT.
dwt_output_dim_sym(length, length2, J);
// ...
int siz = length2.size();
int rows_n = length2[siz - 2];
int cols_n = length2[siz - 1];
Vector2d dwtdisp(rows_n, Vector1d(cols_n));
For reference, the image display layout is shown below.
Three_Level_Wavelet_Image_Decomposition.png
The implementation of the dwt_output_dim_sym() function is as follows.
void* dwt_output_dim_sym(vector<int> &length, vector<int> &length2, int J)
{
unsigned int sz = length.size();
int rows = length[sz - 2];
int cols = length[sz - 1];
for (int i = 0; i < J; i++) {
rows = (int) ceil((double) rows / 2.0);
cols = (int) ceil((double) cols / 2.0);
}
for (int i = 0; i < J + 1; i++) {
length2.push_back(rows);
length2.push_back(cols);
rows = rows * 2;
cols = cols * 2;
}
return 0;
}
Wavelet2d DWT Example
Here is how to output the 2D DWT result as an OpenCV IplImage.
// 3.5 Image Approximation Demo
// http://wavelet2d.sourceforge.net/
IplImage * createDWTImage(IplImage * original)
{
using namespace std;
using namespace cv;
int height = original->height;
int width = original->width;
// int channels = original->nChannels;
// int depth = original->depth;
Mat matrix_original(original);
Vector2d vector_original(height, Vector1d(width));
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
const int k = 1; // what is k ?
uchar * image_cursor = (uchar*) matrix_original.data + y * matrix_original.step;
uchar pixel = image_cursor[x * matrix_original.elemSize() + k];
vector_original[y][x] = (double) pixel;
}
}
std::string nm = "db2"; // Daubechies : db1,db2,.., ,db15
Vector1d l1, h1, l2, h2;
filtcoef(nm, l1, h1, l2, h2);
// unsigned int lf=l1.size();
// int rows_n =(int) (rows+ J*(lf-1));
// int cols_n =(int) (cols + J * ( lf -1));
// Finding 2D DWT Transform of the image using symetric extension algorithm
// Extension is set to 0 (eg., int e = 0)
Vector1i length;
Vector1d output, flag;
int J = 1; // depth of dwt.
dwt_2d(vector_original, J, nm, output, flag, length);
double max;
Vector1i length2;
// This algorithm computes DWT of image of any given size. Together with convolution and
// subsampling operations it is clear that subsampled images are of different length than
// dyadic length images. In order to compute the "effective" size of DWT we do additional
// calculations.
dwt_output_dim_sym(length, length2, J);
// length2 is gives the integer vector that contains the size of subimages that will
// combine to form the displayed output image. The last two entries of length2 gives the
// size of DWT ( rows_n by cols_n)
int siz = length2.size();
int rows_n = length2[siz - 2];
int cols_n = length2[siz - 1];
Vector2d dwtdisp(rows_n, Vector1d(cols_n));
dispDWT(output, dwtdisp, length, length2, J);
// dispDWT returns the 2D object dwtdisp which will be displayed using OPENCV’s image
// handling functions
Vector2d dwt_output = dwtdisp;
// Storing the DWT coefficients in two different vectors that will be used to approximate
// Image with two different sets of chosen coefficients.
Vector1d dwt_coef1;
Vector1d dwt_coef2;
dwt_coef1 = output;
dwt_coef2 = output;
maxval(dwt_output, max); // max value is needed to take care of overflow which happens because
// of convolution operations performed on unsigned 8 bit images
//Displaying Scaled Image
// Creating Image in OPENCV
IplImage * cvImg; // image used for output
CvSize imgSize; // size of output image
imgSize.width = cols_n;
imgSize.height = rows_n;
cvImg = cvCreateImage(imgSize, 8, 1);
// dwt_hold is created to hold the dwt output as further operations need to be
// carried out on dwt_output in order to display scaled images.
Vector2d dwt_hold(rows_n, Vector1d(cols_n));
dwt_hold = dwt_output;
// Setting coefficients of created image to the scaled DWT output values
for (int i = 0; i < imgSize.height; i++) {
for (int j = 0; j < imgSize.width; j++) {
if (dwt_output[i][j] <= 0.0) {
dwt_output[i][j] = 0.0;
}
if (i <= (length2[0]) && j <= (length2[1])) {
((uchar*) (cvImg->imageData + cvImg->widthStep * i))[j] =
(char) ((dwt_output[i][j] / max) * 255.0);
} else {
((uchar*) (cvImg->imageData + cvImg->widthStep * i))[j] =
(char) (dwt_output[i][j]);
}
}
}
// cvNamedWindow("DWT Image", 1); // creation of a visualisation window
// cvShowImage("DWT Image", cvImg); // image visualisation
// cvWaitKey();
return cvImg;
}