What does dynamic range values in SSIM image quality technique refers and how to calculate?

71 Views Asked by At

http://en.wikipedia.org/wiki/Structural_similarity Below is java implementation of SSIM.

package com.ssim;

import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class SSIM {

    private static BufferedImage original1, original2;
    // REC 601 coefficients for standard def digital formats
    // http://en.wikipedia.org/wiki/Luma_(video)
    private static final float RED_COEFFICIENT = 0.212655f;
    private static final float GREEN_COEFFICIENT = 0.715158f;
    private static final float BLUE_COEFFICIENT = 0.072187f;

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub

        BufferedImage imgA = null;
        BufferedImage imgB = null;
        double sigxy, sigsqx, sigsqy;
        sigxy = sigsqx = sigsqy = 0f;
        double m1, m2;
        File fileA, fileB;
//      try {
        fileA = new File("E:\\java\\BECM9\\src\\com\\dataset\\cameraman.jpg");
        fileB = new File("E:\\java\\BECM9\\src\\com\\dataset\\cameraman_seg.jpg");

        imgA = ImageIO.read(fileA);
        imgB = ImageIO.read(fileB);
        /*
         * } catch (IOException e) { System.out.println(e); }
         */
        int width = imgA.getWidth();
        int height = imgA.getHeight();
        int width2 = imgB.getWidth();
        int height2 = imgB.getHeight();
        if (width != width2 || height != height2)
            System.out.println("Error: Images dimensions" + " mismatch");
        else {
            original1 = ImageIO.read(fileA);
            m1 = meanValue(original1);
            original2 = ImageIO.read(fileB);
            m2 = meanValue(original2);
            System.out.println("Mean value m1: " + m1);
            System.out.println("Mean value m2: " + m2);

            // calculating variance
            sigsqx = varianceValue(original1, m1);
            sigsqy = varianceValue(original2, m2);
            System.out.println("Variance value m1: " + sigsqx);
            System.out.println("Variance value m2: " + sigsqy);

            // calculating variance
            sigxy = sumVarValue(original1, original2, m1, m2);
            System.out.println("Sig xy value: " + sigxy);

            double avgLuma1, avgLuma2;
            avgLuma1 = calcLumaValues(original1);
            avgLuma2 = calcLumaValues(original2);
            double k1, k2, finalValue;
            System.out.println("Avg Luma 1: " + avgLuma1);
            System.out.println("Avg Luma 2: " + avgLuma2);
            k1 = Math.pow(0.01 * avgLuma1,2);
            k2 = Math.pow(0.03 * avgLuma2,2);
            finalValue = ((2 * m1 * m2 + k1) * (2 * sigxy + k2)) / 
                    (sigsqx + sigsqy + k2) * ((Math.pow(m1, 2) + Math.pow(m2,2) + k1));
            System.out.println("Final value: " + finalValue);

        }
    }

    public static double calcLumaValues(BufferedImage image) 
    {
        double lumaValues[], averageLuma;
        lumaValues = calculateLumaValuesForWindow(image);
        averageLuma = calculateAverageLuma(lumaValues);
        return averageLuma;

    }

    private static double calculateAverageLuma(double[] lumaValues) 
    {
        double sumLuma = 0.0f;
        for (int i = 0; i < lumaValues.length; i++) 
        {
            sumLuma += lumaValues[i];
        }

        return sumLuma / (double) lumaValues.length;
    }

    private static double[] calculateLumaValuesForWindow(BufferedImage image) 
    {
        final double[] lumaValues = new double[image.getHeight()
                * image.getWidth()];

        int counter = 0;
        for (int i = 0; i < 8; i++) 
        {
            for (int j = 0; j < 8; j++) 
            {
                final int rgb = image.getRGB(i, j);

                final int red = (rgb >> 16) & 0xFF;
                final int green = (rgb >> 8) & 0xFF;
                final int blue = rgb & 0xFF;

                final double Y = ((double) red * RED_COEFFICIENT)
                        +  ((double) green * GREEN_COEFFICIENT)
                        + ((double) blue * BLUE_COEFFICIENT);

                lumaValues[counter] = Y;
                counter++;
            }
        }

        return lumaValues;
    }


    public static double meanValue(BufferedImage image) {
        Raster raster = image.getRaster();
        double sum = 0.0;

        for (int y = 0; y < image.getHeight(); ++y) {
            for (int x = 0; x < image.getWidth(); ++x) {
                sum += raster.getSample(x, y, 0);
            }
        }
        return sum / (image.getWidth() * image.getHeight());
    }

    public static double varianceValue(BufferedImage image, double meanValue) {
        Raster raster = image.getRaster();
        double sum = 0.0;

        for (int y = 0; y < image.getHeight(); ++y) {
            for (int x = 0; x < image.getWidth(); ++x) {
                sum += Math.pow(raster.getSample(x, y, 0) - meanValue, 2);
            }
        }
        return sum / (image.getWidth() * image.getHeight() - 1);
    }

    public static double sumVarValue(BufferedImage image1, BufferedImage image2, double meanValue1, double meanValue2) {
        Raster raster1 = image1.getRaster();
        Raster raster2 = image2.getRaster();
        double sum = 0.0;

        for (int y = 0; y < image1.getHeight(); ++y) {
            for (int x = 0; x < image1.getWidth(); ++x) {
                sum += (raster1.getSample(x, y, 0) - meanValue1) * (raster2.getSample(x, y, 0) - meanValue2);
            }
        }
        return sum / (image1.getWidth() * image1.getHeight() - 1);
    }

}

According to this technique final value should be between -1 and 1. But I am getting 1.53 (approx.). I think there is problem with calculation of dynamic range (L). Where am I going wrong?