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