17bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola/* 27bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 37bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola * 47bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola * Use of this source code is governed by a BSD-style license 57bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola * that can be found in the LICENSE file in the root of the source 67bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola * tree. An additional intellectual property rights grant can be found 77bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola * in the file PATENTS. All contributing project authors may 87bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola * be found in the AUTHORS file in the root of the source tree. 97bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola */ 107bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 117bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 127bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#include "vpx_scale/yv12config.h" 137bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#include "math.h" 147bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#include "onyx_int.h" 157bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 167bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#if CONFIG_RUNTIME_CPU_DETECT 177bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#define IF_RTCD(x) (x) 187bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#else 197bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#define IF_RTCD(x) NULL 207bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#endif 217bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola// Google version of SSIM 227bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola// SSIM 237bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#define KERNEL 3 247bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola#define KERNEL_SIZE (2 * KERNEL + 1) 25563321a2582851c653d0863e8e0bba3d483734f9Jim Laskey 26b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindolatypedef unsigned char uint8; 277bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindolatypedef unsigned int uint32; 287bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 297bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindolastatic const int K[KERNEL_SIZE] = 307bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola{ 317bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 1, 4, 11, 16, 11, 4, 1 // 16 * exp(-0.3 * i * i) 327bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola}; 337bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindolastatic const double ki_w = 1. / 2304.; // 1 / sum(i:0..6, j..6) K[i]*K[j] 347bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindoladouble get_ssimg(const uint8 *org, const uint8 *rec, 357bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola int xo, int yo, int W, int H, 367bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const int stride1, const int stride2 37ac0b6ae358944ae8b2b5a11dc08f52c3ed89f2daChris Lattner ) 387bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola{ 39e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola // TODO(skal): use summed tables 40e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola int y, x; 41e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola 42e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola const int ymin = (yo - KERNEL < 0) ? 0 : yo - KERNEL; 43e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola const int ymax = (yo + KERNEL > H - 1) ? H - 1 : yo + KERNEL; 44e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola const int xmin = (xo - KERNEL < 0) ? 0 : xo - KERNEL; 45e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola const int xmax = (xo + KERNEL > W - 1) ? W - 1 : xo + KERNEL; 46e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola // worst case of accumulation is a weight of 48 = 16 + 2 * (11 + 4 + 1) 47e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola // with a diff of 255, squares. That would a max error of 0x8ee0900, 48e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola // which fits into 32 bits integers. 49e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola uint32 w = 0, xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; 50e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola org += ymin * stride1; 51e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola rec += ymin * stride2; 52e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola 53e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola for (y = ymin; y <= ymax; ++y, org += stride1, rec += stride2) 54e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola { 55e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola const int Wy = K[KERNEL + y - yo]; 56e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola 57e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola for (x = xmin; x <= xmax; ++x) 58e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola { 59e931a37a4eb3e46d73ab0379dd84173dca1214f2Rafael Espindola const int Wxy = Wy * K[KERNEL + x - xo]; 60563321a2582851c653d0863e8e0bba3d483734f9Jim Laskey // TODO(skal): inlined assembly 61a0f3d17daac73c9c71aad497b298cbe82848f726Jim Laskey w += Wxy; 62563321a2582851c653d0863e8e0bba3d483734f9Jim Laskey xm += Wxy * org[x]; 63563321a2582851c653d0863e8e0bba3d483734f9Jim Laskey ym += Wxy * rec[x]; 647bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola xxm += Wxy * org[x] * org[x]; 65392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola xym += Wxy * org[x] * rec[x]; 66392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola yym += Wxy * rec[x] * rec[x]; 677bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 687bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 697bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 707bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola { 717bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double iw = 1. / w; 727bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double iwx = xm * iw; 737bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double iwy = ym * iw; 747bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola double sxx = xxm * iw - iwx * iwx; 757bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola double syy = yym * iw - iwy * iwy; 767bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 777bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola // small errors are possible, due to rounding. Clamp to zero. 787cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola if (sxx < 0.) sxx = 0.; 796e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola 8032bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola if (syy < 0.) syy = 0.; 817bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 827bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola { 837bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double sxsy = sqrt(sxx * syy); 847bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double sxy = xym * iw - iwx * iwy; 857bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola static const double C11 = (0.01 * 0.01) * (255 * 255); 867bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola static const double C22 = (0.03 * 0.03) * (255 * 255); 877bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola static const double C33 = (0.015 * 0.015) * (255 * 255); 887bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double l = (2. * iwx * iwy + C11) / (iwx * iwx + iwy * iwy + C11); 897bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double c = (2. * sxsy + C22) / (sxx + syy + C22); 907bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 917bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const double s = (sxy + C33) / (sxsy + C33); 927bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola return l * c * s; 937bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 947bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 957bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 967bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 977bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola} 987bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola 997bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindoladouble get_ssimfull_kernelg(const uint8 *org, const uint8 *rec, 1007bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola int xo, int yo, int W, int H, 1017bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola const int stride1, const int stride2) 102a0f3d17daac73c9c71aad497b298cbe82848f726Jim Laskey{ 1037bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola // TODO(skal): use summed tables 1047bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola // worst case of accumulation is a weight of 48 = 16 + 2 * (11 + 4 + 1) 1057bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola // with a diff of 255, squares. That would a max error of 0x8ee0900, 1067bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola // which fits into 32 bits integers. 1077bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola int y_, x_; 1087bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola uint32 xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; 1094b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola org += (yo - KERNEL) * stride1; 1104b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola org += (xo - KERNEL); 1114b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola rec += (yo - KERNEL) * stride2; 1124b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola rec += (xo - KERNEL); 1134b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola 1144b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola for (y_ = 0; y_ < KERNEL_SIZE; ++y_, org += stride1, rec += stride2) 1154b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola { 1161da31ee472b9615d7329c656e2cc17c419ed7c95Chris Lattner const int Wy = K[y_]; 1174b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola 1184b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola for (x_ = 0; x_ < KERNEL_SIZE; ++x_) 1194b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola { 1206f6f69950f5a36d3ae7e4d1d5b96fda204beb79aChris Lattner const int Wxy = Wy * K[x_]; 1216f6f69950f5a36d3ae7e4d1d5b96fda204beb79aChris Lattner // TODO(skal): inlined assembly 1224b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const int org_x = org[x_]; 1234b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const int rec_x = rec[x_]; 1244b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola xm += Wxy * org_x; 1254b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola ym += Wxy * rec_x; 1264b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola xxm += Wxy * org_x * org_x; 1274b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola xym += Wxy * org_x * rec_x; 1284b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola yym += Wxy * rec_x * rec_x; 1294b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola } 1304b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola } 131392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola 1324b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola { 1334b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const double iw = ki_w; 134a1334cdfb2afb44a1f2b952391e1b2fecb1d4bd8Rafael Espindola const double iwx = xm * iw; 1354b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const double iwy = ym * iw; 1364b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola double sxx = xxm * iw - iwx * iwx; 1374b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola double syy = yym * iw - iwy * iwy; 1384b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola 1394b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola // small errors are possible, due to rounding. Clamp to zero. 1404b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola if (sxx < 0.) sxx = 0.; 1414b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola 1424b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola if (syy < 0.) syy = 0.; 1434b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola 1444b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola { 1454b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const double sxsy = sqrt(sxx * syy); 1464b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const double sxy = xym * iw - iwx * iwy; 1474b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola static const double C11 = (0.01 * 0.01) * (255 * 255); 1484b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola static const double C22 = (0.03 * 0.03) * (255 * 255); 1494b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola static const double C33 = (0.015 * 0.015) * (255 * 255); 1504b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const double l = (2. * iwx * iwy + C11) / (iwx * iwx + iwy * iwy + C11); 1514b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const double c = (2. * sxsy + C22) / (sxx + syy + C22); 1524b442b528a50ef06cd75f0e7c41ad57426175bccRafael Espindola const double s = (sxy + C33) / (sxsy + C33); 1537bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola return l * c * s; 1547bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 1557bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 1567cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola} 1573ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola 1583ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindoladouble calc_ssimg(const uint8 *org, const uint8 *rec, 1593ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola const int image_width, const int image_height, 1607cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola const int stride1, const int stride2 1613ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola ) 1623ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola{ 1637cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola int j, i; 1647cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola double SSIM = 0.; 1653ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola 1667cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola for (j = 0; j < KERNEL; ++j) 1673ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola { 1683ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola for (i = 0; i < image_width; ++i) 1693ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola { 1703ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 1713ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola } 1723ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola } 1733ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola 1743ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola for (j = KERNEL; j < image_height - KERNEL; ++j) 1753ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola { 1763ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola for (i = 0; i < KERNEL; ++i) 1773ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola { 1783ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 1793ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola } 1803ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola 1813ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola for (i = KERNEL; i < image_width - KERNEL; ++i) 1823ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola { 1833ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola SSIM += get_ssimfull_kernelg(org, rec, i, j, 1843ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola image_width, image_height, stride1, stride2); 1853ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola } 1863ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola 1873ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola for (i = image_width - KERNEL; i < image_width; ++i) 1883ad5e5cf998841681e9d11e08eb82a94ddffd1f8Rafael Espindola { 1897cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 1907cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola } 1917cca7c531773f763c1bddc3fefecc99ba56ed10aRafael Espindola } 1926e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola 1936e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola for (j = image_height - KERNEL; j < image_height; ++j) 1946e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola { 1956e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola for (i = 0; i < image_width; ++i) 1966e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola { 1976e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 1986e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola } 1996e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola } 2006e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola 2016e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola return SSIM; 2026e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola} 2036e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola 2046e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola 2056e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindoladouble vp8_calc_ssimg 2066e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola( 2076e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola YV12_BUFFER_CONFIG *source, 2086e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola YV12_BUFFER_CONFIG *dest, 2096e8c6493f0db238d06549368bd647e29ff3c7821Rafael Espindola double *ssim_y, 21032bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola double *ssim_u, 21132bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola double *ssim_v 21232bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola) 21332bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola{ 21432bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola double ssim_all = 0; 21532bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola int ysize = source->y_width * source->y_height; 21632bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola int uvsize = ysize / 4; 21732bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola 21832bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola *ssim_y = calc_ssimg(source->y_buffer, dest->y_buffer, 21932bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola source->y_width, source->y_height, 22032bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola source->y_stride, dest->y_stride); 22132bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola 22232bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola 22332bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola *ssim_u = calc_ssimg(source->u_buffer, dest->u_buffer, 22432bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola source->uv_width, source->uv_height, 22532bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola source->uv_stride, dest->uv_stride); 22632bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola 22732bd5f4f6a374f9ab0fcbd2cf6a8561019a6fd56Rafael Espindola 2287bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola *ssim_v = calc_ssimg(source->v_buffer, dest->v_buffer, 2292f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola source->uv_width, source->uv_height, 2302f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola source->uv_stride, dest->uv_stride); 2312f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola 2322f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola ssim_all = (*ssim_y + *ssim_u + *ssim_v) / (ysize + uvsize + uvsize); 2332f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola *ssim_y /= ysize; 2342f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola *ssim_u /= uvsize; 2352f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola *ssim_v /= uvsize; 2362f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola return ssim_all; 2372f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola} 2382f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola 2392f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola 2402f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindolavoid ssim_parms_c 2412f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola( 242687bc49d1ada3fe0a2cd3fb5c044f12d267f259fRafael Espindola unsigned char *s, 2432f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola int sp, 24484b19be6ab9544f72eafb11048a1121f5ea77c95Rafael Espindola unsigned char *r, 24584b19be6ab9544f72eafb11048a1121f5ea77c95Rafael Espindola int rp, 24684b19be6ab9544f72eafb11048a1121f5ea77c95Rafael Espindola unsigned long *sum_s, 24784b19be6ab9544f72eafb11048a1121f5ea77c95Rafael Espindola unsigned long *sum_r, 248392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola unsigned long *sum_sq_s, 249392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola unsigned long *sum_sq_r, 250392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola unsigned long *sum_sxr 25184b19be6ab9544f72eafb11048a1121f5ea77c95Rafael Espindola) 2522f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola{ 2532f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola int i,j; 2540505be03adf561afbd8307516125da10dba8f0c4Rafael Espindola for(i=0;i<16;i++,s+=sp,r+=rp) 2552f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola { 2562f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola for(j=0;j<16;j++) 257563321a2582851c653d0863e8e0bba3d483734f9Jim Laskey { 25806c1e7eacb11edd1671eabfc11291b7716be2608Rafael Espindola *sum_s += s[j]; 2592f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola *sum_r += r[j]; 2602f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola *sum_sq_s += s[j] * s[j]; 2612f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola *sum_sq_r += r[j] * r[j]; 2622f99b6bd9601ae8d4fd248f9bb701283795c38a8Rafael Espindola *sum_sxr += s[j] * r[j]; 2637bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 2647bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola } 2657bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola} 2667bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindolavoid ssim_parms_8x8_c 2677bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola( 2687bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola unsigned char *s, 2697bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola int sp, 2707bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola unsigned char *r, 2716f602de3b68cc63d12554ad6ae3c98a4c436c32dRafael Espindola int rp, 2726f602de3b68cc63d12554ad6ae3c98a4c436c32dRafael Espindola unsigned long *sum_s, 2737bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola unsigned long *sum_r, 2747bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola unsigned long *sum_sq_s, 2757bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola unsigned long *sum_sq_r, 276ff59d22232f47f138ed3d753975153befd1aa0c0Rafael Espindola unsigned long *sum_sxr 2777bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola) 2787bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola{ 2797bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola int i,j; 2807bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola for(i=0;i<8;i++,s+=sp,r+=rp) 281b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola { 282b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola for(j=0;j<8;j++) 283b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola { 284b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola *sum_s += s[j]; 285b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola *sum_r += r[j]; 286b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola *sum_sq_s += s[j] * s[j]; 287b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola *sum_sq_r += r[j] * r[j]; 288b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola *sum_sxr += s[j] * r[j]; 289b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola } 290b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola } 291b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola} 292b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola 293b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindolaconst static long long c1 = 426148; // (256^2*(.01*255)^2 294b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindolaconst static long long c2 = 3835331; //(256^2*(.03*255)^2 2951c411dee4f406e33d70666898f62ab9ba23bb73dRafael Espindola 296b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindolastatic double similarity 297b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola( 2987367d05cb713d11f8ac1e0815ac6b2eb6b17088cRafael Espindola unsigned long sum_s, 299b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola unsigned long sum_r, 300b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola unsigned long sum_sq_s, 301b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola unsigned long sum_sq_r, 302b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola unsigned long sum_sxr, 303b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola int count 304b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola) 3051c411dee4f406e33d70666898f62ab9ba23bb73dRafael Espindola{ 3061c411dee4f406e33d70666898f62ab9ba23bb73dRafael Espindola long long ssim_n = (2*sum_s*sum_r+ c1)*(2*count*sum_sxr-2*sum_s*sum_r+c2); 307b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola 308b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola long long ssim_d = (sum_s*sum_s +sum_r*sum_r+c1)* 309b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola (count*sum_sq_s-sum_s*sum_s + count*sum_sq_r-sum_r*sum_r +c2) ; 310b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola 311b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola return ssim_n * 1.0 / ssim_d; 312b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola} 313b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola 314b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindolastatic double ssim_16x16(unsigned char *s,int sp, unsigned char *r,int rp, 315b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola const vp8_variance_rtcd_vtable_t *rtcd) 316b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola{ 317b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; 318b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola rtcd->ssimpf(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); 319b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 256); 3201366626e08322aaecd60704d02a5d881b0826725Rafael Espindola} 3211366626e08322aaecd60704d02a5d881b0826725Rafael Espindolastatic double ssim_8x8(unsigned char *s,int sp, unsigned char *r,int rp, 3221366626e08322aaecd60704d02a5d881b0826725Rafael Espindola const vp8_variance_rtcd_vtable_t *rtcd) 3231366626e08322aaecd60704d02a5d881b0826725Rafael Espindola{ 3241366626e08322aaecd60704d02a5d881b0826725Rafael Espindola unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; 3251366626e08322aaecd60704d02a5d881b0826725Rafael Espindola rtcd->ssimpf_8x8(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); 3261366626e08322aaecd60704d02a5d881b0826725Rafael Espindola return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64); 3271366626e08322aaecd60704d02a5d881b0826725Rafael Espindola} 3281366626e08322aaecd60704d02a5d881b0826725Rafael Espindola 3291366626e08322aaecd60704d02a5d881b0826725Rafael Espindola// TODO: (jbb) tried to scale this function such that we may be able to use it 3301366626e08322aaecd60704d02a5d881b0826725Rafael Espindola// for distortion metric in mode selection code ( provided we do a reconstruction) 331b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindolalong dssim(unsigned char *s,int sp, unsigned char *r,int rp, 332b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola const vp8_variance_rtcd_vtable_t *rtcd) 333b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola{ 334b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; 335b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola double ssim3; 336b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola long long ssim_n; 337b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola long long ssim_d; 338b01c4bbb4573e0007444e218b683840e4519e0c8Rafael Espindola 339b97809c9a7a4ef681070ab1cbc7bd4fb18d34ba1Rafael Espindola rtcd->ssimpf(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); 340392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola ssim_n = (2*sum_s*sum_r+ c1)*(2*256*sum_sxr-2*sum_s*sum_r+c2); 341392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola 342392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola ssim_d = (sum_s*sum_s +sum_r*sum_r+c1)* 343392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola (256*sum_sq_s-sum_s*sum_s + 256*sum_sq_r-sum_r*sum_r +c2) ; 344392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola 345392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola ssim3 = 256 * (ssim_d-ssim_n) / ssim_d; 346392b1b2ef3ace82b5104ba4c9280fc7957c669d4Rafael Espindola return (long)( 256*ssim3 * ssim3 ); 3477bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola} 3487bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola// TODO: (jbb) this 8x8 window might be too big + we may want to pick pixels 3497bc59bc3952ad7842b1e079753deb32217a768a3Rafael Espindola// such that the window regions overlap block boundaries to penalize blocking 350// artifacts. 351 352double vp8_ssim2 353( 354 unsigned char *img1, 355 unsigned char *img2, 356 int stride_img1, 357 int stride_img2, 358 int width, 359 int height, 360 const vp8_variance_rtcd_vtable_t *rtcd 361) 362{ 363 int i,j; 364 365 double ssim_total=0; 366 367 // we can sample points as frequently as we like start with 1 per 8x8 368 for(i=0; i < height; i+=8, img1 += stride_img1*8, img2 += stride_img2*8) 369 { 370 for(j=0; j < width; j+=8 ) 371 { 372 ssim_total += ssim_8x8(img1, stride_img1, img2, stride_img2, rtcd); 373 } 374 } 375 ssim_total /= (width/8 * height /8); 376 return ssim_total; 377 378} 379double vp8_calc_ssim 380( 381 YV12_BUFFER_CONFIG *source, 382 YV12_BUFFER_CONFIG *dest, 383 int lumamask, 384 double *weight, 385 const vp8_variance_rtcd_vtable_t *rtcd 386) 387{ 388 double a, b, c; 389 double ssimv; 390 391 a = vp8_ssim2(source->y_buffer, dest->y_buffer, 392 source->y_stride, dest->y_stride, source->y_width, 393 source->y_height, rtcd); 394 395 b = vp8_ssim2(source->u_buffer, dest->u_buffer, 396 source->uv_stride, dest->uv_stride, source->uv_width, 397 source->uv_height, rtcd); 398 399 c = vp8_ssim2(source->v_buffer, dest->v_buffer, 400 source->uv_stride, dest->uv_stride, source->uv_width, 401 source->uv_height, rtcd); 402 403 ssimv = a * .8 + .1 * (b + c); 404 405 *weight = 1; 406 407 return ssimv; 408} 409