1

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?

janak
  • 11
  • Structural similarity should be between 0 and 1, no? Also math SE is not a site where people seem so keen on searching for bugs, maybe you can try hmm, signal processing SE or computational science SE or some third. – mathreadler Nov 15 '19 at 17:32
  • Quoting from aforementioned link: In order to evaluate the image quality, this formula is usually applied only on luma, although it may also be applied on color (e.g., RGB) values or chromatic (e.g. YCbCr) values. The resultant SSIM index is a decimal value between -1 and 1, and value 1 is only reachable in the case of two identical sets of data and therefore indicates perfect structural similarity. – janak Nov 15 '19 at 17:52
  • Never heard of this, any link or citation to people who actually use this color version of SSIM in a research paper? – mathreadler Nov 15 '19 at 18:43

0 Answers0