ssim.c revision 90d3ed91ae9228e1c8bab561b6138d4cb8c1e4fd
190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber/* 290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. 390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber * 490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber * Use of this source code is governed by a BSD-style license and patent 590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber * grant that can be found in the LICENSE file in the root of the source 690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber * tree. All contributing project authors may be found in the AUTHORS 790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber * file in the root of the source tree. 890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber */ 990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 1090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 1190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#include "vpx_scale/yv12config.h" 1290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#include "math.h" 1390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 1490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define C1 (float)(64 * 64 * 0.01*255*0.01*255) 1590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define C2 (float)(64 * 64 * 0.03*255*0.03*255) 1690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 1790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int width_y; 1890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int height_y; 1990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int height_uv; 2090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int width_uv; 2190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int stride_uv; 2290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int stride; 2390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int lumimask; 2490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int luminance; 2590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic double plane_summed_weights = 0; 2690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 2790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic short img12_sum_block[8*4096*4096*2] ; 2890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 2990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic short img1_sum[8*4096*2]; 3090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic short img2_sum[8*4096*2]; 3190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int img1_sq_sum[8*4096*2]; 3290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int img2_sq_sum[8*4096*2]; 3390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic int img12_mul_sum[8*4096*2]; 3490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 3590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 3690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberdouble vp8_similarity 3790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber( 3890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int mu_x, 3990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int mu_y, 4090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int pre_mu_x2, 4190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int pre_mu_y2, 4290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int pre_mu_xy2 4390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber) 4490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 4590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int mu_x2, mu_y2, mu_xy, theta_x2, theta_y2, theta_xy; 4690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 4790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mu_x2 = mu_x * mu_x; 4890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mu_y2 = mu_y * mu_y; 4990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mu_xy = mu_x * mu_y; 5090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 5190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber theta_x2 = 64 * pre_mu_x2 - mu_x2; 5290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber theta_y2 = 64 * pre_mu_y2 - mu_y2; 5390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber theta_xy = 64 * pre_mu_xy2 - mu_xy; 5490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 5590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return (2 * mu_xy + C1) * (2 * theta_xy + C2) / ((mu_x2 + mu_y2 + C1) * (theta_x2 + theta_y2 + C2)); 5690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber} 5790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 5890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberdouble vp8_ssim 5990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber( 6090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const unsigned char *img1, 6190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const unsigned char *img2, 6290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int stride_img1, 6390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int stride_img2, 6490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int width, 6590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int height 6690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber) 6790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 6890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int x, y, x2, y2, img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block, temp; 6990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 7090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double plane_quality, weight, mean; 7190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 7290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber short *img1_sum_ptr1, *img1_sum_ptr2; 7390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber short *img2_sum_ptr1, *img2_sum_ptr2; 7490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int *img1_sq_sum_ptr1, *img1_sq_sum_ptr2; 7590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int *img2_sq_sum_ptr1, *img2_sq_sum_ptr2; 7690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int *img12_mul_sum_ptr1, *img12_mul_sum_ptr2; 7790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 7890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_quality = 0; 7990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 8090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (lumimask) 8190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_summed_weights = 0.0f; 8290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber else 8390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_summed_weights = (height - 7) * (width - 7); 8490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 8590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //some prologue for the main loop 8690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber temp = 8 * width; 8790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 8890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum_ptr1 = img1_sum + temp; 8990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum_ptr1 = img2_sum + temp; 9090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum_ptr1 = img1_sq_sum + temp; 9190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum_ptr1 = img2_sq_sum + temp; 9290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum_ptr1 = img12_mul_sum + temp; 9390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 9490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (x = 0; x < width; x++) 9590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 9690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum[x] = img1[x]; 9790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum[x] = img2[x]; 9890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum[x] = img1[x] * img1[x]; 9990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum[x] = img2[x] * img2[x]; 10090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum[x] = img1[x] * img2[x]; 10190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 10290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum_ptr1[x] = 0; 10390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum_ptr1[x] = 0; 10490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum_ptr1[x] = 0; 10590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum_ptr1[x] = 0; 10690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum_ptr1[x] = 0; 10790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 10890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 10990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //the main loop 11090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (y = 1; y < height; y++) 11190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 11290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1 += stride_img1; 11390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2 += stride_img2; 11490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 11590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber temp = (y - 1) % 9 * width; 11690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 11790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum_ptr1 = img1_sum + temp; 11890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum_ptr1 = img2_sum + temp; 11990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum_ptr1 = img1_sq_sum + temp; 12090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum_ptr1 = img2_sq_sum + temp; 12190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum_ptr1 = img12_mul_sum + temp; 12290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 12390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber temp = y % 9 * width; 12490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 12590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum_ptr2 = img1_sum + temp; 12690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum_ptr2 = img2_sum + temp; 12790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum_ptr2 = img1_sq_sum + temp; 12890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum_ptr2 = img2_sq_sum + temp; 12990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum_ptr2 = img12_mul_sum + temp; 13090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 13190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (x = 0; x < width; x++) 13290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 13390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum_ptr2[x] = img1_sum_ptr1[x] + img1[x]; 13490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum_ptr2[x] = img2_sum_ptr1[x] + img2[x]; 13590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum_ptr2[x] = img1_sq_sum_ptr1[x] + img1[x] * img1[x]; 13690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum_ptr2[x] = img2_sq_sum_ptr1[x] + img2[x] * img2[x]; 13790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum_ptr2[x] = img12_mul_sum_ptr1[x] + img1[x] * img2[x]; 13890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 13990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 14090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (y > 6) 14190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 14290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //calculate the sum of the last 8 lines by subtracting the total sum of 8 lines back from the present sum 14390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber temp = (y + 1) % 9 * width; 14490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 14590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum_ptr1 = img1_sum + temp; 14690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum_ptr1 = img2_sum + temp; 14790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum_ptr1 = img1_sq_sum + temp; 14890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum_ptr1 = img2_sq_sum + temp; 14990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum_ptr1 = img12_mul_sum + temp; 15090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 15190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (x = 0; x < width; x++) 15290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 15390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sum_ptr1[x] = img1_sum_ptr2[x] - img1_sum_ptr1[x]; 15490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sum_ptr1[x] = img2_sum_ptr2[x] - img2_sum_ptr1[x]; 15590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_sum_ptr1[x] = img1_sq_sum_ptr2[x] - img1_sq_sum_ptr1[x]; 15690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_sum_ptr1[x] = img2_sq_sum_ptr2[x] - img2_sq_sum_ptr1[x]; 15790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_sum_ptr1[x] = img12_mul_sum_ptr2[x] - img12_mul_sum_ptr1[x]; 15890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 15990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 16090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //here we calculate the sum over the 8x8 block of pixels 16190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //this is done by sliding a window across the column sums for the last 8 lines 16290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //each time adding the new column sum, and subtracting the one which fell out of the window 16390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_block = 0; 16490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_block = 0; 16590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_block = 0; 16690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_block = 0; 16790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_block = 0; 16890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 16990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //prologue, and calculation of simularity measure from the first 8 column sums 17090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (x = 0; x < 8; x++) 17190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 17290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_block += img1_sum_ptr1[x]; 17390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_block += img2_sum_ptr1[x]; 17490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_block += img1_sq_sum_ptr1[x]; 17590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_block += img2_sq_sum_ptr1[x]; 17690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_block += img12_mul_sum_ptr1[x]; 17790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 17890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 17990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (lumimask) 18090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 18190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber y2 = y - 7; 18290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber x2 = 0; 18390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 18490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (luminance) 18590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 18690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean = (img2_block + img1_block) / 128.0f; 18790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 18890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (!(y2 % 2 || x2 % 2)) 18990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *(img12_sum_block + y2 / 2 * width_uv + x2 / 2) = img2_block + img1_block; 19090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 19190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber else 19290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 19390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean = *(img12_sum_block + y2 * width_uv + x2); 19490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean += *(img12_sum_block + y2 * width_uv + x2 + 4); 19590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean += *(img12_sum_block + (y2 + 4) * width_uv + x2); 19690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean += *(img12_sum_block + (y2 + 4) * width_uv + x2 + 4); 19790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 19890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean /= 512.0f; 19990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 20090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 20190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber weight = mean < 40 ? 0.0f : 20290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber (mean < 50 ? (mean - 40.0f) / 10.0f : 1.0f); 20390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_summed_weights += weight; 20490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 20590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_quality += weight * vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); 20690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 20790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber else 20890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_quality += vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); 20990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 21090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber //and for the rest 21190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (x = 8; x < width; x++) 21290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 21390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_block = img1_block + img1_sum_ptr1[x] - img1_sum_ptr1[x - 8]; 21490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_block = img2_block + img2_sum_ptr1[x] - img2_sum_ptr1[x - 8]; 21590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img1_sq_block = img1_sq_block + img1_sq_sum_ptr1[x] - img1_sq_sum_ptr1[x - 8]; 21690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img2_sq_block = img2_sq_block + img2_sq_sum_ptr1[x] - img2_sq_sum_ptr1[x - 8]; 21790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber img12_mul_block = img12_mul_block + img12_mul_sum_ptr1[x] - img12_mul_sum_ptr1[x - 8]; 21890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 21990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (lumimask) 22090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 22190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber y2 = y - 7; 22290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber x2 = x - 7; 22390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 22490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (luminance) 22590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 22690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean = (img2_block + img1_block) / 128.0f; 22790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 22890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (!(y2 % 2 || x2 % 2)) 22990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *(img12_sum_block + y2 / 2 * width_uv + x2 / 2) = img2_block + img1_block; 23090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 23190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber else 23290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 23390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean = *(img12_sum_block + y2 * width_uv + x2); 23490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean += *(img12_sum_block + y2 * width_uv + x2 + 4); 23590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean += *(img12_sum_block + (y2 + 4) * width_uv + x2); 23690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean += *(img12_sum_block + (y2 + 4) * width_uv + x2 + 4); 23790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 23890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber mean /= 512.0f; 23990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 24090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 24190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber weight = mean < 40 ? 0.0f : 24290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber (mean < 50 ? (mean - 40.0f) / 10.0f : 1.0f); 24390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_summed_weights += weight; 24490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 24590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_quality += weight * vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); 24690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 24790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber else 24890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber plane_quality += vp8_similarity(img1_block, img2_block, img1_sq_block, img2_sq_block, img12_mul_block); 24990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 25090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 25190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 25290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 25390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (plane_summed_weights == 0) 25490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return 1.0f; 25590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber else 25690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return plane_quality / plane_summed_weights; 25790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber} 25890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 25990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberdouble vp8_calc_ssim 26090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber( 26190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber YV12_BUFFER_CONFIG *source, 26290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber YV12_BUFFER_CONFIG *dest, 26390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int lumamask, 26490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double *weight 26590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber) 26690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 26790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double a, b, c; 26890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double frame_weight; 26990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double ssimv; 27090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 27190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber width_y = source->y_width; 27290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber height_y = source->y_height; 27390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber height_uv = source->uv_height; 27490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber width_uv = source->uv_width; 27590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber stride_uv = dest->uv_stride; 27690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber stride = dest->y_stride; 27790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 27890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber lumimask = lumamask; 27990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 28090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber luminance = 1; 28190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber a = vp8_ssim(source->y_buffer, dest->y_buffer, 28290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->y_stride, dest->y_stride, source->y_width, source->y_height); 28390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber luminance = 0; 28490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 28590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber frame_weight = plane_summed_weights / ((width_y - 7) * (height_y - 7)); 28690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 28790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (frame_weight == 0) 28890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber a = b = c = 1.0f; 28990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber else 29090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 29190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber b = vp8_ssim(source->u_buffer, dest->u_buffer, 29290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->uv_stride, dest->uv_stride, source->uv_width, source->uv_height); 29390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 29490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber c = vp8_ssim(source->v_buffer, dest->v_buffer, 29590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->uv_stride, dest->uv_stride, source->uv_width, source->uv_height); 29690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 29790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 29890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber ssimv = a * .8 + .1 * (b + c); 29990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 30090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *weight = frame_weight; 30190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 30290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return ssimv; 30390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber} 30490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 30590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber// Google version of SSIM 30690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber// SSIM 30790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define KERNEL 3 30890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber#define KERNEL_SIZE (2 * KERNEL + 1) 30990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 31090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Hubertypedef unsigned char uint8; 31190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Hubertypedef unsigned int uint32; 31290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 31390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic const int K[KERNEL_SIZE] = 31490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 31590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 1, 4, 11, 16, 11, 4, 1 // 16 * exp(-0.3 * i * i) 31690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber}; 31790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberstatic const double ki_w = 1. / 2304.; // 1 / sum(i:0..6, j..6) K[i]*K[j] 31890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberdouble get_ssimg(const uint8 *org, const uint8 *rec, 31990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int xo, int yo, int W, int H, 32090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int stride1, const int stride2 32190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber ) 32290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 32390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // TODO(skal): use summed tables 32490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int y, x; 32590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 32690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int ymin = (yo - KERNEL < 0) ? 0 : yo - KERNEL; 32790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int ymax = (yo + KERNEL > H - 1) ? H - 1 : yo + KERNEL; 32890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int xmin = (xo - KERNEL < 0) ? 0 : xo - KERNEL; 32990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int xmax = (xo + KERNEL > W - 1) ? W - 1 : xo + KERNEL; 33090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // worst case of accumulation is a weight of 48 = 16 + 2 * (11 + 4 + 1) 33190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // with a diff of 255, squares. That would a max error of 0x8ee0900, 33290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // which fits into 32 bits integers. 33390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber uint32 w = 0, xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; 33490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber org += ymin * stride1; 33590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber rec += ymin * stride2; 33690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 33790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (y = ymin; y <= ymax; ++y, org += stride1, rec += stride2) 33890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 33990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int Wy = K[KERNEL + y - yo]; 34090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 34190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (x = xmin; x <= xmax; ++x) 34290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 34390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int Wxy = Wy * K[KERNEL + x - xo]; 34490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // TODO(skal): inlined assembly 34590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber w += Wxy; 34690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber xm += Wxy * org[x]; 34790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber ym += Wxy * rec[x]; 34890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber xxm += Wxy * org[x] * org[x]; 34990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber xym += Wxy * org[x] * rec[x]; 35090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber yym += Wxy * rec[x] * rec[x]; 35190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 35290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 35390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 35490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 35590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double iw = 1. / w; 35690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double iwx = xm * iw; 35790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double iwy = ym * iw; 35890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double sxx = xxm * iw - iwx * iwx; 35990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double syy = yym * iw - iwy * iwy; 36090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 36190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // small errors are possible, due to rounding. Clamp to zero. 36290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (sxx < 0.) sxx = 0.; 36390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 36490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (syy < 0.) syy = 0.; 36590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 36690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 36790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double sxsy = sqrt(sxx * syy); 36890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double sxy = xym * iw - iwx * iwy; 36990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber static const double C11 = (0.01 * 0.01) * (255 * 255); 37090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber static const double C22 = (0.03 * 0.03) * (255 * 255); 37190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber static const double C33 = (0.015 * 0.015) * (255 * 255); 37290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double l = (2. * iwx * iwy + C11) / (iwx * iwx + iwy * iwy + C11); 37390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double c = (2. * sxsy + C22) / (sxx + syy + C22); 37490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 37590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double s = (sxy + C33) / (sxsy + C33); 37690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return l * c * s; 37790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 37890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 37990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 38090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 38190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber} 38290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 38390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberdouble get_ssimfull_kernelg(const uint8 *org, const uint8 *rec, 38490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int xo, int yo, int W, int H, 38590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int stride1, const int stride2) 38690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 38790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // TODO(skal): use summed tables 38890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // worst case of accumulation is a weight of 48 = 16 + 2 * (11 + 4 + 1) 38990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // with a diff of 255, squares. That would a max error of 0x8ee0900, 39090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // which fits into 32 bits integers. 39190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int y_, x_; 39290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber uint32 xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; 39390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber org += (yo - KERNEL) * stride1; 39490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber org += (xo - KERNEL); 39590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber rec += (yo - KERNEL) * stride2; 39690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber rec += (xo - KERNEL); 39790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 39890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (y_ = 0; y_ < KERNEL_SIZE; ++y_, org += stride1, rec += stride2) 39990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 40090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int Wy = K[y_]; 40190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 40290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (x_ = 0; x_ < KERNEL_SIZE; ++x_) 40390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 40490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int Wxy = Wy * K[x_]; 40590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // TODO(skal): inlined assembly 40690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int org_x = org[x_]; 40790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int rec_x = rec[x_]; 40890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber xm += Wxy * org_x; 40990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber ym += Wxy * rec_x; 41090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber xxm += Wxy * org_x * org_x; 41190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber xym += Wxy * org_x * rec_x; 41290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber yym += Wxy * rec_x * rec_x; 41390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 41490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 41590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 41690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 41790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double iw = ki_w; 41890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double iwx = xm * iw; 41990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double iwy = ym * iw; 42090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double sxx = xxm * iw - iwx * iwx; 42190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double syy = yym * iw - iwy * iwy; 42290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 42390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber // small errors are possible, due to rounding. Clamp to zero. 42490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (sxx < 0.) sxx = 0.; 42590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 42690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber if (syy < 0.) syy = 0.; 42790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 42890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 42990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double sxsy = sqrt(sxx * syy); 43090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double sxy = xym * iw - iwx * iwy; 43190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber static const double C11 = (0.01 * 0.01) * (255 * 255); 43290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber static const double C22 = (0.03 * 0.03) * (255 * 255); 43390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber static const double C33 = (0.015 * 0.015) * (255 * 255); 43490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double l = (2. * iwx * iwy + C11) / (iwx * iwx + iwy * iwy + C11); 43590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double c = (2. * sxsy + C22) / (sxx + syy + C22); 43690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const double s = (sxy + C33) / (sxsy + C33); 43790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return l * c * s; 43890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 43990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 44090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber} 44190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 44290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberdouble calc_ssimg(const uint8 *org, const uint8 *rec, 44390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int image_width, const int image_height, 44490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber const int stride1, const int stride2 44590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber ) 44690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 44790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int j, i; 44890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double SSIM = 0.; 44990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 45090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (j = 0; j < KERNEL; ++j) 45190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 45290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (i = 0; i < image_width; ++i) 45390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 45490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 45590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 45690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 45790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 45890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (j = KERNEL; j < image_height - KERNEL; ++j) 45990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 46090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (i = 0; i < KERNEL; ++i) 46190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 46290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 46390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 46490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 46590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (i = KERNEL; i < image_width - KERNEL; ++i) 46690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 46790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber SSIM += get_ssimfull_kernelg(org, rec, i, j, 46890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber image_width, image_height, stride1, stride2); 46990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 47090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 47190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (i = image_width - KERNEL; i < image_width; ++i) 47290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 47390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 47490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 47590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 47690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 47790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (j = image_height - KERNEL; j < image_height; ++j) 47890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 47990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber for (i = 0; i < image_width; ++i) 48090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber { 48190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber SSIM += get_ssimg(org, rec, i, j, image_width, image_height, stride1, stride2); 48290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 48390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber } 48490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 48590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return SSIM; 48690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber} 48790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 48890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 48990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huberdouble vp8_calc_ssimg 49090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber( 49190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber YV12_BUFFER_CONFIG *source, 49290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber YV12_BUFFER_CONFIG *dest, 49390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double *ssim_y, 49490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double *ssim_u, 49590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double *ssim_v 49690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber) 49790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber{ 49890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber double ssim_all = 0; 49990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int ysize = source->y_width * source->y_height; 50090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber int uvsize = ysize / 4; 50190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 50290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *ssim_y = calc_ssimg(source->y_buffer, dest->y_buffer, 50390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->y_width, source->y_height, 50490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->y_stride, dest->y_stride); 50590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 50690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 50790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *ssim_u = calc_ssimg(source->u_buffer, dest->u_buffer, 50890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->uv_width, source->uv_height, 50990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->uv_stride, dest->uv_stride); 51090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 51190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 51290d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *ssim_v = calc_ssimg(source->v_buffer, dest->v_buffer, 51390d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->uv_width, source->uv_height, 51490d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber source->uv_stride, dest->uv_stride); 51590d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber 51690d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber ssim_all = (*ssim_y + *ssim_u + *ssim_v) / (ysize + uvsize + uvsize); 51790d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *ssim_y /= ysize; 51890d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *ssim_u /= uvsize; 51990d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber *ssim_v /= uvsize; 52090d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber return ssim_all; 52190d3ed91ae9228e1c8bab561b6138d4cb8c1e4fdAndreas Huber} 522