11b362b15af34006e6a11974088a46d42b903418eJohann/* 21b362b15af34006e6a11974088a46d42b903418eJohann * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 31b362b15af34006e6a11974088a46d42b903418eJohann * 41b362b15af34006e6a11974088a46d42b903418eJohann * Use of this source code is governed by a BSD-style license 51b362b15af34006e6a11974088a46d42b903418eJohann * that can be found in the LICENSE file in the root of the source 61b362b15af34006e6a11974088a46d42b903418eJohann * tree. An additional intellectual property rights grant can be found 71b362b15af34006e6a11974088a46d42b903418eJohann * in the file PATENTS. All contributing project authors may 81b362b15af34006e6a11974088a46d42b903418eJohann * be found in the AUTHORS file in the root of the source tree. 91b362b15af34006e6a11974088a46d42b903418eJohann */ 101b362b15af34006e6a11974088a46d42b903418eJohann 111b362b15af34006e6a11974088a46d42b903418eJohann 121b362b15af34006e6a11974088a46d42b903418eJohann#include "onyx_int.h" 131b362b15af34006e6a11974088a46d42b903418eJohann 141b362b15af34006e6a11974088a46d42b903418eJohannvoid vp8_ssim_parms_16x16_c 151b362b15af34006e6a11974088a46d42b903418eJohann( 161b362b15af34006e6a11974088a46d42b903418eJohann unsigned char *s, 171b362b15af34006e6a11974088a46d42b903418eJohann int sp, 181b362b15af34006e6a11974088a46d42b903418eJohann unsigned char *r, 191b362b15af34006e6a11974088a46d42b903418eJohann int rp, 201b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_s, 211b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_r, 221b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_sq_s, 231b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_sq_r, 241b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_sxr 251b362b15af34006e6a11974088a46d42b903418eJohann) 261b362b15af34006e6a11974088a46d42b903418eJohann{ 271b362b15af34006e6a11974088a46d42b903418eJohann int i,j; 281b362b15af34006e6a11974088a46d42b903418eJohann for(i=0;i<16;i++,s+=sp,r+=rp) 291b362b15af34006e6a11974088a46d42b903418eJohann { 301b362b15af34006e6a11974088a46d42b903418eJohann for(j=0;j<16;j++) 311b362b15af34006e6a11974088a46d42b903418eJohann { 321b362b15af34006e6a11974088a46d42b903418eJohann *sum_s += s[j]; 331b362b15af34006e6a11974088a46d42b903418eJohann *sum_r += r[j]; 341b362b15af34006e6a11974088a46d42b903418eJohann *sum_sq_s += s[j] * s[j]; 351b362b15af34006e6a11974088a46d42b903418eJohann *sum_sq_r += r[j] * r[j]; 361b362b15af34006e6a11974088a46d42b903418eJohann *sum_sxr += s[j] * r[j]; 371b362b15af34006e6a11974088a46d42b903418eJohann } 381b362b15af34006e6a11974088a46d42b903418eJohann } 391b362b15af34006e6a11974088a46d42b903418eJohann} 401b362b15af34006e6a11974088a46d42b903418eJohannvoid vp8_ssim_parms_8x8_c 411b362b15af34006e6a11974088a46d42b903418eJohann( 421b362b15af34006e6a11974088a46d42b903418eJohann unsigned char *s, 431b362b15af34006e6a11974088a46d42b903418eJohann int sp, 441b362b15af34006e6a11974088a46d42b903418eJohann unsigned char *r, 451b362b15af34006e6a11974088a46d42b903418eJohann int rp, 461b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_s, 471b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_r, 481b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_sq_s, 491b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_sq_r, 501b362b15af34006e6a11974088a46d42b903418eJohann unsigned long *sum_sxr 511b362b15af34006e6a11974088a46d42b903418eJohann) 521b362b15af34006e6a11974088a46d42b903418eJohann{ 531b362b15af34006e6a11974088a46d42b903418eJohann int i,j; 541b362b15af34006e6a11974088a46d42b903418eJohann for(i=0;i<8;i++,s+=sp,r+=rp) 551b362b15af34006e6a11974088a46d42b903418eJohann { 561b362b15af34006e6a11974088a46d42b903418eJohann for(j=0;j<8;j++) 571b362b15af34006e6a11974088a46d42b903418eJohann { 581b362b15af34006e6a11974088a46d42b903418eJohann *sum_s += s[j]; 591b362b15af34006e6a11974088a46d42b903418eJohann *sum_r += r[j]; 601b362b15af34006e6a11974088a46d42b903418eJohann *sum_sq_s += s[j] * s[j]; 611b362b15af34006e6a11974088a46d42b903418eJohann *sum_sq_r += r[j] * r[j]; 621b362b15af34006e6a11974088a46d42b903418eJohann *sum_sxr += s[j] * r[j]; 631b362b15af34006e6a11974088a46d42b903418eJohann } 641b362b15af34006e6a11974088a46d42b903418eJohann } 651b362b15af34006e6a11974088a46d42b903418eJohann} 661b362b15af34006e6a11974088a46d42b903418eJohann 671b362b15af34006e6a11974088a46d42b903418eJohannconst static int64_t cc1 = 26634; // (64^2*(.01*255)^2 681b362b15af34006e6a11974088a46d42b903418eJohannconst static int64_t cc2 = 239708; // (64^2*(.03*255)^2 691b362b15af34006e6a11974088a46d42b903418eJohann 701b362b15af34006e6a11974088a46d42b903418eJohannstatic double similarity 711b362b15af34006e6a11974088a46d42b903418eJohann( 721b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_s, 731b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_r, 741b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_sq_s, 751b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_sq_r, 761b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_sxr, 771b362b15af34006e6a11974088a46d42b903418eJohann int count 781b362b15af34006e6a11974088a46d42b903418eJohann) 791b362b15af34006e6a11974088a46d42b903418eJohann{ 801b362b15af34006e6a11974088a46d42b903418eJohann int64_t ssim_n, ssim_d; 811b362b15af34006e6a11974088a46d42b903418eJohann int64_t c1, c2; 821b362b15af34006e6a11974088a46d42b903418eJohann 831b362b15af34006e6a11974088a46d42b903418eJohann //scale the constants by number of pixels 841b362b15af34006e6a11974088a46d42b903418eJohann c1 = (cc1*count*count)>>12; 851b362b15af34006e6a11974088a46d42b903418eJohann c2 = (cc2*count*count)>>12; 861b362b15af34006e6a11974088a46d42b903418eJohann 871b362b15af34006e6a11974088a46d42b903418eJohann ssim_n = (2*sum_s*sum_r+ c1)*((int64_t) 2*count*sum_sxr- 881b362b15af34006e6a11974088a46d42b903418eJohann (int64_t) 2*sum_s*sum_r+c2); 891b362b15af34006e6a11974088a46d42b903418eJohann 901b362b15af34006e6a11974088a46d42b903418eJohann ssim_d = (sum_s*sum_s +sum_r*sum_r+c1)* 911b362b15af34006e6a11974088a46d42b903418eJohann ((int64_t)count*sum_sq_s-(int64_t)sum_s*sum_s + 921b362b15af34006e6a11974088a46d42b903418eJohann (int64_t)count*sum_sq_r-(int64_t) sum_r*sum_r +c2) ; 931b362b15af34006e6a11974088a46d42b903418eJohann 941b362b15af34006e6a11974088a46d42b903418eJohann return ssim_n * 1.0 / ssim_d; 951b362b15af34006e6a11974088a46d42b903418eJohann} 961b362b15af34006e6a11974088a46d42b903418eJohann 971b362b15af34006e6a11974088a46d42b903418eJohannstatic double ssim_16x16(unsigned char *s,int sp, unsigned char *r,int rp) 981b362b15af34006e6a11974088a46d42b903418eJohann{ 991b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; 1001b362b15af34006e6a11974088a46d42b903418eJohann vp8_ssim_parms_16x16(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); 1011b362b15af34006e6a11974088a46d42b903418eJohann return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 256); 1021b362b15af34006e6a11974088a46d42b903418eJohann} 1031b362b15af34006e6a11974088a46d42b903418eJohannstatic double ssim_8x8(unsigned char *s,int sp, unsigned char *r,int rp) 1041b362b15af34006e6a11974088a46d42b903418eJohann{ 1051b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; 1061b362b15af34006e6a11974088a46d42b903418eJohann vp8_ssim_parms_8x8(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); 1071b362b15af34006e6a11974088a46d42b903418eJohann return similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, 64); 1081b362b15af34006e6a11974088a46d42b903418eJohann} 1091b362b15af34006e6a11974088a46d42b903418eJohann 1101b362b15af34006e6a11974088a46d42b903418eJohann// TODO: (jbb) tried to scale this function such that we may be able to use it 1111b362b15af34006e6a11974088a46d42b903418eJohann// for distortion metric in mode selection code ( provided we do a reconstruction) 1121b362b15af34006e6a11974088a46d42b903418eJohannlong dssim(unsigned char *s,int sp, unsigned char *r,int rp) 1131b362b15af34006e6a11974088a46d42b903418eJohann{ 1141b362b15af34006e6a11974088a46d42b903418eJohann unsigned long sum_s=0,sum_r=0,sum_sq_s=0,sum_sq_r=0,sum_sxr=0; 1151b362b15af34006e6a11974088a46d42b903418eJohann int64_t ssim3; 1161b362b15af34006e6a11974088a46d42b903418eJohann int64_t ssim_n1,ssim_n2; 1171b362b15af34006e6a11974088a46d42b903418eJohann int64_t ssim_d1,ssim_d2; 1181b362b15af34006e6a11974088a46d42b903418eJohann int64_t ssim_t1,ssim_t2; 1191b362b15af34006e6a11974088a46d42b903418eJohann int64_t c1, c2; 1201b362b15af34006e6a11974088a46d42b903418eJohann 1211b362b15af34006e6a11974088a46d42b903418eJohann // normalize by 256/64 1221b362b15af34006e6a11974088a46d42b903418eJohann c1 = cc1*16; 1231b362b15af34006e6a11974088a46d42b903418eJohann c2 = cc2*16; 1241b362b15af34006e6a11974088a46d42b903418eJohann 1251b362b15af34006e6a11974088a46d42b903418eJohann vp8_ssim_parms_16x16(s, sp, r, rp, &sum_s, &sum_r, &sum_sq_s, &sum_sq_r, &sum_sxr); 1261b362b15af34006e6a11974088a46d42b903418eJohann ssim_n1 = (2*sum_s*sum_r+ c1); 1271b362b15af34006e6a11974088a46d42b903418eJohann 1281b362b15af34006e6a11974088a46d42b903418eJohann ssim_n2 =((int64_t) 2*256*sum_sxr-(int64_t) 2*sum_s*sum_r+c2); 1291b362b15af34006e6a11974088a46d42b903418eJohann 1301b362b15af34006e6a11974088a46d42b903418eJohann ssim_d1 =((int64_t)sum_s*sum_s +(int64_t)sum_r*sum_r+c1); 1311b362b15af34006e6a11974088a46d42b903418eJohann 1321b362b15af34006e6a11974088a46d42b903418eJohann ssim_d2 = (256 * (int64_t) sum_sq_s-(int64_t) sum_s*sum_s + 1331b362b15af34006e6a11974088a46d42b903418eJohann (int64_t) 256*sum_sq_r-(int64_t) sum_r*sum_r +c2) ; 1341b362b15af34006e6a11974088a46d42b903418eJohann 1351b362b15af34006e6a11974088a46d42b903418eJohann ssim_t1 = 256 - 256 * ssim_n1 / ssim_d1; 1361b362b15af34006e6a11974088a46d42b903418eJohann ssim_t2 = 256 - 256 * ssim_n2 / ssim_d2; 1371b362b15af34006e6a11974088a46d42b903418eJohann 1381b362b15af34006e6a11974088a46d42b903418eJohann ssim3 = 256 *ssim_t1 * ssim_t2; 1391b362b15af34006e6a11974088a46d42b903418eJohann if(ssim3 <0 ) 1401b362b15af34006e6a11974088a46d42b903418eJohann ssim3=0; 1411b362b15af34006e6a11974088a46d42b903418eJohann return (long)( ssim3 ); 1421b362b15af34006e6a11974088a46d42b903418eJohann} 1431b362b15af34006e6a11974088a46d42b903418eJohann 1441b362b15af34006e6a11974088a46d42b903418eJohann// We are using a 8x8 moving window with starting location of each 8x8 window 1451b362b15af34006e6a11974088a46d42b903418eJohann// on the 4x4 pixel grid. Such arrangement allows the windows to overlap 1461b362b15af34006e6a11974088a46d42b903418eJohann// block boundaries to penalize blocking artifacts. 1471b362b15af34006e6a11974088a46d42b903418eJohanndouble vp8_ssim2 1481b362b15af34006e6a11974088a46d42b903418eJohann( 1491b362b15af34006e6a11974088a46d42b903418eJohann unsigned char *img1, 1501b362b15af34006e6a11974088a46d42b903418eJohann unsigned char *img2, 1511b362b15af34006e6a11974088a46d42b903418eJohann int stride_img1, 1521b362b15af34006e6a11974088a46d42b903418eJohann int stride_img2, 1531b362b15af34006e6a11974088a46d42b903418eJohann int width, 1541b362b15af34006e6a11974088a46d42b903418eJohann int height 1551b362b15af34006e6a11974088a46d42b903418eJohann) 1561b362b15af34006e6a11974088a46d42b903418eJohann{ 1571b362b15af34006e6a11974088a46d42b903418eJohann int i,j; 1581b362b15af34006e6a11974088a46d42b903418eJohann int samples =0; 1591b362b15af34006e6a11974088a46d42b903418eJohann double ssim_total=0; 1601b362b15af34006e6a11974088a46d42b903418eJohann 1611b362b15af34006e6a11974088a46d42b903418eJohann // sample point start with each 4x4 location 1621b362b15af34006e6a11974088a46d42b903418eJohann for(i=0; i < height-8; i+=4, img1 += stride_img1*4, img2 += stride_img2*4) 1631b362b15af34006e6a11974088a46d42b903418eJohann { 1641b362b15af34006e6a11974088a46d42b903418eJohann for(j=0; j < width-8; j+=4 ) 1651b362b15af34006e6a11974088a46d42b903418eJohann { 1661b362b15af34006e6a11974088a46d42b903418eJohann double v = ssim_8x8(img1+j, stride_img1, img2+j, stride_img2); 1671b362b15af34006e6a11974088a46d42b903418eJohann ssim_total += v; 1681b362b15af34006e6a11974088a46d42b903418eJohann samples++; 1691b362b15af34006e6a11974088a46d42b903418eJohann } 1701b362b15af34006e6a11974088a46d42b903418eJohann } 1711b362b15af34006e6a11974088a46d42b903418eJohann ssim_total /= samples; 1721b362b15af34006e6a11974088a46d42b903418eJohann return ssim_total; 1731b362b15af34006e6a11974088a46d42b903418eJohann} 1741b362b15af34006e6a11974088a46d42b903418eJohanndouble vp8_calc_ssim 1751b362b15af34006e6a11974088a46d42b903418eJohann( 1761b362b15af34006e6a11974088a46d42b903418eJohann YV12_BUFFER_CONFIG *source, 1771b362b15af34006e6a11974088a46d42b903418eJohann YV12_BUFFER_CONFIG *dest, 1781b362b15af34006e6a11974088a46d42b903418eJohann int lumamask, 1791b362b15af34006e6a11974088a46d42b903418eJohann double *weight 1801b362b15af34006e6a11974088a46d42b903418eJohann) 1811b362b15af34006e6a11974088a46d42b903418eJohann{ 1821b362b15af34006e6a11974088a46d42b903418eJohann double a, b, c; 1831b362b15af34006e6a11974088a46d42b903418eJohann double ssimv; 1841b362b15af34006e6a11974088a46d42b903418eJohann 1851b362b15af34006e6a11974088a46d42b903418eJohann a = vp8_ssim2(source->y_buffer, dest->y_buffer, 1861b362b15af34006e6a11974088a46d42b903418eJohann source->y_stride, dest->y_stride, source->y_width, 1871b362b15af34006e6a11974088a46d42b903418eJohann source->y_height); 1881b362b15af34006e6a11974088a46d42b903418eJohann 1891b362b15af34006e6a11974088a46d42b903418eJohann b = vp8_ssim2(source->u_buffer, dest->u_buffer, 1901b362b15af34006e6a11974088a46d42b903418eJohann source->uv_stride, dest->uv_stride, source->uv_width, 1911b362b15af34006e6a11974088a46d42b903418eJohann source->uv_height); 1921b362b15af34006e6a11974088a46d42b903418eJohann 1931b362b15af34006e6a11974088a46d42b903418eJohann c = vp8_ssim2(source->v_buffer, dest->v_buffer, 1941b362b15af34006e6a11974088a46d42b903418eJohann source->uv_stride, dest->uv_stride, source->uv_width, 1951b362b15af34006e6a11974088a46d42b903418eJohann source->uv_height); 1961b362b15af34006e6a11974088a46d42b903418eJohann 1971b362b15af34006e6a11974088a46d42b903418eJohann ssimv = a * .8 + .1 * (b + c); 1981b362b15af34006e6a11974088a46d42b903418eJohann 1991b362b15af34006e6a11974088a46d42b903418eJohann *weight = 1; 2001b362b15af34006e6a11974088a46d42b903418eJohann 2011b362b15af34006e6a11974088a46d42b903418eJohann return ssimv; 2021b362b15af34006e6a11974088a46d42b903418eJohann} 2031b362b15af34006e6a11974088a46d42b903418eJohann 2041b362b15af34006e6a11974088a46d42b903418eJohanndouble vp8_calc_ssimg 2051b362b15af34006e6a11974088a46d42b903418eJohann( 2061b362b15af34006e6a11974088a46d42b903418eJohann YV12_BUFFER_CONFIG *source, 2071b362b15af34006e6a11974088a46d42b903418eJohann YV12_BUFFER_CONFIG *dest, 2081b362b15af34006e6a11974088a46d42b903418eJohann double *ssim_y, 2091b362b15af34006e6a11974088a46d42b903418eJohann double *ssim_u, 2101b362b15af34006e6a11974088a46d42b903418eJohann double *ssim_v 2111b362b15af34006e6a11974088a46d42b903418eJohann) 2121b362b15af34006e6a11974088a46d42b903418eJohann{ 2131b362b15af34006e6a11974088a46d42b903418eJohann double ssim_all = 0; 2141b362b15af34006e6a11974088a46d42b903418eJohann double a, b, c; 2151b362b15af34006e6a11974088a46d42b903418eJohann 2161b362b15af34006e6a11974088a46d42b903418eJohann a = vp8_ssim2(source->y_buffer, dest->y_buffer, 2171b362b15af34006e6a11974088a46d42b903418eJohann source->y_stride, dest->y_stride, source->y_width, 2181b362b15af34006e6a11974088a46d42b903418eJohann source->y_height); 2191b362b15af34006e6a11974088a46d42b903418eJohann 2201b362b15af34006e6a11974088a46d42b903418eJohann b = vp8_ssim2(source->u_buffer, dest->u_buffer, 2211b362b15af34006e6a11974088a46d42b903418eJohann source->uv_stride, dest->uv_stride, source->uv_width, 2221b362b15af34006e6a11974088a46d42b903418eJohann source->uv_height); 2231b362b15af34006e6a11974088a46d42b903418eJohann 2241b362b15af34006e6a11974088a46d42b903418eJohann c = vp8_ssim2(source->v_buffer, dest->v_buffer, 2251b362b15af34006e6a11974088a46d42b903418eJohann source->uv_stride, dest->uv_stride, source->uv_width, 2261b362b15af34006e6a11974088a46d42b903418eJohann source->uv_height); 2271b362b15af34006e6a11974088a46d42b903418eJohann *ssim_y = a; 2281b362b15af34006e6a11974088a46d42b903418eJohann *ssim_u = b; 2291b362b15af34006e6a11974088a46d42b903418eJohann *ssim_v = c; 2301b362b15af34006e6a11974088a46d42b903418eJohann ssim_all = (a * 4 + b + c) /6; 2311b362b15af34006e6a11974088a46d42b903418eJohann 2321b362b15af34006e6a11974088a46d42b903418eJohann return ssim_all; 2331b362b15af34006e6a11974088a46d42b903418eJohann} 234