1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker * Copyright (c) 2014 The WebM project authors. All Rights Reserved.
3*fb1b10abSAndroid Build Coastguard Worker *
4*fb1b10abSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker */
10*fb1b10abSAndroid Build Coastguard Worker #include <stdlib.h>
11*fb1b10abSAndroid Build Coastguard Worker
12*fb1b10abSAndroid Build Coastguard Worker #include "vpx/vpx_integer.h"
13*fb1b10abSAndroid Build Coastguard Worker #include "vpx_ports/system_state.h"
14*fb1b10abSAndroid Build Coastguard Worker #include "vp9/encoder/vp9_blockiness.h"
15*fb1b10abSAndroid Build Coastguard Worker
horizontal_filter(const uint8_t * s)16*fb1b10abSAndroid Build Coastguard Worker static int horizontal_filter(const uint8_t *s) {
17*fb1b10abSAndroid Build Coastguard Worker return (s[1] - s[-2]) * 2 + (s[-1] - s[0]) * 6;
18*fb1b10abSAndroid Build Coastguard Worker }
19*fb1b10abSAndroid Build Coastguard Worker
vertical_filter(const uint8_t * s,int p)20*fb1b10abSAndroid Build Coastguard Worker static int vertical_filter(const uint8_t *s, int p) {
21*fb1b10abSAndroid Build Coastguard Worker return (s[p] - s[-2 * p]) * 2 + (s[-p] - s[0]) * 6;
22*fb1b10abSAndroid Build Coastguard Worker }
23*fb1b10abSAndroid Build Coastguard Worker
variance(int sum,int sum_squared,int size)24*fb1b10abSAndroid Build Coastguard Worker static int variance(int sum, int sum_squared, int size) {
25*fb1b10abSAndroid Build Coastguard Worker return sum_squared / size - (sum / size) * (sum / size);
26*fb1b10abSAndroid Build Coastguard Worker }
27*fb1b10abSAndroid Build Coastguard Worker // Calculate a blockiness level for a vertical block edge.
28*fb1b10abSAndroid Build Coastguard Worker // This function returns a new blockiness metric that's defined as
29*fb1b10abSAndroid Build Coastguard Worker
30*fb1b10abSAndroid Build Coastguard Worker // p0 p1 p2 p3
31*fb1b10abSAndroid Build Coastguard Worker // q0 q1 q2 q3
32*fb1b10abSAndroid Build Coastguard Worker // block edge ->
33*fb1b10abSAndroid Build Coastguard Worker // r0 r1 r2 r3
34*fb1b10abSAndroid Build Coastguard Worker // s0 s1 s2 s3
35*fb1b10abSAndroid Build Coastguard Worker
36*fb1b10abSAndroid Build Coastguard Worker // blockiness = p0*-2+q0*6+r0*-6+s0*2 +
37*fb1b10abSAndroid Build Coastguard Worker // p1*-2+q1*6+r1*-6+s1*2 +
38*fb1b10abSAndroid Build Coastguard Worker // p2*-2+q2*6+r2*-6+s2*2 +
39*fb1b10abSAndroid Build Coastguard Worker // p3*-2+q3*6+r3*-6+s3*2 ;
40*fb1b10abSAndroid Build Coastguard Worker
41*fb1b10abSAndroid Build Coastguard Worker // reconstructed_blockiness = abs(blockiness from reconstructed buffer -
42*fb1b10abSAndroid Build Coastguard Worker // blockiness from source buffer,0)
43*fb1b10abSAndroid Build Coastguard Worker //
44*fb1b10abSAndroid Build Coastguard Worker // I make the assumption that flat blocks are much more visible than high
45*fb1b10abSAndroid Build Coastguard Worker // contrast blocks. As such, I scale the result of the blockiness calc
46*fb1b10abSAndroid Build Coastguard Worker // by dividing the blockiness by the variance of the pixels on either side
47*fb1b10abSAndroid Build Coastguard Worker // of the edge as follows:
48*fb1b10abSAndroid Build Coastguard Worker // var_0 = (q0^2+q1^2+q2^2+q3^2) - ((q0 + q1 + q2 + q3) / 4 )^2
49*fb1b10abSAndroid Build Coastguard Worker // var_1 = (r0^2+r1^2+r2^2+r3^2) - ((r0 + r1 + r2 + r3) / 4 )^2
50*fb1b10abSAndroid Build Coastguard Worker // The returned blockiness is the scaled value
51*fb1b10abSAndroid Build Coastguard Worker // Reconstructed blockiness / ( 1 + var_0 + var_1 ) ;
blockiness_vertical(const uint8_t * s,int sp,const uint8_t * r,int rp,int size)52*fb1b10abSAndroid Build Coastguard Worker static int blockiness_vertical(const uint8_t *s, int sp, const uint8_t *r,
53*fb1b10abSAndroid Build Coastguard Worker int rp, int size) {
54*fb1b10abSAndroid Build Coastguard Worker int s_blockiness = 0;
55*fb1b10abSAndroid Build Coastguard Worker int r_blockiness = 0;
56*fb1b10abSAndroid Build Coastguard Worker int sum_0 = 0;
57*fb1b10abSAndroid Build Coastguard Worker int sum_sq_0 = 0;
58*fb1b10abSAndroid Build Coastguard Worker int sum_1 = 0;
59*fb1b10abSAndroid Build Coastguard Worker int sum_sq_1 = 0;
60*fb1b10abSAndroid Build Coastguard Worker int i;
61*fb1b10abSAndroid Build Coastguard Worker int var_0;
62*fb1b10abSAndroid Build Coastguard Worker int var_1;
63*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < size; ++i, s += sp, r += rp) {
64*fb1b10abSAndroid Build Coastguard Worker s_blockiness += horizontal_filter(s);
65*fb1b10abSAndroid Build Coastguard Worker r_blockiness += horizontal_filter(r);
66*fb1b10abSAndroid Build Coastguard Worker sum_0 += s[0];
67*fb1b10abSAndroid Build Coastguard Worker sum_sq_0 += s[0] * s[0];
68*fb1b10abSAndroid Build Coastguard Worker sum_1 += s[-1];
69*fb1b10abSAndroid Build Coastguard Worker sum_sq_1 += s[-1] * s[-1];
70*fb1b10abSAndroid Build Coastguard Worker }
71*fb1b10abSAndroid Build Coastguard Worker var_0 = variance(sum_0, sum_sq_0, size);
72*fb1b10abSAndroid Build Coastguard Worker var_1 = variance(sum_1, sum_sq_1, size);
73*fb1b10abSAndroid Build Coastguard Worker r_blockiness = abs(r_blockiness);
74*fb1b10abSAndroid Build Coastguard Worker s_blockiness = abs(s_blockiness);
75*fb1b10abSAndroid Build Coastguard Worker
76*fb1b10abSAndroid Build Coastguard Worker if (r_blockiness > s_blockiness)
77*fb1b10abSAndroid Build Coastguard Worker return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
78*fb1b10abSAndroid Build Coastguard Worker else
79*fb1b10abSAndroid Build Coastguard Worker return 0;
80*fb1b10abSAndroid Build Coastguard Worker }
81*fb1b10abSAndroid Build Coastguard Worker
82*fb1b10abSAndroid Build Coastguard Worker // Calculate a blockiness level for a horizontal block edge
83*fb1b10abSAndroid Build Coastguard Worker // same as above.
blockiness_horizontal(const uint8_t * s,int sp,const uint8_t * r,int rp,int size)84*fb1b10abSAndroid Build Coastguard Worker static int blockiness_horizontal(const uint8_t *s, int sp, const uint8_t *r,
85*fb1b10abSAndroid Build Coastguard Worker int rp, int size) {
86*fb1b10abSAndroid Build Coastguard Worker int s_blockiness = 0;
87*fb1b10abSAndroid Build Coastguard Worker int r_blockiness = 0;
88*fb1b10abSAndroid Build Coastguard Worker int sum_0 = 0;
89*fb1b10abSAndroid Build Coastguard Worker int sum_sq_0 = 0;
90*fb1b10abSAndroid Build Coastguard Worker int sum_1 = 0;
91*fb1b10abSAndroid Build Coastguard Worker int sum_sq_1 = 0;
92*fb1b10abSAndroid Build Coastguard Worker int i;
93*fb1b10abSAndroid Build Coastguard Worker int var_0;
94*fb1b10abSAndroid Build Coastguard Worker int var_1;
95*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < size; ++i, ++s, ++r) {
96*fb1b10abSAndroid Build Coastguard Worker s_blockiness += vertical_filter(s, sp);
97*fb1b10abSAndroid Build Coastguard Worker r_blockiness += vertical_filter(r, rp);
98*fb1b10abSAndroid Build Coastguard Worker sum_0 += s[0];
99*fb1b10abSAndroid Build Coastguard Worker sum_sq_0 += s[0] * s[0];
100*fb1b10abSAndroid Build Coastguard Worker sum_1 += s[-sp];
101*fb1b10abSAndroid Build Coastguard Worker sum_sq_1 += s[-sp] * s[-sp];
102*fb1b10abSAndroid Build Coastguard Worker }
103*fb1b10abSAndroid Build Coastguard Worker var_0 = variance(sum_0, sum_sq_0, size);
104*fb1b10abSAndroid Build Coastguard Worker var_1 = variance(sum_1, sum_sq_1, size);
105*fb1b10abSAndroid Build Coastguard Worker r_blockiness = abs(r_blockiness);
106*fb1b10abSAndroid Build Coastguard Worker s_blockiness = abs(s_blockiness);
107*fb1b10abSAndroid Build Coastguard Worker
108*fb1b10abSAndroid Build Coastguard Worker if (r_blockiness > s_blockiness)
109*fb1b10abSAndroid Build Coastguard Worker return (r_blockiness - s_blockiness) / (1 + var_0 + var_1);
110*fb1b10abSAndroid Build Coastguard Worker else
111*fb1b10abSAndroid Build Coastguard Worker return 0;
112*fb1b10abSAndroid Build Coastguard Worker }
113*fb1b10abSAndroid Build Coastguard Worker
114*fb1b10abSAndroid Build Coastguard Worker // This function returns the blockiness for the entire frame currently by
115*fb1b10abSAndroid Build Coastguard Worker // looking at all borders in steps of 4.
vp9_get_blockiness(const uint8_t * img1,int img1_pitch,const uint8_t * img2,int img2_pitch,int width,int height)116*fb1b10abSAndroid Build Coastguard Worker double vp9_get_blockiness(const uint8_t *img1, int img1_pitch,
117*fb1b10abSAndroid Build Coastguard Worker const uint8_t *img2, int img2_pitch, int width,
118*fb1b10abSAndroid Build Coastguard Worker int height) {
119*fb1b10abSAndroid Build Coastguard Worker double blockiness = 0;
120*fb1b10abSAndroid Build Coastguard Worker int i, j;
121*fb1b10abSAndroid Build Coastguard Worker vpx_clear_system_state();
122*fb1b10abSAndroid Build Coastguard Worker for (i = 0; i < height;
123*fb1b10abSAndroid Build Coastguard Worker i += 4, img1 += img1_pitch * 4, img2 += img2_pitch * 4) {
124*fb1b10abSAndroid Build Coastguard Worker for (j = 0; j < width; j += 4) {
125*fb1b10abSAndroid Build Coastguard Worker if (i > 0 && i < height && j > 0 && j < width) {
126*fb1b10abSAndroid Build Coastguard Worker blockiness +=
127*fb1b10abSAndroid Build Coastguard Worker blockiness_vertical(img1 + j, img1_pitch, img2 + j, img2_pitch, 4);
128*fb1b10abSAndroid Build Coastguard Worker blockiness += blockiness_horizontal(img1 + j, img1_pitch, img2 + j,
129*fb1b10abSAndroid Build Coastguard Worker img2_pitch, 4);
130*fb1b10abSAndroid Build Coastguard Worker }
131*fb1b10abSAndroid Build Coastguard Worker }
132*fb1b10abSAndroid Build Coastguard Worker }
133*fb1b10abSAndroid Build Coastguard Worker blockiness /= width * height / 16;
134*fb1b10abSAndroid Build Coastguard Worker return blockiness;
135*fb1b10abSAndroid Build Coastguard Worker }
136