blob: 095ba5d13b6f72d8df265cbd6b4c686fb8afc7f7 [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,
Yaowu Xu195bf522016-02-22 10:22:42 -0800121 const double _csf[8][8], uint32_t bit_depth,
122 uint32_t _shift) {
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800123 double ret;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800124 const uint8_t *_src8 = src;
125 const uint8_t *_dst8 = dst;
126 const uint16_t *_src16 = CONVERT_TO_SHORTPTR(src);
127 const uint16_t *_dst16 = CONVERT_TO_SHORTPTR(dst);
Yaowu Xub423a6b2015-04-20 16:44:12 -0700128 int16_t dct_s[8 * 8], dct_d[8 * 8];
129 tran_low_t dct_s_coef[8 * 8], dct_d_coef[8 * 8];
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800130 double mask[8][8];
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700131 int pixels;
132 int x;
133 int y;
134 (void) _par;
135 ret = pixels = 0;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800136
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700137 /*In the PSNR-HVS-M paper[1] the authors describe the construction of
138 their masking table as "we have used the quantization table for the
139 color component Y of JPEG [6] that has been also obtained on the
140 basis of CSF. Note that the values in quantization table JPEG have
141 been normalized and then squared." Their CSF matrix (from PSNR-HVS)
142 was also constructed from the JPEG matrices. I can not find any obvious
143 scheme of normalizing to produce their table, but if I multiply their
144 CSF by 0.38857 and square the result I get their masking table.
145 I have no idea where this constant comes from, but deviating from it
146 too greatly hurts MOS agreement.
147
148 [1] Nikolay Ponomarenko, Flavia Silvestri, Karen Egiazarian, Marco Carli,
149 Jaakko Astola, Vladimir Lukin, "On between-coefficient contrast masking
150 of DCT basis functions", CD-ROM Proceedings of the Third
151 International Workshop on Video Processing and Quality Metrics for Consumer
152 Electronics VPQM-07, Scottsdale, Arizona, USA, 25-26 January, 2007, 4 p.*/
153 for (x = 0; x < 8; x++)
154 for (y = 0; y < 8; y++)
155 mask[x][y] = (_csf[x][y] * 0.3885746225901003)
156 * (_csf[x][y] * 0.3885746225901003);
157 for (y = 0; y < _h - 7; y += _step) {
158 for (x = 0; x < _w - 7; x += _step) {
159 int i;
160 int j;
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800161 double s_means[4];
162 double d_means[4];
163 double s_vars[4];
164 double d_vars[4];
165 double s_gmean = 0;
166 double d_gmean = 0;
167 double s_gvar = 0;
168 double d_gvar = 0;
169 double s_mask = 0;
170 double d_mask = 0;
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700171 for (i = 0; i < 4; i++)
172 s_means[i] = d_means[i] = s_vars[i] = d_vars[i] = 0;
173 for (i = 0; i < 8; i++) {
174 for (j = 0; j < 8; j++) {
175 int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
Yaowu Xu195bf522016-02-22 10:22:42 -0800176 if (bit_depth == 8 && _shift == 0) {
Yaowu Xubb8ca082016-02-05 13:03:47 -0800177 dct_s[i * 8 + j] = _src8[(y + i) * _systride + (j + x)];
178 dct_d[i * 8 + j] = _dst8[(y + i) * _dystride + (j + x)];
179 } else if (bit_depth == 10 || bit_depth == 12) {
Yaowu Xu195bf522016-02-22 10:22:42 -0800180 dct_s[i * 8 + j] = _src16[(y + i) * _systride + (j + x)] >> _shift;
181 dct_d[i * 8 + j] = _dst16[(y + i) * _dystride + (j + x)] >> _shift;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800182 }
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700183 s_gmean += dct_s[i * 8 + j];
184 d_gmean += dct_d[i * 8 + j];
185 s_means[sub] += dct_s[i * 8 + j];
186 d_means[sub] += dct_d[i * 8 + j];
187 }
188 }
189 s_gmean /= 64.f;
190 d_gmean /= 64.f;
191 for (i = 0; i < 4; i++)
192 s_means[i] /= 16.f;
193 for (i = 0; i < 4; i++)
194 d_means[i] /= 16.f;
195 for (i = 0; i < 8; i++) {
196 for (j = 0; j < 8; j++) {
197 int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
198 s_gvar += (dct_s[i * 8 + j] - s_gmean) * (dct_s[i * 8 + j] - s_gmean);
199 d_gvar += (dct_d[i * 8 + j] - d_gmean) * (dct_d[i * 8 + j] - d_gmean);
200 s_vars[sub] += (dct_s[i * 8 + j] - s_means[sub])
201 * (dct_s[i * 8 + j] - s_means[sub]);
202 d_vars[sub] += (dct_d[i * 8 + j] - d_means[sub])
203 * (dct_d[i * 8 + j] - d_means[sub]);
204 }
205 }
206 s_gvar *= 1 / 63.f * 64;
207 d_gvar *= 1 / 63.f * 64;
208 for (i = 0; i < 4; i++)
209 s_vars[i] *= 1 / 15.f * 16;
210 for (i = 0; i < 4; i++)
211 d_vars[i] *= 1 / 15.f * 16;
212 if (s_gvar > 0)
213 s_gvar = (s_vars[0] + s_vars[1] + s_vars[2] + s_vars[3]) / s_gvar;
214 if (d_gvar > 0)
215 d_gvar = (d_vars[0] + d_vars[1] + d_vars[2] + d_vars[3]) / d_gvar;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800216#if CONFIG_VP9_HIGHBITDEPTH
217 if (bit_depth == 10 || bit_depth == 12) {
218 hbd_od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
219 hbd_od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
220 }
221#endif
222 if (bit_depth == 8) {
223 od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
224 od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
225 }
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700226 for (i = 0; i < 8; i++)
227 for (j = (i == 0); j < 8; j++)
Yaowu Xub423a6b2015-04-20 16:44:12 -0700228 s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j];
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700229 for (i = 0; i < 8; i++)
230 for (j = (i == 0); j < 8; j++)
Yaowu Xub423a6b2015-04-20 16:44:12 -0700231 d_mask += dct_d_coef[i * 8 + j] * dct_d_coef[i * 8 + j] * mask[i][j];
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700232 s_mask = sqrt(s_mask * s_gvar) / 32.f;
233 d_mask = sqrt(d_mask * d_gvar) / 32.f;
234 if (d_mask > s_mask)
235 s_mask = d_mask;
236 for (i = 0; i < 8; i++) {
237 for (j = 0; j < 8; j++) {
Yaowu Xu3c28b4a2016-02-08 09:41:43 -0800238 double err;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800239 err = fabs((double)(dct_s_coef[i * 8 + j] - dct_d_coef[i * 8 + j]));
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700240 if (i != 0 || j != 0)
241 err = err < s_mask / mask[i][j] ? 0 : err - s_mask / mask[i][j];
242 ret += (err * _csf[i][j]) * (err * _csf[i][j]);
243 pixels++;
244 }
245 }
246 }
247 }
248 ret /= pixels;
249 return ret;
250}
Yaowu Xubb8ca082016-02-05 13:03:47 -0800251
Yaowu Xu6e695da2016-02-21 18:49:01 -0800252double vpx_psnrhvs(const YV12_BUFFER_CONFIG *src,
Alex Conversec1f911a2015-08-06 18:37:58 -0700253 const YV12_BUFFER_CONFIG *dest, double *y_psnrhvs,
Yaowu Xu6e695da2016-02-21 18:49:01 -0800254 double *u_psnrhvs, double *v_psnrhvs,
255 uint32_t bd, uint32_t in_bd) {
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700256 double psnrhvs;
Alex Conversec1f911a2015-08-06 18:37:58 -0700257 const double par = 1.0;
258 const int step = 7;
Yaowu Xu195bf522016-02-22 10:22:42 -0800259 uint32_t bd_shift = 0;
Alex Conversec7b70112015-08-06 12:53:59 -0700260 vpx_clear_system_state();
Yaowu Xubb8ca082016-02-05 13:03:47 -0800261
Yaowu Xu6e695da2016-02-21 18:49:01 -0800262 assert(bd == 8 || bd == 10 || bd == 12);
Yaowu Xu195bf522016-02-22 10:22:42 -0800263 assert(bd >= in_bd);
264
265 bd_shift = bd - in_bd;
Yaowu Xubb8ca082016-02-05 13:03:47 -0800266
Yaowu Xu6e695da2016-02-21 18:49:01 -0800267 *y_psnrhvs = calc_psnrhvs(src->y_buffer, src->y_stride, dest->y_buffer,
268 dest->y_stride, par, src->y_crop_width,
Yaowu Xu195bf522016-02-22 10:22:42 -0800269 src->y_crop_height, step, csf_y, bd,
270 bd_shift);
Yaowu Xu6e695da2016-02-21 18:49:01 -0800271 *u_psnrhvs = calc_psnrhvs(src->u_buffer, src->uv_stride, dest->u_buffer,
272 dest->uv_stride, par, src->uv_crop_width,
Yaowu Xu195bf522016-02-22 10:22:42 -0800273 src->uv_crop_height, step, csf_cb420, bd,
274 bd_shift);
Yaowu Xu6e695da2016-02-21 18:49:01 -0800275 *v_psnrhvs = calc_psnrhvs(src->v_buffer, src->uv_stride, dest->v_buffer,
276 dest->uv_stride, par, src->uv_crop_width,
Yaowu Xu195bf522016-02-22 10:22:42 -0800277 src->uv_crop_height, step, csf_cr420, bd,
278 bd_shift);
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700279 psnrhvs = (*y_psnrhvs) * .8 + .1 * ((*u_psnrhvs) + (*v_psnrhvs));
Yaowu Xu195bf522016-02-22 10:22:42 -0800280 return convert_score_db(psnrhvs, 1.0, in_bd);
Jim Bankoski9757c1a2015-04-17 10:27:56 -0700281}
Yaowu Xubb8ca082016-02-05 13:03:47 -0800282