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