Given a 1D signal of length 2^n, how can we construct the 2^n x 2^n matrices for 1D direct and inverse Haar wavelet transforms?
Direct Matrix
The 2^n by 2^n matrix for 2D direct Haar wavelet transform is obtained by computing 1D Haar transforms of the 2^n basis vectors. Each such vector becomes the corresponding column of the matrix. In other words, the directly transformed 0th base vector becomes the 0th column of the direct matrix, the 1st transformed base vector becomes the 1st column in the direct matrix and so on. For example, if we want to compute the forward matrix for any signal of length 2^3, we need to convert the following 8 basis vectors:
double[] bv0 = {1, 0, 0, 0, 0, 0, 0, 0};
double[] bv1 = {0, 1, 0, 0, 0, 0, 0, 0};
double[] bv2 = {0, 0, 1, 0, 0, 0, 0, 0};
double[] bv3 = {0, 0, 0, 1, 0, 0, 0, 0};
double[] bv4 = {0, 0, 0, 0, 1, 0, 0, 0};
double[] bv5 = {0, 0, 0, 0, 0, 1, 0, 0};
double[] bv6 = {0, 0, 0, 0, 0, 0, 1, 0};
double[] bv7 = {0, 0, 0, 0, 0, 0, 0, 1};
The 1D Haar transforms of these vectors can be computed by using OneDHaar.orderedFastHaarWaveletTransform(double[] v). Let us quickly define two methods to display the results.
public static void forward_basis_vector(double[] bv) {
OneDHaar.orderedFastHaarWaveletTransform(bv);
OneDHaar.displaySample(bv);
}
public static void test_forward_basis_vectors() {
double[] bv0 = {1, 0, 0, 0, 0, 0, 0, 0};
double[] bv1 = {0, 1, 0, 0, 0, 0, 0, 0};
double[] bv2 = {0, 0, 1, 0, 0, 0, 0, 0};
double[] bv3 = {0, 0, 0, 1, 0, 0, 0, 0};
double[] bv4 = {0, 0, 0, 0, 1, 0, 0, 0};
double[] bv5 = {0, 0, 0, 0, 0, 1, 0, 0};
double[] bv6 = {0, 0, 0, 0, 0, 0, 1, 0};
double[] bv7 = {0, 0, 0, 0, 0, 0, 0, 1};
forward_basis_vector(bv0);
forward_basis_vector(bv1);
forward_basis_vector(bv2);
forward_basis_vector(bv3);
forward_basis_vector(bv4);
forward_basis_vector(bv5);
forward_basis_vector(bv6);
forward_basis_vector(bv7);
}
The output of test_forward_basis_vectors() is as follows:
0.125 0.125 0.25 0.0 0.5 0.0 0.0 0.0
0.125 0.125 0.25 0.0 -0.5 0.0 0.0 0.0
0.125 0.125 -0.25 0.0 0.0 0.5 0.0 0.0
0.125 0.125 -0.25 0.0 0.0 -0.5 0.0 0.0
0.125 -0.125 0.0 0.25 0.0 0.0 0.5 0.0
0.125 -0.125 0.0 0.25 0.0 0.0 -0.5 0.0
0.125 -0.125 0.0 -0.25 0.0 0.0 0.0 0.5
0.125 -0.125 0.0 -0.25 0.0 0.0 0.0 -0.5
Now we can compute the direct or forward 2D Haar matrix for any n.
public static double[][] computeForwardHaarTransformMatrix(int n) {
int size = (int) Math.pow(2, n);
double[] base_vector = new double[size];
double[][] fhw = new double[size][size];
for(int col_num = 0; col_num < size; col_num++) {
for(int i = 0; i < size; i++) {
if ( i == col_num )
base_vector[i] = 1;
else
base_vector[i] = 0;
}
OneDHaar.orderedFastHaarWaveletTransform(base_vector);
for(int row_num = 0; row_num < size; row_num++) {
fhw[row_num][col_num] = base_vector[row_num];
}
}
return fhw;
}
We can test our implementation with testForwardHaarTransformMatrix():
public static void testForwardHaarTransformMatrix() {
double[][] fhtm3 = OneDHaar.computeForwardHaarTransformMatrix(3);
double[][] fhtm4 = OneDHaar.computeForwardHaarTransformMatrix(4);
TwoDHaar.displaySample(fhtm3, 8, 0);
double[] sample00 = {1, 1, 1, 1, 1, 1, 1, 1};
double[] sample01 = {1, 1, 1, 1, 1, 1, 1, 1};
System.out.print("Input:\t"); OneDHaar.displaySample(sample00);
OneDHaar.orderedFastHaarWaveletTransform(sample00);
System.out.print("FHWT:\t"); OneDHaar.displaySample(sample00);
double[] fwd_sample01 = OneDHaar.applyHaarTransformMatrix(fhtm3, sample01);
System.out.print("MHWT:\t"); OneDHaar.displaySample(fwd_sample01);
System.out.println();
double[] sample10 = {1, 1, 1, 1, 0, 0, 0, 0};
double[] sample11 = {1, 1, 1, 1, 0, 0, 0, 0};
System.out.print("Input:\t"); OneDHaar.displaySample(sample10);
OneDHaar.orderedFastHaarWaveletTransform(sample10);
System.out.print("FHWT:\t"); OneDHaar.displaySample(sample10);
double[] fwd_sample11 = OneDHaar.applyHaarTransformMatrix(fhtm3, sample11);
System.out.print("MHWT:\t"); OneDHaar.displaySample(fwd_sample11);
double[] sample20 = {12.0, 16.0, 27.0, 32.8, 33.5, 33.5, 39.0, 39.0,
40.0, 41.3, 41.3, 42.0, 43.0, 45.0, 35.5, 49.0};
double[] sample21 = {12.0, 16.0, 27.0, 32.8, 33.5, 33.5, 39.0, 39.0,
40.0, 41.3, 41.3, 42.0, 43.0, 45.0, 35.5, 49.0};
System.out.print("Input:\t"); OneDHaar.displaySample(sample20);
OneDHaar.orderedFastHaarWaveletTransform(sample20);
System.out.print("FHWT:\t"); OneDHaar.displaySample(sample20);
double[] fwd_sample21 = OneDHaar.applyHaarTransformMatrix(fhtm4, sample21);
System.out.print("MHWT:\t"); OneDHaar.displaySample(fwd_sample21);
}
The 2^n by 2^n matrix for 2D direct Haar wavelet transform is obtained by computing 1D Haar transforms of the 2^n basis vectors. Each such vector becomes the corresponding column of the matrix. In other words, the directly transformed 0th base vector becomes the 0th column of the direct matrix, the 1st transformed base vector becomes the 1st column in the direct matrix and so on. For example, if we want to compute the forward matrix for any signal of length 2^3, we need to convert the following 8 basis vectors:
double[] bv0 = {1, 0, 0, 0, 0, 0, 0, 0};
double[] bv1 = {0, 1, 0, 0, 0, 0, 0, 0};
double[] bv2 = {0, 0, 1, 0, 0, 0, 0, 0};
double[] bv3 = {0, 0, 0, 1, 0, 0, 0, 0};
double[] bv4 = {0, 0, 0, 0, 1, 0, 0, 0};
double[] bv5 = {0, 0, 0, 0, 0, 1, 0, 0};
double[] bv6 = {0, 0, 0, 0, 0, 0, 1, 0};
double[] bv7 = {0, 0, 0, 0, 0, 0, 0, 1};
The 1D Haar transforms of these vectors can be computed by using OneDHaar.orderedFastHaarWaveletTransform(double[] v). Let us quickly define two methods to display the results.
public static void forward_basis_vector(double[] bv) {
OneDHaar.orderedFastHaarWaveletTransform(bv);
OneDHaar.displaySample(bv);
}
public static void test_forward_basis_vectors() {
double[] bv0 = {1, 0, 0, 0, 0, 0, 0, 0};
double[] bv1 = {0, 1, 0, 0, 0, 0, 0, 0};
double[] bv2 = {0, 0, 1, 0, 0, 0, 0, 0};
double[] bv3 = {0, 0, 0, 1, 0, 0, 0, 0};
double[] bv4 = {0, 0, 0, 0, 1, 0, 0, 0};
double[] bv5 = {0, 0, 0, 0, 0, 1, 0, 0};
double[] bv6 = {0, 0, 0, 0, 0, 0, 1, 0};
double[] bv7 = {0, 0, 0, 0, 0, 0, 0, 1};
forward_basis_vector(bv0);
forward_basis_vector(bv1);
forward_basis_vector(bv2);
forward_basis_vector(bv3);
forward_basis_vector(bv4);
forward_basis_vector(bv5);
forward_basis_vector(bv6);
forward_basis_vector(bv7);
}
The output of test_forward_basis_vectors() is as follows:
0.125 0.125 0.25 0.0 0.5 0.0 0.0 0.0
0.125 0.125 0.25 0.0 -0.5 0.0 0.0 0.0
0.125 0.125 -0.25 0.0 0.0 0.5 0.0 0.0
0.125 0.125 -0.25 0.0 0.0 -0.5 0.0 0.0
0.125 -0.125 0.0 0.25 0.0 0.0 0.5 0.0
0.125 -0.125 0.0 0.25 0.0 0.0 -0.5 0.0
0.125 -0.125 0.0 -0.25 0.0 0.0 0.0 0.5
0.125 -0.125 0.0 -0.25 0.0 0.0 0.0 -0.5
Now we can compute the direct or forward 2D Haar matrix for any n.
public static double[][] computeForwardHaarTransformMatrix(int n) {
int size = (int) Math.pow(2, n);
double[] base_vector = new double[size];
double[][] fhw = new double[size][size];
for(int col_num = 0; col_num < size; col_num++) {
for(int i = 0; i < size; i++) {
if ( i == col_num )
base_vector[i] = 1;
else
base_vector[i] = 0;
}
OneDHaar.orderedFastHaarWaveletTransform(base_vector);
for(int row_num = 0; row_num < size; row_num++) {
fhw[row_num][col_num] = base_vector[row_num];
}
}
return fhw;
}
We can test our implementation with testForwardHaarTransformMatrix():
public static void testForwardHaarTransformMatrix() {
double[][] fhtm3 = OneDHaar.computeForwardHaarTransformMatrix(3);
double[][] fhtm4 = OneDHaar.computeForwardHaarTransformMatrix(4);
TwoDHaar.displaySample(fhtm3, 8, 0);
double[] sample00 = {1, 1, 1, 1, 1, 1, 1, 1};
double[] sample01 = {1, 1, 1, 1, 1, 1, 1, 1};
System.out.print("Input:\t"); OneDHaar.displaySample(sample00);
OneDHaar.orderedFastHaarWaveletTransform(sample00);
System.out.print("FHWT:\t"); OneDHaar.displaySample(sample00);
double[] fwd_sample01 = OneDHaar.applyHaarTransformMatrix(fhtm3, sample01);
System.out.print("MHWT:\t"); OneDHaar.displaySample(fwd_sample01);
System.out.println();
double[] sample10 = {1, 1, 1, 1, 0, 0, 0, 0};
double[] sample11 = {1, 1, 1, 1, 0, 0, 0, 0};
System.out.print("Input:\t"); OneDHaar.displaySample(sample10);
OneDHaar.orderedFastHaarWaveletTransform(sample10);
System.out.print("FHWT:\t"); OneDHaar.displaySample(sample10);
double[] fwd_sample11 = OneDHaar.applyHaarTransformMatrix(fhtm3, sample11);
System.out.print("MHWT:\t"); OneDHaar.displaySample(fwd_sample11);
double[] sample20 = {12.0, 16.0, 27.0, 32.8, 33.5, 33.5, 39.0, 39.0,
40.0, 41.3, 41.3, 42.0, 43.0, 45.0, 35.5, 49.0};
double[] sample21 = {12.0, 16.0, 27.0, 32.8, 33.5, 33.5, 39.0, 39.0,
40.0, 41.3, 41.3, 42.0, 43.0, 45.0, 35.5, 49.0};
System.out.print("Input:\t"); OneDHaar.displaySample(sample20);
OneDHaar.orderedFastHaarWaveletTransform(sample20);
System.out.print("FHWT:\t"); OneDHaar.displaySample(sample20);
double[] fwd_sample21 = OneDHaar.applyHaarTransformMatrix(fhtm4, sample21);
System.out.print("MHWT:\t"); OneDHaar.displaySample(fwd_sample21);
}
Inverse Matrix
The 2^n by 2^n matrix for the inverse 2D Haar wavelet
transform is obtained by computing the inverse 1D Haar transforms of the 2^n basis
vectors. Each such vector becomes the corresponding column of the inverse
matrix. In other words, the inversely transformed 0th base vector becomes the 0th
column vector, the 1st inversely transformed base vector becomes the 1st column in the
direct matrix and so on. For example, if we want to compute the inverse
matrix for any signal of length 2^3, we need to compute the inverse transforms the following 8
basis vectors:
double[] bv0 = {1, 0, 0, 0, 0, 0, 0, 0};
double[] bv1 = {0, 1, 0, 0, 0, 0, 0, 0};
double[] bv2 = {0, 0, 1, 0, 0, 0, 0, 0};
double[] bv3 = {0, 0, 0, 1, 0, 0, 0, 0};
double[] bv4 = {0, 0, 0, 0, 1, 0, 0, 0};
double[] bv5 = {0, 0, 0, 0, 0, 1, 0, 0};
double[] bv6 = {0, 0, 0, 0, 0, 0, 1, 0};
double[] bv7 = {0, 0, 0, 0, 0, 0, 0, 1};
The inverse 1D Haar transforms of these vectors can be computed by using OneDHaar.orderedFastInverseHaarWaveletTransform(double[] v). Let us quickly define two methods to display the results.
public static void inverse_basis_vector(double[] bv) {
OneDHaar.orderedFastInverseHaarWaveletTransform(bv);
OneDHaar.displaySample(bv);
}
public static void test_inverse_basis_vectors() {
double[] bv0 = {1, 0, 0, 0, 0, 0, 0, 0};
double[] bv1 = {0, 1, 0, 0, 0, 0, 0, 0};
double[] bv2 = {0, 0, 1, 0, 0, 0, 0, 0};
double[] bv3 = {0, 0, 0, 1, 0, 0, 0, 0};
double[] bv4 = {0, 0, 0, 0, 1, 0, 0, 0};
double[] bv5 = {0, 0, 0, 0, 0, 1, 0, 0};
double[] bv6 = {0, 0, 0, 0, 0, 0, 1, 0};
double[] bv7 = {0, 0, 0, 0, 0, 0, 0, 1};
inverse_basis_vector(bv0);
inverse_basis_vector(bv1);
inverse_basis_vector(bv2);
inverse_basis_vector(bv3);
inverse_basis_vector(bv4);
inverse_basis_vector(bv5);
inverse_basis_vector(bv6);
inverse_basis_vector(bv7);
}
The output of running test_inverse_basis_vectors() is given below.
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 -1.0 -1.0 -1.0 -1.0
1.0 1.0 -1.0 -1.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 1.0 1.0 -1.0 -1.0
1.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 1.0 -1.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 1.0 -1.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 1.0 -1.0
We can now compute the inverse 2D Haar matrix for any n:
public static double[][] computeInverseHaarTransformMatrix(int n) {
int size = (int) Math.pow(2, n);
double[] base_vector = new double[size];
double[][] ihw = new double[size][size];
for(int col_num = 0; col_num < size; col_num++) {
for(int i = 0; i < size; i++) {
if ( i == col_num )
base_vector[i] = 1;
else
base_vector[i] = 0;
}
OneDHaar.orderedFastInverseHaarWaveletTransform(base_vector);
for(int row_num = 0; row_num < size; row_num++) {
ihw[row_num][col_num] = base_vector[row_num];
}
}
return ihw;
}
We can test the computation of the inverse 2D matrix as follows:
public static void testInverseHaarTransformMatrix() {
double[][] ihtm3 = OneDHaar.computeInverseHaarTransformMatrix(3);
double[][] ihtm4 = OneDHaar.computeInverseHaarTransformMatrix(4);
TwoDHaar.displaySample(ihtm3, 8, 0);
double[] sample00 = {1, 1, 1, 1, 1, 1, 1, 1};
double[] sample01 = {1, 1, 1, 1, 1, 1, 1, 1};
OneDHaar.orderedFastHaarWaveletTransform(sample00);
OneDHaar.orderedFastHaarWaveletTransform(sample01);
System.out.print("Input:\t"); OneDHaar.displaySample(sample00);
OneDHaar.orderedFastInverseHaarWaveletTransform(sample00);
System.out.print("IFHWT:\t"); OneDHaar.displaySample(sample00);
double[] isample01 = OneDHaar.applyHaarTransformMatrix(ihtm3, sample01);
System.out.print("IMHWT:\t"); OneDHaar.displaySample(isample01);
System.out.println();
double[] sample10 = {1, 1, 1, 1, 0, 0, 0, 0};
double[] sample11 = {1, 1, 1, 1, 0, 0, 0, 0};
OneDHaar.orderedFastHaarWaveletTransform(sample10);
OneDHaar.orderedFastHaarWaveletTransform(sample11);
System.out.print("Input:\t"); OneDHaar.displaySample(sample10);
OneDHaar.orderedFastInverseHaarWaveletTransform(sample10);
System.out.print("IFHWT:\t"); OneDHaar.displaySample(sample10);
double[] isample11 = OneDHaar.applyHaarTransformMatrix(ihtm3, sample11);
System.out.print("IMHWT:\t"); OneDHaar.displaySample(isample11);
double[] sample20 = {12.0, 16.0, 27.0, 32.8, 33.5, 33.5, 39.0, 39.0,
40.0, 41.3, 41.3, 42.0, 43.0, 45.0, 35.5, 49.0};
double[] sample21 = {12.0, 16.0, 27.0, 32.8, 33.5, 33.5, 39.0, 39.0,
40.0, 41.3, 41.3, 42.0, 43.0, 45.0, 35.5, 49.0};
OneDHaar.orderedFastHaarWaveletTransform(sample20);
OneDHaar.orderedFastHaarWaveletTransform(sample21);
System.out.print("Input:\t"); OneDHaar.displaySample(sample20);
OneDHaar.orderedFastInverseHaarWaveletTransform(sample20);
System.out.print("IFHWT:\t"); OneDHaar.displaySample(sample20);
double[] isample21 = OneDHaar.applyHaarTransformMatrix(ihtm4, sample21);
System.out.print("IMHWT:\t"); OneDHaar.displaySample(isample21);
}
Matrix Multiplication
Here is how the direct or inverse matrices can be applied to the transform or invert the 1D signals:
public static double[] applyHaarTransformMatrix(double[][] htm, double[] v) {
int num_rows = htm.length;
if ( num_rows < 1 ) return null;
int num_cols = htm[0].length;
if ( num_cols < 1 ) return null;
if ( num_rows != num_cols ) return null;
if ( num_rows != v.length ) return null;
double[] inversed_v = new double[num_cols];
double dot_product = 0;
for(int row = 0; row < num_rows; row++) {
dot_product = 0;
for(int col = 0; col < num_cols; col++) {
dot_product += htm[row][col]*v[col];
}
inversed_v[row] = dot_product;
}
return inversed_v;
}