xref: /aosp_15_r20/external/libvpx/vp9/encoder/vp9_blockiness.c (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
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