blockiness.c 4.64 KB
Newer Older
Jingning Han's avatar
Jingning Han committed
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Jingning Han's avatar
Jingning Han committed
3
 *
4 5 6 7 8 9
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Jingning Han's avatar
Jingning Han committed
10 11
 */

Yaowu Xu's avatar
Yaowu Xu committed
12
#include "./av1_rtcd.h"
Jingning Han's avatar
Jingning Han committed
13 14
#include "./vpx_config.h"
#include "./vpx_dsp_rtcd.h"
Yaowu Xu's avatar
Yaowu Xu committed
15 16
#include "av1/common/common.h"
#include "av1/common/filter.h"
Yaowu Xu's avatar
Yaowu Xu committed
17 18 19 20 21
#include "aom/vpx_integer.h"
#include "aom_dsp/vpx_convolve.h"
#include "aom_dsp/vpx_filter.h"
#include "aom_ports/mem.h"
#include "aom_ports/system_state.h"
Jingning Han's avatar
Jingning Han committed
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

static int horizontal_filter(const uint8_t *s) {
  return (s[1] - s[-2]) * 2 + (s[-1] - s[0]) * 6;
}

static int vertical_filter(const uint8_t *s, int p) {
  return (s[p] - s[-2 * p]) * 2 + (s[-p] - s[0]) * 6;
}

static int variance(int sum, int sum_squared, int size) {
  return sum_squared / size - (sum / size) * (sum / size);
}
// Calculate a blockiness level for a vertical block edge.
// This function returns a new blockiness metric that's defined as

//              p0 p1 p2 p3
//              q0 q1 q2 q3
// block edge ->
//              r0 r1 r2 r3
//              s0 s1 s2 s3

// blockiness =  p0*-2+q0*6+r0*-6+s0*2 +
//               p1*-2+q1*6+r1*-6+s1*2 +
//               p2*-2+q2*6+r2*-6+s2*2 +
//               p3*-2+q3*6+r3*-6+s3*2 ;

// reconstructed_blockiness = abs(blockiness from reconstructed buffer -
//                                blockiness from source buffer,0)
//
// I make the assumption that flat blocks are much more visible than high
// contrast blocks. As such, I scale the result of the blockiness calc
// by dividing the blockiness by the variance of the pixels on either side
// of the edge as follows:
// var_0 = (q0^2+q1^2+q2^2+q3^2) - ((q0 + q1 + q2 + q3) / 4 )^2
// var_1 = (r0^2+r1^2+r2^2+r3^2) - ((r0 + r1 + r2 + r3) / 4 )^2
// The returned blockiness is the scaled value
// Reconstructed blockiness / ( 1 + var_0 + var_1 ) ;
59 60
static int blockiness_vertical(const uint8_t *s, int sp, const uint8_t *r,
                               int rp, int size) {
Jingning Han's avatar
Jingning Han committed
61 62 63 64 65 66 67 68 69 70 71 72 73
  int s_blockiness = 0;
  int r_blockiness = 0;
  int sum_0 = 0;
  int sum_sq_0 = 0;
  int sum_1 = 0;
  int sum_sq_1 = 0;
  int i;
  int var_0;
  int var_1;
  for (i = 0; i < size; ++i, s += sp, r += rp) {
    s_blockiness += horizontal_filter(s);
    r_blockiness += horizontal_filter(r);
    sum_0 += s[0];
clang-format's avatar
clang-format committed
74
    sum_sq_0 += s[0] * s[0];
Jingning Han's avatar
Jingning Han committed
75
    sum_1 += s[-1];
clang-format's avatar
clang-format committed
76
    sum_sq_1 += s[-1] * s[-1];
Jingning Han's avatar
Jingning Han committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90
  }
  var_0 = variance(sum_0, sum_sq_0, size);
  var_1 = variance(sum_1, sum_sq_1, size);
  r_blockiness = abs(r_blockiness);
  s_blockiness = abs(s_blockiness);

  if (r_blockiness > s_blockiness)
    return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
  else
    return 0;
}

// Calculate a blockiness level for a horizontal block edge
// same as above.
91 92
static int blockiness_horizontal(const uint8_t *s, int sp, const uint8_t *r,
                                 int rp, int size) {
Jingning Han's avatar
Jingning Han committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
  int s_blockiness = 0;
  int r_blockiness = 0;
  int sum_0 = 0;
  int sum_sq_0 = 0;
  int sum_1 = 0;
  int sum_sq_1 = 0;
  int i;
  int var_0;
  int var_1;
  for (i = 0; i < size; ++i, ++s, ++r) {
    s_blockiness += vertical_filter(s, sp);
    r_blockiness += vertical_filter(r, rp);
    sum_0 += s[0];
    sum_sq_0 += s[0] * s[0];
    sum_1 += s[-sp];
    sum_sq_1 += s[-sp] * s[-sp];
  }
  var_0 = variance(sum_0, sum_sq_0, size);
  var_1 = variance(sum_1, sum_sq_1, size);
  r_blockiness = abs(r_blockiness);
  s_blockiness = abs(s_blockiness);

  if (r_blockiness > s_blockiness)
    return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
  else
    return 0;
}

// This function returns the blockiness for the entire frame currently by
// looking at all borders in steps of 4.
double vp10_get_blockiness(const unsigned char *img1, int img1_pitch,
clang-format's avatar
clang-format committed
124 125
                           const unsigned char *img2, int img2_pitch, int width,
                           int height) {
Jingning Han's avatar
Jingning Han committed
126 127 128
  double blockiness = 0;
  int i, j;
  vpx_clear_system_state();
clang-format's avatar
clang-format committed
129 130
  for (i = 0; i < height;
       i += 4, img1 += img1_pitch * 4, img2 += img2_pitch * 4) {
Jingning Han's avatar
Jingning Han committed
131 132
    for (j = 0; j < width; j += 4) {
      if (i > 0 && i < height && j > 0 && j < width) {
clang-format's avatar
clang-format committed
133 134 135 136
        blockiness +=
            blockiness_vertical(img1 + j, img1_pitch, img2 + j, img2_pitch, 4);
        blockiness += blockiness_horizontal(img1 + j, img1_pitch, img2 + j,
                                            img2_pitch, 4);
Jingning Han's avatar
Jingning Han committed
137 138 139 140 141 142
      }
    }
  }
  blockiness /= width * height / 16;
  return blockiness;
}