Wednesday, June 29, 2016

Creating Images of Forward Ordered 2D Haar Wavelet Transforms




Problem
  
This note describes how to create images of forward ordered 2D Haar Wavelet Transform (HWT).



Auxiliary Methods
  
The methods below assume that the project has the jar archive for OpenCV 2.4.9. First of all, we define a method that takes a path with an image and convert it to grayscale. 
 
 public static double[][] getGrayscalePixMat(String infile) {
        Mat orig = Highgui.imread(IMAGE_SOURCE_DIR + infile);
        if (orig.rows() == 0 || orig.cols() == 0) {
            throw new IllegalArgumentException("Failed to read " + IMAGE_SOURCE_DIR + infile);
        }
       
        Mat grayscale = new Mat(orig.rows(), orig.cols(), CvType.CV_8UC1);
        Imgproc.cvtColor(orig, grayscale, Imgproc.COLOR_RGB2GRAY);
       
        double[][] pix_mat = get1CPixMat(grayscale);
        orig.release();
        grayscale.release();
        return pix_mat;

}

Second, we need to define methods to scale values of specific wavelets in a 2D transform in the third argument to be in the range [0, 255]. The scaled values are placed into the mat passed as the first argument. The methods scaleSetHorMatValsInImage(), scaleSetVerMatValsInImage(), scaleSetDigValsInImage() scale the values of the horizontal, vertical, and diagonal coefficients.

public static double findMaxVal(double[][] cmat) {
        double max = Double.MIN_VALUE;
        for(int row = 0; row < cmat.length; row++) {
            for(int col = 0; col < cmat[row].length; col++) {
                if ( cmat[row][col] > max ) {
                    max = cmat[row][col];
                }
            }
        }
        return max;
    }
   
    public static double findMinVal(double[][] cmat) {
        double min = Double.MAX_VALUE;
        for(int row = 0; row < cmat.length; row++) {
            for(int col = 0; col < cmat[row].length; col++) {
                if ( cmat[row][col] < min ) {
                    min = cmat[row][col];
                }
            }
        }
        return min;
    }

 
public static void scaleSetHorMatValsInImage(Mat grayscale, int mat_size, double[][] cmat) {
        System.out.println("setHorMatValsInImage " + mat_size);
        double max    = findMaxVal(cmat);
        double min    = findMinVal(cmat);
        double crange = max - min;
        double scaler = 255/crange;
        int half = mat_size/2;
        Mat temp = new Mat(cmat.length, cmat[0].length, CvType.CV_8UC1);
        for(int img_row = 0, cmat_row = 0; img_row < half; img_row++, cmat_row++) {
            for(int img_col = half, cmat_col = 0; img_col < mat_size; img_col++, cmat_col++) {
                double cmat_val = (cmat[cmat_row][cmat_col] - min)*scaler;
                double[] data = { cmat_val, cmat_val, cmat_val };
                grayscale.put(img_row, img_col, data);
                temp.put(cmat_row, cmat_col, data);
            }
        }
        Highgui.imwrite(IMAGE_SOURCE_DIR + "temp_hor_scale_" + half + ".jpg", temp);
        temp.release();
 }


public static void scaleVerMatValsInImage(Mat grayscale, int mat_size, double[][] cmat) {
        System.out.println("setVerMatValsInImage " + mat_size);
        double max    = findMaxVal(cmat);
        double min    = findMinVal(cmat);
        double crange = max - min;
        double scaler = 255/crange;
        int half = mat_size/2;
        Mat temp = new Mat(cmat.length, cmat[0].length, CvType.CV_8UC1);
        for(int img_row = half, cmat_row = 0; img_row < mat_size; img_row++, cmat_row++) {
            for(int img_col = 0, cmat_col = 0; img_col < half; img_col++, cmat_col++) {
                double cmat_val = (cmat[cmat_row][cmat_col] - min)*scaler;
                double[] data = { cmat_val, cmat_val, cmat_val };
                grayscale.put(img_row, img_col, data);
                temp.put(cmat_row, cmat_col, data);
            }
        }
        Highgui.imwrite(IMAGE_SOURCE_DIR + "temp_ver_scale_" + half + ".jpg", temp);
        temp.release();
    }


