-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSSIM_Index.py
105 lines (81 loc) · 3.09 KB
/
SSIM_Index.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
__author__ = 'Helder C. R. de Oliveira'
__email__ = '[email protected]'
__url__ = 'http://helderc.net'
"""
This is an improved implementation of SSIM, based on version of:
Antoine Vacavant, ISIT lab, [email protected],
http://isit.u-clermont1.fr/~anvacava
References:
[1] Z. Wang, A. C. Bovik, H. R. Sheikh and E. P. Simoncelli.
Image quality assessment: From error visibility to structural similarity.
IEEE Transactions on Image Processing, 13(4):600--612, 2004.
[2] Z. Wang and A. C. Bovik.
Mean squared error: Love it or leave it? - A new look at signal fidelity measures.
IEEE Signal Processing Magazine, 26(1):98--117, 2009.
"""
import numpy as np
import scipy.ndimage
def compute_ssim(im1, im2, l=255):
# k1,k2 & c1,c2 depend on L (width of color map)
k_1 = 0.01
c_1 = (k_1 * l)**2
k_2 = 0.03
c_2 = (k_2 * l)**2
# window = np.ones((8, 8))
window = gauss_2d((11, 11), 1.5)
# Normalization
# window /= np.sum(window)
# Convert image matrices to double precision (like in the Matlab version)
im1 = im1.astype(np.float)
im2 = im2.astype(np.float)
# Means obtained by Gaussian filtering of inputs
mu_1 = scipy.ndimage.filters.convolve(im1, window)
mu_2 = scipy.ndimage.filters.convolve(im2, window)
# Squares of means
mu_1_sq = mu_1**2
mu_2_sq = mu_2**2
mu_1_mu_2 = mu_1 * mu_2
# Squares of input matrices
im1_sq = im1**2
im2_sq = im2**2
im12 = im1 * im2
# Variances obtained by Gaussian filtering of inputs' squares
sigma_1_sq = scipy.ndimage.filters.convolve(im1_sq, window)
sigma_2_sq = scipy.ndimage.filters.convolve(im2_sq, window)
# Covariance
sigma_12 = scipy.ndimage.filters.convolve(im12, window)
# Centered squares of variances
sigma_1_sq -= mu_1_sq
sigma_2_sq -= mu_2_sq
sigma_12 -= mu_1_mu_2
if (c_1 > 0) & (c_2 > 0):
ssim_map = ((2 * mu_1_mu_2 + c_1) * (2 * sigma_12 + c_2)) / \
((mu_1_sq + mu_2_sq + c_1) * (sigma_1_sq + sigma_2_sq + c_2))
else:
numerator1 = 2 * mu_1_mu_2 + c_1
numerator2 = 2 * sigma_12 + c_2
denominator1 = mu_1_sq + mu_2_sq + c_1
denominator2 = sigma_1_sq + sigma_2_sq + c_2
ssim_map = np.ones(mu_1.size)
index = (denominator1 * denominator2 > 0)
ssim_map[index] = (numerator1[index] * numerator2[index]) / \
(denominator1[index] * denominator2[index])
index = (denominator1 != 0) & (denominator2 == 0)
ssim_map[index] = numerator1[index] / denominator1[index]
# return MSSIM
index = np.mean(ssim_map)
return index
def gauss_2d(shape=(3, 3), sigma=0.5):
"""
Code from Stack Overflow's thread
2D gaussian mask - should give the same result as MATLAB's
fspecial('gaussian',[shape],[sigma])
"""
m, n = [(ss - 1.) / 2. for ss in shape]
y, x = np.ogrid[-m:m + 1, -n:n + 1]
h = np.exp(-(x * x + y * y) / (2. * sigma * sigma))
h[h < np.finfo(h.dtype).eps * h.max()] = 0
sumh = h.sum()
if sumh != 0:
h /= sumh
return h