blob: 7015c09872ae6e9fdf5997285b0971b52e0eeefe [file] [log] [blame]
Jim Bankoski9757c1a2015-04-17 10:27:56 -07001/*
2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 *
10 * This code was originally written by: Gregory Maxwell, at the Daala
11 * project.
12 */
Yaowu Xuefe1b1d2016-02-04 14:03:48 -080013#include <assert.h>
Jim Bankoski9757c1a2015-04-17 10:27:56 -070014#include <stdio.h>
15#include <stdlib.h>
16#include <math.h>
17
18#include "./vpx_config.h"
Jingning Han598b0832015-07-23 11:31:45 -070019#include "./vpx_dsp_rtcd.h"
Alex Conversec7b70112015-08-06 12:53:59 -070020#include "vpx_dsp/ssim.h"
Alex Conversea8a08ce2015-08-10 11:28:04 -070021#include "vpx_ports/system_state.h"
Yaowu Xu75385012016-02-17 08:42:56 -080022#include "vpx_dsp/psnr.h"
Jim Bankoski9757c1a2015-04-17 10:27:56 -070023
24#if !defined(M_PI)
25# define M_PI (3.141592653589793238462643)
26#endif
27#include <string.h>
28
Alex Conversec1f911a2015-08-06 18:37:58 -070029static void od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
30 int xstride) {
Yaowu Xuac898d22016-02-04 16:15:42 -080031 int i, j;
Jim Bankoski9757c1a2015-04-17 10:27:56 -070032 (void) xstride;
Jingning Han4b5109c2015-07-28 15:57:40 -070033 vpx_fdct8x8(x, y, ystride);
Yaowu Xuac898d22016-02-04 16:15:42 -080034 for (i = 0; i < 8; i++)
35 for (j = 0; j< 8; j++)
36 *(y + ystride*i + j) = (*(y + ystride*i + j) + 4) >> 3;
Jim Bankoski9757c1a2015-04-17 10:27:56 -070037}
Yaowu Xubb8ca082016-02-05 13:03:47 -080038#if CONFIG_VP9_HIGHBITDEPTH
39static void hbd_od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
40 int xstride) {
41 int i, j;
42 (void) xstride;
43 vpx_highbd_fdct8x8(x, y, ystride);
44 for (i = 0; i < 8; i++)
45 for (j = 0; j< 8; j++)
46 *(y + ystride*i + j) = (*(y + ystride*i + j) + 4) >> 3;
47}
48#endif
Jim Bankoski9757c1a2015-04-17 10:27:56 -070049
50/* Normalized inverse quantization matrix for 8x8 DCT at the point of
51 * transparency. This is not the JPEG based matrix from the paper,
52 this one gives a slightly higher MOS agreement.*/
Yaowu Xu3c28b4a2016-02-08 09:41:43 -080053static const double csf_y[8][8] = {
Alex Conversec1f911a2015-08-06 18:37:58 -070054 {1.6193873005, 2.2901594831, 2.08509755623, 1.48366094411, 1.00227514334,
55 0.678296995242, 0.466224900598, 0.3265091542},
56 {2.2901594831, 1.94321815382, 2.04793073064, 1.68731108984, 1.2305666963,
57 0.868920337363, 0.61280991668, 0.436405793551},
58 {2.08509755623, 2.04793073064, 1.34329019223, 1.09205635862, 0.875748795257,
59 0.670882927016, 0.501731932449, 0.372504254596},
60 {1.48366094411, 1.68731108984, 1.09205635862, 0.772819797575,
61 0.605636379554, 0.48309405692, 0.380429446972, 0.295774038565},
62 {1.00227514334, 1.2305666963, 0.875748795257, 0.605636379554,
63 0.448996256676, 0.352889268808, 0.283006984131, 0.226951348204},
64 {0.678296995242, 0.868920337363, 0.670882927016, 0.48309405692,
65 0.352889268808, 0.27032073436, 0.215017739696, 0.17408067321},
66 {0.466224900598, 0.61280991668, 0.501731932449, 0.380429446972,
67 0.283006984131, 0.215017739696, 0.168869545842, 0.136153931001},
68 {0.3265091542, 0.436405793551, 0.372504254596, 0.295774038565,
69 0.226951348204, 0.17408067321, 0.136153931001, 0.109083846276}};
Yaowu Xu3c28b4a2016-02-08 09:41:43 -080070static const double csf_cb420[8][8] = {
Jim Bankoski9757c1a2015-04-17 10:27:56 -070071 {1.91113096927, 2.46074210438, 1.18284184739, 1.14982565193, 1.05017074788,
Alex Conversec1f911a2015-08-06 18:37:58 -070072 0.898018824055, 0.74725392039, 0.615105596242},
73 {2.46074210438, 1.58529308355, 1.21363250036, 1.38190029285, 1.33100189972,
74 1.17428548929, 0.996404342439, 0.830890433625},
75 {1.18284184739, 1.21363250036, 0.978712413627, 1.02624506078, 1.03145147362,
76 0.960060382087, 0.849823426169, 0.731221236837},
77 {1.14982565193, 1.38190029285, 1.02624506078, 0.861317501629,
78 0.801821139099, 0.751437590932, 0.685398513368, 0.608694761374},
79 {1.05017074788, 1.33100189972, 1.03145147362, 0.801821139099,
80 0.676555426187, 0.605503172737, 0.55002013668, 0.495804539034},
81 {0.898018824055, 1.17428548929, 0.960060382087, 0.751437590932,
82 0.605503172737, 0.514674450957, 0.454353482512, 0.407050308965},
83 {0.74725392039, 0.996404342439, 0.849823426169, 0.685398513368,
84 0.55002013668, 0.454353482512, 0.389234902883, 0.342353999733},
85 {0.615105596242, 0.830890433625, 0.731221236837, 0.608694761374,
86 0.495804539034, 0.407050308965, 0.342353999733, 0.295530605237}};
Yaowu Xu3c28b4a2016-02-08 09:41:43 -080087static const double csf_cr420[8][8] = {
Jim Bankoski9757c1a2015-04-17 10:27:56 -070088 {2.03871978502, 2.62502345193, 1.26180942886, 1.11019789803, 1.01397751469,
Alex Conversec1f911a2015-08-06 18:37:58 -070089 0.867069376285, 0.721500455585, 0.593906509971},
90 {2.62502345193, 1.69112867013, 1.17180569821, 1.3342742857, 1.28513006198,
91 1.13381474809, 0.962064122248, 0.802254508198},
92 {1.26180942886, 1.17180569821, 0.944981930573, 0.990876405848,
93 0.995903384143, 0.926972725286, 0.820534991409, 0.706020324706},
94 {1.11019789803, 1.3342742857, 0.990876405848, 0.831632933426, 0.77418706195,
95 0.725539939514, 0.661776842059, 0.587716619023},
96 {1.01397751469, 1.28513006198, 0.995903384143, 0.77418706195,
97 0.653238524286, 0.584635025748, 0.531064164893, 0.478717061273},
98 {0.867069376285, 1.13381474809, 0.926972725286, 0.725539939514,
99 0.584635025748, 0.496936637883, 0.438694579826, 0.393021669543},
100 {0.721500455585, 0.962064122248, 0.820534991409, 0.661776842059,
101 0.531064164893, 0.438694579826, 0.375820256136, 0.330555063063},
102 {0.593906509971, 0.802254508198, 0.706020324706, 0.587716619023,
103 0.478717061273, 0.393021669543, 0.330555063063, 0.285345396658}};
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700104
Yaowu Xubb8ca082016-02-05 13:03:47 -0800105static double convert_score_db(double _score, double _weight, int bit_depth) {
106 int16_t pix_max = 255;
Yaowu Xuefe1b1d2016-02-04 14:03:48 -0800107 assert(_score * _weight >= 0.0);
Yaowu Xubb8ca082016-02-05 13:03:47 -0800108 if (bit_depth == 10)
109 pix_max = 1023;
110 else if (bit_depth == 12)
111 pix_max = 4095;
112
113 if (_weight * _score < pix_max * pix_max * 1e-10)
Yaowu Xuefe1b1d2016-02-04 14:03:48 -0800114 return MAX_PSNR;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800115 return 10 * (log10(pix_max * pix_max) - log10(_weight * _score));
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700116}
117
Yaowu Xubb8ca082016-02-05 13:03:47 -0800118static double calc_psnrhvs(const unsigned char *src, int _systride,
119 const unsigned char *dst, int _dystride,
120 double _par, int _w, int _h, int _step,
121 const double _csf[8][8], uint32_t bit_depth) {
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800122 double ret;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800123 const uint8_t *_src8 = src;
124 const uint8_t *_dst8 = dst;
125 const uint16_t *_src16 = CONVERT_TO_SHORTPTR(src);
126 const uint16_t *_dst16 = CONVERT_TO_SHORTPTR(dst);
Yaowu Xub423a6b2015-04-20 16:44:12 -0700127 int16_t dct_s[8 * 8], dct_d[8 * 8];
128 tran_low_t dct_s_coef[8 * 8], dct_d_coef[8 * 8];
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800129 double mask[8][8];
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700130 int pixels;
131 int x;
132 int y;
133 (void) _par;
134 ret = pixels = 0;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800135
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700136 /*In the PSNR-HVS-M paper[1] the authors describe the construction of
137 their masking table as "we have used the quantization table for the
138 color component Y of JPEG [6] that has been also obtained on the
139 basis of CSF. Note that the values in quantization table JPEG have
140 been normalized and then squared." Their CSF matrix (from PSNR-HVS)
141 was also constructed from the JPEG matrices. I can not find any obvious
142 scheme of normalizing to produce their table, but if I multiply their
143 CSF by 0.38857 and square the result I get their masking table.
144 I have no idea where this constant comes from, but deviating from it
145 too greatly hurts MOS agreement.
146
147 [1] Nikolay Ponomarenko, Flavia Silvestri, Karen Egiazarian, Marco Carli,
148 Jaakko Astola, Vladimir Lukin, "On between-coefficient contrast masking
149 of DCT basis functions", CD-ROM Proceedings of the Third
150 International Workshop on Video Processing and Quality Metrics for Consumer
151 Electronics VPQM-07, Scottsdale, Arizona, USA, 25-26 January, 2007, 4 p.*/
152 for (x = 0; x < 8; x++)
153 for (y = 0; y < 8; y++)
154 mask[x][y] = (_csf[x][y] * 0.3885746225901003)
155 * (_csf[x][y] * 0.3885746225901003);
156 for (y = 0; y < _h - 7; y += _step) {
157 for (x = 0; x < _w - 7; x += _step) {
158 int i;
159 int j;
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800160 double s_means[4];
161 double d_means[4];
162 double s_vars[4];
163 double d_vars[4];
164 double s_gmean = 0;
165 double d_gmean = 0;
166 double s_gvar = 0;
167 double d_gvar = 0;
168 double s_mask = 0;
169 double d_mask = 0;
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700170 for (i = 0; i < 4; i++)
171 s_means[i] = d_means[i] = s_vars[i] = d_vars[i] = 0;
172 for (i = 0; i < 8; i++) {
173 for (j = 0; j < 8; j++) {
174 int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
Yaowu Xubb8ca082016-02-05 13:03:47 -0800175 if (bit_depth == 8) {
176 dct_s[i * 8 + j] = _src8[(y + i) * _systride + (j + x)];
177 dct_d[i * 8 + j] = _dst8[(y + i) * _dystride + (j + x)];
178 } else if (bit_depth == 10 || bit_depth == 12) {
179 dct_s[i * 8 + j] = _src16[(y + i) * _systride + (j + x)];
180 dct_d[i * 8 + j] = _dst16[(y + i) * _dystride + (j + x)];
181 }
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700182 s_gmean += dct_s[i * 8 + j];
183 d_gmean += dct_d[i * 8 + j];
184 s_means[sub] += dct_s[i * 8 + j];
185 d_means[sub] += dct_d[i * 8 + j];
186 }
187 }
188 s_gmean /= 64.f;
189 d_gmean /= 64.f;
190 for (i = 0; i < 4; i++)
191 s_means[i] /= 16.f;
192 for (i = 0; i < 4; i++)
193 d_means[i] /= 16.f;
194 for (i = 0; i < 8; i++) {
195 for (j = 0; j < 8; j++) {
196 int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
197 s_gvar += (dct_s[i * 8 + j] - s_gmean) * (dct_s[i * 8 + j] - s_gmean);
198 d_gvar += (dct_d[i * 8 + j] - d_gmean) * (dct_d[i * 8 + j] - d_gmean);
199 s_vars[sub] += (dct_s[i * 8 + j] - s_means[sub])
200 * (dct_s[i * 8 + j] - s_means[sub]);
201 d_vars[sub] += (dct_d[i * 8 + j] - d_means[sub])
202 * (dct_d[i * 8 + j] - d_means[sub]);
203 }
204 }
205 s_gvar *= 1 / 63.f * 64;
206 d_gvar *= 1 / 63.f * 64;
207 for (i = 0; i < 4; i++)
208 s_vars[i] *= 1 / 15.f * 16;
209 for (i = 0; i < 4; i++)
210 d_vars[i] *= 1 / 15.f * 16;
211 if (s_gvar > 0)
212 s_gvar = (s_vars[0] + s_vars[1] + s_vars[2] + s_vars[3]) / s_gvar;
213 if (d_gvar > 0)
214 d_gvar = (d_vars[0] + d_vars[1] + d_vars[2] + d_vars[3]) / d_gvar;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800215#if CONFIG_VP9_HIGHBITDEPTH
216 if (bit_depth == 10 || bit_depth == 12) {
217 hbd_od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
218 hbd_od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
219 }
220#endif
221 if (bit_depth == 8) {
222 od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
223 od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
224 }
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700225 for (i = 0; i < 8; i++)
226 for (j = (i == 0); j < 8; j++)
Yaowu Xub423a6b2015-04-20 16:44:12 -0700227 s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j];
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700228 for (i = 0; i < 8; i++)
229 for (j = (i == 0); j < 8; j++)
Yaowu Xub423a6b2015-04-20 16:44:12 -0700230 d_mask += dct_d_coef[i * 8 + j] * dct_d_coef[i * 8 + j] * mask[i][j];
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700231 s_mask = sqrt(s_mask * s_gvar) / 32.f;
232 d_mask = sqrt(d_mask * d_gvar) / 32.f;
233 if (d_mask > s_mask)
234 s_mask = d_mask;
235 for (i = 0; i < 8; i++) {
236 for (j = 0; j < 8; j++) {
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800237 double err;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800238 err = fabs((double)(dct_s_coef[i * 8 + j] - dct_d_coef[i * 8 + j]));
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700239 if (i != 0 || j != 0)
240 err = err < s_mask / mask[i][j] ? 0 : err - s_mask / mask[i][j];
241 ret += (err * _csf[i][j]) * (err * _csf[i][j]);
242 pixels++;
243 }
244 }
245 }
246 }
247 ret /= pixels;
248 return ret;
249}
Yaowu Xubb8ca082016-02-05 13:03:47 -0800250
Yaowu Xu6e695da2016-02-21 18:49:01 -0800251double vpx_psnrhvs(const YV12_BUFFER_CONFIG *src,
Alex Conversec1f911a2015-08-06 18:37:58 -0700252 const YV12_BUFFER_CONFIG *dest, double *y_psnrhvs,
Yaowu Xu6e695da2016-02-21 18:49:01 -0800253 double *u_psnrhvs, double *v_psnrhvs,
254 uint32_t bd, uint32_t in_bd) {
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700255 double psnrhvs;
Alex Conversec1f911a2015-08-06 18:37:58 -0700256 const double par = 1.0;
257 const int step = 7;
Alex Conversec7b70112015-08-06 12:53:59 -0700258 vpx_clear_system_state();
Yaowu Xubb8ca082016-02-05 13:03:47 -0800259
Yaowu Xu6e695da2016-02-21 18:49:01 -0800260 assert(bd == 8 || bd == 10 || bd == 12);
Yaowu Xubb8ca082016-02-05 13:03:47 -0800261
Yaowu Xu6e695da2016-02-21 18:49:01 -0800262 *y_psnrhvs = calc_psnrhvs(src->y_buffer, src->y_stride, dest->y_buffer,
263 dest->y_stride, par, src->y_crop_width,
264 src->y_crop_height, step, csf_y, bd);
265 *u_psnrhvs = calc_psnrhvs(src->u_buffer, src->uv_stride, dest->u_buffer,
266 dest->uv_stride, par, src->uv_crop_width,
267 src->uv_crop_height, step, csf_cb420, bd);
268 *v_psnrhvs = calc_psnrhvs(src->v_buffer, src->uv_stride, dest->v_buffer,
269 dest->uv_stride, par, src->uv_crop_width,
270 src->uv_crop_height, step, csf_cr420, bd);
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700271 psnrhvs = (*y_psnrhvs) * .8 + .1 * ((*u_psnrhvs) + (*v_psnrhvs));
Yaowu Xu6e695da2016-02-21 18:49:01 -0800272 return convert_score_db(psnrhvs, 1.0, bd);
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700273}
Yaowu Xubb8ca082016-02-05 13:03:47 -0800274