public static void scaleDigMatValsInImage(Mat grayscale, int mat_size, double[][] cmat) {
        System.out.println("scaleDigMatValsInImage " + mat_size);
        double max    = findMaxVal(cmat);
        double min    = findMinVal(cmat);
        double crange = max - min;
        double scaler = 255/crange;
        int half = mat_size/2;
        Mat temp = new Mat(cmat.length, cmat[0].length, CvType.CV_8UC1);
        for(int img_row = half, cmat_row = 0; img_row < mat_size; img_row++, cmat_row++) {
            for(int img_col = half, cmat_col = 0; img_col < mat_size; img_col++, cmat_col++) {
                double cmat_val = (cmat[cmat_row][cmat_col] - min)*scaler;
                double[] data = { cmat_val, cmat_val, cmat_val };
                grayscale.put(img_row, img_col, data);
                temp.put(cmat_row, cmat_col, data);
            }
        }
        Highgui.imwrite(IMAGE_SOURCE_DIR + "temp_dig_scale_" + half + ".jpg", temp);
        temp.release();
    }


The method below scales the averages.
 
public static void setAvrgMatValsInImage(Mat grayscale, int mat_size, double[][] cmat) {
        System.out.println("setAvrgMatValsInImage " + mat_size);
        double max    = findMaxVal(cmat);
        double min    = findMinVal(cmat);
        double crange = max - min;
        double scaler = 255/crange;
        int half = mat_size/2;
        Mat temp = new Mat(cmat.length, cmat[0].length, CvType.CV_8UC1);
        for(int img_row = 0, cmat_row = 0; img_row < half; img_row++, cmat_row++) {
            for(int img_col = 0, cmat_col = 0; img_col < half; img_col++, cmat_col++) {
                double cmat_val = cmat[cmat_row][cmat_col];
                double[] data = { cmat_val, cmat_val, cmat_val };
                grayscale.put(img_row, img_col, data);
                temp.put(cmat_row, cmat_col, data);
            }
        }
        Highgui.imwrite(IMAGE_SOURCE_DIR + "temp_avrg_" + half + ".jpg", temp);
        temp.release();
    }


The method createScaledImageOf2DHWT() creates an image representation of applying the ordered forward 2D HWT for a given specific number of iterations.

public static void createScaledImageOf2DHWT(String infile, String outfile, int num_iters) {
        double[][] mat = getGrayscalePixMat(infile);
        int n = (int)(Math.log(mat.length)/Math.log(2));
        System.out.println("n == " + n);
       
        ArrayList<double[][]> transform = TwoDHaar.orderedForwardDWTForNumIters(mat, n, num_iters);
       
        double[][] lastAvrgMat = transform.remove(transform.size()-1);
        Mat grayscale = new Mat(mat.length, mat[0].length, CvType.CV_8UC1);

        int avrg_size = mat.length;
        for(int i = 0, mat_size = mat.length; i < transform.size(); i += 3, mat_size /= 2) {
            scaleSetHorMatValsInImage(grayscale, mat_size, transform.get(i));
            scaleVerMatValsInImage(grayscale, mat_size, transform.get(i+1));
            scaleDigMatValsInImage(grayscale, mat_size, transform.get(i+2));
            avrg_size /= 2;
        }
       
        setAvrgMatValsInImage(grayscale, 2*avrg_size, lastAvrgMat);
       
        Highgui.imwrite(IMAGE_SOURCE_DIR + outfile, grayscale);
        grayscale.release();
    }





Tests
  
Let us generate four images of applying 1, 2, 3, and 4 scales of the ordered forward 2D HWT to the image shown in Fig. 1 with the following calls.

createScaledImageOf2DHWT("ornament_02.jpg", "ornament_02_1_scale.jpg",  1);    // output shown in Fig. 2
createScaledImageOf2DHWT("ornament_02.jpg", "ornament_02_2_scales.jpg", 2);   // output shown in Fig. 3
createScaledImageOf2DHWT("ornament_02.jpg", "ornament_02_3_scales.jpg", 3);   //output shown in Fig. 4
createScaledImageOf2DHWT("ornament_02.jpg", "ornament_02_4_scales.jpg", 4);   //output shown in Fig. 5



Figure 1. ornament_02.jpg



Figure 2. ornament_02_1_scale.jpg
Figure 3. ornament_02_2_scales.jpg



Figure 4. ornament_02_3_scales.jpg
Figure 5. ornament_02_4_scales.jpg