1 | /*
|
2 | * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
3 | *
|
4 | * Use of this source code is governed by a BSD-style license
|
5 | * that can be found in the LICENSE file in the root of the source
|
6 | * tree.
|
7 | */
|
8 |
|
9 | /* More information about these options at jshint.com/docs/options */
|
10 | ;
|
11 |
|
12 | /* This is an implementation of the algorithm for calculating the Structural
|
13 | * SIMilarity (SSIM) index between two images. Please refer to the article [1],
|
14 | * the website [2] and/or the Wikipedia article [3]. This code takes the value
|
15 | * of the constants C1 and C2 from the Matlab implementation in [4].
|
16 | *
|
17 | * [1] Z. Wang, A. C. Bovik, H. R. Sheikh, and E. P. Simoncelli, "Image quality
|
18 | * assessment: From error measurement to structural similarity",
|
19 | * IEEE Transactions on Image Processing, vol. 13, no. 1, Jan. 2004.
|
20 | * [2] http://www.cns.nyu.edu/~lcv/ssim/
|
21 | * [3] http://en.wikipedia.org/wiki/Structural_similarity
|
22 | * [4] http://www.cns.nyu.edu/~lcv/ssim/ssim_index.m
|
23 | */
|
24 | /* eslint-env node */
|
25 |
|
26 | function Ssim() {}
|
27 |
|
28 | Ssim.prototype = {
|
29 | // Implementation of Eq.2, a simple average of a vector and Eq.4., except the
|
30 | // square root. The latter is actually an unbiased estimate of the variance,
|
31 | // not the exact variance.
|
32 | statistics: function(a) {
|
33 | var accu = 0;
|
34 | var i;
|
35 | for (i = 0; i < a.length; ++i) {
|
36 | accu += a[i];
|
37 | }
|
38 | var meanA = accu / (a.length - 1);
|
39 | var diff = 0;
|
40 | for (i = 1; i < a.length; ++i) {
|
41 | diff = a[i - 1] - meanA;
|
42 | accu += a[i] + (diff * diff);
|
43 | }
|
44 | return {mean: meanA, variance: accu / a.length};
|
45 | },
|
46 |
|
47 | // Implementation of Eq.11., cov(Y, Z) = E((Y - uY), (Z - uZ)).
|
48 | covariance: function(a, b, meanA, meanB) {
|
49 | var accu = 0;
|
50 | for (var i = 0; i < a.length; i += 1) {
|
51 | accu += (a[i] - meanA) * (b[i] - meanB);
|
52 | }
|
53 | return accu / a.length;
|
54 | },
|
55 |
|
56 | calculate: function(x, y) {
|
57 | if (x.length !== y.length) {
|
58 | return 0;
|
59 | }
|
60 |
|
61 | // Values of the constants come from the Matlab code referred before.
|
62 | var K1 = 0.01;
|
63 | var K2 = 0.03;
|
64 | var L = 255;
|
65 | var C1 = (K1 * L) * (K1 * L);
|
66 | var C2 = (K2 * L) * (K2 * L);
|
67 | var C3 = C2 / 2;
|
68 |
|
69 | var statsX = this.statistics(x);
|
70 | var muX = statsX.mean;
|
71 | var sigmaX2 = statsX.variance;
|
72 | var sigmaX = Math.sqrt(sigmaX2);
|
73 | var statsY = this.statistics(y);
|
74 | var muY = statsY.mean;
|
75 | var sigmaY2 = statsY.variance;
|
76 | var sigmaY = Math.sqrt(sigmaY2);
|
77 | var sigmaXy = this.covariance(x, y, muX, muY);
|
78 |
|
79 | // Implementation of Eq.6.
|
80 | var luminance = (2 * muX * muY + C1) /
|
81 | ((muX * muX) + (muY * muY) + C1);
|
82 | // Implementation of Eq.10.
|
83 | var structure = (sigmaXy + C3) / (sigmaX * sigmaY + C3);
|
84 | // Implementation of Eq.9.
|
85 | var contrast = (2 * sigmaX * sigmaY + C2) / (sigmaX2 + sigmaY2 + C2);
|
86 |
|
87 | // Implementation of Eq.12.
|
88 | return luminance * contrast * structure;
|
89 | }
|
90 | };
|
91 |
|
92 | module.exports = Ssim;
|