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?