import numpy as np from PIL import Image def compare_image_quality(im1, im2): """ Computes the structural similarity index of two images im1 - original image im2 - optimized image (reduced quality) """ im1_mean = np.mean(im1) im2_mean = np.mean(im2) im1_var = np.var(im1) im2_var = np.var(im2) im1_var_sqrt = im1_var**0.5 im2_var_sqrt = im2_var**0.5 cross_cov = np.cov(im1.ravel(), im2.ravel()) C1, C2, C3 = 0,0,0 # adjust if needed return ((2 * im1_mean * im2_mean + C1) / (im1_mean**2 + im2_mean**2 + C1)) * (2 * im1_var_sqrt * im2_var_sqrt + C2) / (im1_var + im2_var + C2) + (cross_cov + C3) / (im1_var_sqrt * im2_var_sqrt + C3) images = ['football', 'parrot', 'egg_sandwiches'] for image in images: im1 = np.array(Image.open(image + '_original.jpg')) im2 = np.array(Image.open(image + '_optimized.jpg')) q = compare_image_quality(im1, im2) im1_quality, im2_quality = q[0,0], q[1,1] print('image1 quality: %f, image2 quality: %f' % (im1_quality, im2_quality)) """ image1 quality: 2.012567, image2 quality: 1.987406 image1 quality: 2.003812, image2 quality: 1.996174 image1 quality: 2.001005, image2 quality: 1.998995 """
The image2 versions were created through GIMP, exporting the original images at qualities 75, 75 and 95 percent respectively. The last example shows that at 95% quality, the structural similarity index is still able to detect a small negative difference. If we were to swap the positions of the images (that is, reduced quality image as first parameter and original image as second), this would swap the results at the end, which is convenient.
Comparing the indexes between images having different subjects is not useful with this method (for instance football and parrot here). The two images need to have the same dimensions. But we can use this method to validate the quality of the images we use on a website, for instance. Also look around for other implementations.