Commit bb72d637 authored by Yaowu Xu's avatar Yaowu Xu
Browse files

Enable computing PSNRHVS for highbitdepth build

Ported from libvpx/nextgenv2: bb8ca088

Change-Id: I911529bae9c125baf583e992453106190583fdc2
parent beb3ee3f
......@@ -11,9 +11,11 @@
* This code was originally written by: Gregory Maxwell, at the Daala
* project.
*/
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "./aom_config.h"
#include "./aom_dsp_rtcd.h"
......@@ -27,80 +29,105 @@
static void od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
int xstride) {
int i, j;
(void)xstride;
aom_fdct8x8(x, y, ystride);
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
*(y + ystride * i + j) = (*(y + ystride * i + j) + 4) >> 3;
}
#if CONFIG_AOM_HIGHBITDEPTH
static void hbd_od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
int xstride) {
int i, j;
(void)xstride;
aom_highbd_fdct8x8(x, y, ystride);
for (i = 0; i < 8; i++)
for (j = 0; j < 8; j++)
*(y + ystride * i + j) = (*(y + ystride * i + j) + 4) >> 3;
}
#endif
/* Normalized inverse quantization matrix for 8x8 DCT at the point of
* transparency. This is not the JPEG based matrix from the paper,
this one gives a slightly higher MOS agreement.*/
static const float csf_y[8][8] = {
{ 1.6193873005, 2.2901594831, 2.08509755623, 1.48366094411, 1.00227514334,
0.678296995242, 0.466224900598, 0.3265091542 },
{ 2.2901594831, 1.94321815382, 2.04793073064, 1.68731108984, 1.2305666963,
0.868920337363, 0.61280991668, 0.436405793551 },
{ 2.08509755623, 2.04793073064, 1.34329019223, 1.09205635862, 0.875748795257,
0.670882927016, 0.501731932449, 0.372504254596 },
{ 1.48366094411, 1.68731108984, 1.09205635862, 0.772819797575, 0.605636379554,
0.48309405692, 0.380429446972, 0.295774038565 },
{ 1.00227514334, 1.2305666963, 0.875748795257, 0.605636379554, 0.448996256676,
0.352889268808, 0.283006984131, 0.226951348204 },
{ 0.678296995242, 0.868920337363, 0.670882927016, 0.48309405692,
0.352889268808, 0.27032073436, 0.215017739696, 0.17408067321 },
{ 0.466224900598, 0.61280991668, 0.501731932449, 0.380429446972,
0.283006984131, 0.215017739696, 0.168869545842, 0.136153931001 },
{ 0.3265091542, 0.436405793551, 0.372504254596, 0.295774038565,
0.226951348204, 0.17408067321, 0.136153931001, 0.109083846276 }
};
static const float csf_cb420[8][8] = {
{ 1.91113096927, 2.46074210438, 1.18284184739, 1.14982565193, 1.05017074788,
0.898018824055, 0.74725392039, 0.615105596242 },
{ 2.46074210438, 1.58529308355, 1.21363250036, 1.38190029285, 1.33100189972,
1.17428548929, 0.996404342439, 0.830890433625 },
{ 1.18284184739, 1.21363250036, 0.978712413627, 1.02624506078, 1.03145147362,
0.960060382087, 0.849823426169, 0.731221236837 },
{ 1.14982565193, 1.38190029285, 1.02624506078, 0.861317501629, 0.801821139099,
0.751437590932, 0.685398513368, 0.608694761374 },
{ 1.05017074788, 1.33100189972, 1.03145147362, 0.801821139099, 0.676555426187,
0.605503172737, 0.55002013668, 0.495804539034 },
{ 0.898018824055, 1.17428548929, 0.960060382087, 0.751437590932,
0.605503172737, 0.514674450957, 0.454353482512, 0.407050308965 },
{ 0.74725392039, 0.996404342439, 0.849823426169, 0.685398513368,
0.55002013668, 0.454353482512, 0.389234902883, 0.342353999733 },
{ 0.615105596242, 0.830890433625, 0.731221236837, 0.608694761374,
0.495804539034, 0.407050308965, 0.342353999733, 0.295530605237 }
};
static const float csf_cr420[8][8] = {
{ 2.03871978502, 2.62502345193, 1.26180942886, 1.11019789803, 1.01397751469,
0.867069376285, 0.721500455585, 0.593906509971 },
{ 2.62502345193, 1.69112867013, 1.17180569821, 1.3342742857, 1.28513006198,
1.13381474809, 0.962064122248, 0.802254508198 },
{ 1.26180942886, 1.17180569821, 0.944981930573, 0.990876405848,
0.995903384143, 0.926972725286, 0.820534991409, 0.706020324706 },
{ 1.11019789803, 1.3342742857, 0.990876405848, 0.831632933426, 0.77418706195,
0.725539939514, 0.661776842059, 0.587716619023 },
{ 1.01397751469, 1.28513006198, 0.995903384143, 0.77418706195, 0.653238524286,
0.584635025748, 0.531064164893, 0.478717061273 },
{ 0.867069376285, 1.13381474809, 0.926972725286, 0.725539939514,
0.584635025748, 0.496936637883, 0.438694579826, 0.393021669543 },
{ 0.721500455585, 0.962064122248, 0.820534991409, 0.661776842059,
0.531064164893, 0.438694579826, 0.375820256136, 0.330555063063 },
{ 0.593906509971, 0.802254508198, 0.706020324706, 0.587716619023,
0.478717061273, 0.393021669543, 0.330555063063, 0.285345396658 }
};
static const double csf_y[8][8] = {
{1.6193873005, 2.2901594831, 2.08509755623, 1.48366094411, 1.00227514334,
0.678296995242, 0.466224900598, 0.3265091542},
{2.2901594831, 1.94321815382, 2.04793073064, 1.68731108984, 1.2305666963,
0.868920337363, 0.61280991668, 0.436405793551},
{2.08509755623, 2.04793073064, 1.34329019223, 1.09205635862, 0.875748795257,
0.670882927016, 0.501731932449, 0.372504254596},
{1.48366094411, 1.68731108984, 1.09205635862, 0.772819797575,
0.605636379554, 0.48309405692, 0.380429446972, 0.295774038565},
{1.00227514334, 1.2305666963, 0.875748795257, 0.605636379554,
0.448996256676, 0.352889268808, 0.283006984131, 0.226951348204},
{0.678296995242, 0.868920337363, 0.670882927016, 0.48309405692,
0.352889268808, 0.27032073436, 0.215017739696, 0.17408067321},
{0.466224900598, 0.61280991668, 0.501731932449, 0.380429446972,
0.283006984131, 0.215017739696, 0.168869545842, 0.136153931001},
{0.3265091542, 0.436405793551, 0.372504254596, 0.295774038565,
0.226951348204, 0.17408067321, 0.136153931001, 0.109083846276}};
static const double csf_cb420[8][8] = {
{1.91113096927, 2.46074210438, 1.18284184739, 1.14982565193, 1.05017074788,
0.898018824055, 0.74725392039, 0.615105596242},
{2.46074210438, 1.58529308355, 1.21363250036, 1.38190029285, 1.33100189972,
1.17428548929, 0.996404342439, 0.830890433625},
{1.18284184739, 1.21363250036, 0.978712413627, 1.02624506078, 1.03145147362,
0.960060382087, 0.849823426169, 0.731221236837},
{1.14982565193, 1.38190029285, 1.02624506078, 0.861317501629,
0.801821139099, 0.751437590932, 0.685398513368, 0.608694761374},
{1.05017074788, 1.33100189972, 1.03145147362, 0.801821139099,
0.676555426187, 0.605503172737, 0.55002013668, 0.495804539034},
{0.898018824055, 1.17428548929, 0.960060382087, 0.751437590932,
0.605503172737, 0.514674450957, 0.454353482512, 0.407050308965},
{0.74725392039, 0.996404342439, 0.849823426169, 0.685398513368,
0.55002013668, 0.454353482512, 0.389234902883, 0.342353999733},
{0.615105596242, 0.830890433625, 0.731221236837, 0.608694761374,
0.495804539034, 0.407050308965, 0.342353999733, 0.295530605237}};
static const double csf_cr420[8][8] = {
{2.03871978502, 2.62502345193, 1.26180942886, 1.11019789803, 1.01397751469,
0.867069376285, 0.721500455585, 0.593906509971},
{2.62502345193, 1.69112867013, 1.17180569821, 1.3342742857, 1.28513006198,
1.13381474809, 0.962064122248, 0.802254508198},
{1.26180942886, 1.17180569821, 0.944981930573, 0.990876405848,
0.995903384143, 0.926972725286, 0.820534991409, 0.706020324706},
{1.11019789803, 1.3342742857, 0.990876405848, 0.831632933426, 0.77418706195,
0.725539939514, 0.661776842059, 0.587716619023},
{1.01397751469, 1.28513006198, 0.995903384143, 0.77418706195,
0.653238524286, 0.584635025748, 0.531064164893, 0.478717061273},
{0.867069376285, 1.13381474809, 0.926972725286, 0.725539939514,
0.584635025748, 0.496936637883, 0.438694579826, 0.393021669543},
{0.721500455585, 0.962064122248, 0.820534991409, 0.661776842059,
0.531064164893, 0.438694579826, 0.375820256136, 0.330555063063},
{0.593906509971, 0.802254508198, 0.706020324706, 0.587716619023,
0.478717061273, 0.393021669543, 0.330555063063, 0.285345396658}};
static double convert_score_db(double _score, double _weight, int bit_depth) {
int16_t pix_max = 255;
assert(_score * _weight >= 0.0);
if (bit_depth == 10)
pix_max = 1023;
else if (bit_depth == 12)
pix_max = 4095;
static double convert_score_db(double _score, double _weight) {
return 10 * (log10(255 * 255) - log10(_weight * _score));
if (_weight * _score < pix_max * pix_max * 1e-10) return MAX_PSNR;
return 10 * (log10(pix_max * pix_max) - log10(_weight * _score));
}
static double calc_psnrhvs(const unsigned char *_src, int _systride,
const unsigned char *_dst, int _dystride,
double _par, int _w, int _h, int _step,
const float _csf[8][8]) {
float ret;
static double calc_psnrhvs(const unsigned char *src, int _systride,
const unsigned char *dst, int _dystride, double _par,
int _w, int _h, int _step, const double _csf[8][8],
uint32_t bit_depth) {
double ret;
const uint8_t *_src8 = src;
const uint8_t *_dst8 = dst;
const uint16_t *_src16 = CONVERT_TO_SHORTPTR(src);
const uint16_t *_dst16 = CONVERT_TO_SHORTPTR(dst);
int16_t dct_s[8 * 8], dct_d[8 * 8];
tran_low_t dct_s_coef[8 * 8], dct_d_coef[8 * 8];
float mask[8][8];
double mask[8][8];
int pixels;
int x;
int y;
......@@ -130,23 +157,28 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
for (x = 0; x < _w - 7; x += _step) {
int i;
int j;
float s_means[4];
float d_means[4];
float s_vars[4];
float d_vars[4];
float s_gmean = 0;
float d_gmean = 0;
float s_gvar = 0;
float d_gvar = 0;
float s_mask = 0;
float d_mask = 0;
double s_means[4];
double d_means[4];
double s_vars[4];
double d_vars[4];
double s_gmean = 0;
double d_gmean = 0;
double s_gvar = 0;
double d_gvar = 0;
double s_mask = 0;
double d_mask = 0;
for (i = 0; i < 4; i++)
s_means[i] = d_means[i] = s_vars[i] = d_vars[i] = 0;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
dct_s[i * 8 + j] = _src[(y + i) * _systride + (j + x)];
dct_d[i * 8 + j] = _dst[(y + i) * _dystride + (j + x)];
if (bit_depth == 8) {
dct_s[i * 8 + j] = _src8[(y + i) * _systride + (j + x)];
dct_d[i * 8 + j] = _dst8[(y + i) * _dystride + (j + x)];
} else if (bit_depth == 10 || bit_depth == 12) {
dct_s[i * 8 + j] = _src16[(y + i) * _systride + (j + x)];
dct_d[i * 8 + j] = _dst16[(y + i) * _dystride + (j + x)];
}
s_gmean += dct_s[i * 8 + j];
d_gmean += dct_d[i * 8 + j];
s_means[sub] += dct_s[i * 8 + j];
......@@ -176,8 +208,16 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
s_gvar = (s_vars[0] + s_vars[1] + s_vars[2] + s_vars[3]) / s_gvar;
if (d_gvar > 0)
d_gvar = (d_vars[0] + d_vars[1] + d_vars[2] + d_vars[3]) / d_gvar;
#if CONFIG_AOM_HIGHBITDEPTH
if (bit_depth == 10 || bit_depth == 12) {
hbd_od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
hbd_od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
}
#endif
if (bit_depth == 8) {
od_bin_fdct8x8(dct_s_coef, 8, dct_s, 8);
od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
}
for (i = 0; i < 8; i++)
for (j = (i == 0); j < 8; j++)
s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j];
......@@ -190,7 +230,7 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
float err;
err = fabs((float)(dct_s_coef[i * 8 + j] - dct_d_coef[i * 8 + j]));
err = fabs((double)(dct_s_coef[i * 8 + j] - dct_d_coef[i * 8 + j]));
if (i != 0 || j != 0)
err = err < s_mask / mask[i][j] ? 0 : err - s_mask / mask[i][j];
ret += (err * _csf[i][j]) * (err * _csf[i][j]);
......@@ -202,25 +242,28 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
ret /= pixels;
return ret;
}
double aom_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, double *y_psnrhvs,
double *u_psnrhvs, double *v_psnrhvs) {
double *u_psnrhvs, double *v_psnrhvs, uint32_t bit_depth) {
double psnrhvs;
const double par = 1.0;
const int step = 7;
aom_clear_system_state();
assert(bit_depth == 8 || bit_depth == 10 || bit_depth == 12);
*y_psnrhvs = calc_psnrhvs(source->y_buffer, source->y_stride, dest->y_buffer,
dest->y_stride, par, source->y_crop_width,
source->y_crop_height, step, csf_y);
source->y_crop_height, step, csf_y, bit_depth);
*u_psnrhvs = calc_psnrhvs(source->u_buffer, source->uv_stride, dest->u_buffer,
dest->uv_stride, par, source->uv_crop_width,
source->uv_crop_height, step, csf_cb420);
source->uv_crop_height, step, csf_cb420, bit_depth);
*v_psnrhvs = calc_psnrhvs(source->v_buffer, source->uv_stride, dest->v_buffer,
dest->uv_stride, par, source->uv_crop_width,
source->uv_crop_height, step, csf_cr420);
source->uv_crop_height, step, csf_cr420, bit_depth);
psnrhvs = (*y_psnrhvs) * .8 + .1 * ((*u_psnrhvs) + (*v_psnrhvs));
return convert_score_db(psnrhvs, 1.0);
return convert_score_db(psnrhvs, 1.0, bit_depth);
}
......@@ -12,6 +12,7 @@
#ifndef AOM_DSP_SSIM_H_
#define AOM_DSP_SSIM_H_
#define MAX_PSNR 100.0;
#define MAX_SSIM_DB 100.0;
#ifdef __cplusplus
......@@ -79,8 +80,8 @@ double aom_calc_fastssim(const YV12_BUFFER_CONFIG *source,
double *ssim_u, double *ssim_v, uint32_t bit_depth);
double aom_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, double *ssim_y,
double *ssim_u, double *ssim_v);
const YV12_BUFFER_CONFIG *dest, double *phvs_y,
double *phvs_u, double *phvs_v, uint32_t bit_depth);
#if CONFIG_AOM_HIGHBITDEPTH
double aom_highbd_calc_ssim(const YV12_BUFFER_CONFIG *source,
......
......@@ -44,8 +44,8 @@
#define ALIGN_POWER_OF_TWO(value, n) \
(((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1))
#if CONFIG_AOM_HIGHBITDEPTH
#define CONVERT_TO_SHORTPTR(x) ((uint16_t *)(((uintptr_t)x) << 1))
#if CONFIG_AOM_HIGHBITDEPTH
#define CONVERT_TO_BYTEPTR(x) ((uint8_t *)(((uintptr_t)x) >> 1))
#endif // CONFIG_AOM_HIGHBITDEPTH
......
......@@ -4088,14 +4088,9 @@ int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
frame_all = aom_calc_fastssim(cpi->Source, cm->frame_to_show, &y, &u,
&v, bit_depth);
adjust_image_stat(y, u, v, frame_all, &cpi->fastssim);
/* TODO(JBB): add 10/12 bit support */
}
#if CONFIG_AOM_HIGHBITDEPTH
if (!cm->use_highbitdepth)
#endif
{
double y, u, v, frame_all;
frame_all = aom_psnrhvs(cpi->Source, cm->frame_to_show, &y, &u, &v);
frame_all =
aom_psnrhvs(cpi->Source, cm->frame_to_show, &y, &u, &v, bit_depth);
adjust_image_stat(y, u, v, frame_all, &cpi->psnrhvs);
}
}
......
......@@ -31,6 +31,18 @@ typedef double (*LBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, uint32_t bd);
double compute_hbd_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, uint32_t bit_depth) {
double tempy, tempu, tempv;
return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, bit_depth);
}
double compute_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest) {
double tempy, tempu, tempv;
return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, 8);
}
double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest,
uint32_t bit_depth) {
......@@ -97,10 +109,35 @@ class HBDMetricsTestBase {
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, bit_depth_);
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
i = 0;
while (i < lbd_src.buffer_alloc_sz) {
uint16_t dpel;
// Create some small distortion for dst buffer.
dpel = 120 + (rnd.Rand8() >> 4);
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
i++;
}
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, bit_depth_);
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
printf("%10f \n", lbd_db);
printf("%10f \n", hbd_db);
i = 0;
while (i < lbd_src.buffer_alloc_sz) {
uint16_t dpel;
// Create some small distortion for dst buffer.
dpel = 126 + (rnd.Rand8() >> 6);
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
i++;
}
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, bit_depth_);
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
aom_free_frame_buffer(&lbd_src);
aom_free_frame_buffer(&lbd_dst);
aom_free_frame_buffer(&hbd_src);
......@@ -133,8 +170,10 @@ TEST_P(HBDMetricsTest, RunAccuracyCheck) { RunAccuracyCheck(); }
// Allow small variation due to floating point operations.
static const double kSsim_thresh = 0.001;
// Allow some variation from accumulated errors in floating point operations.
static const double kFSsim_thresh = 0.01;
// Allow some additional errors accumulated in floating point operations.
static const double kFSsim_thresh = 0.03;
// Allow some extra variation due to rounding error accumulated in dct.
static const double kPhvs_thresh = 0.3;
INSTANTIATE_TEST_CASE_P(
AOMSSIM, HBDMetricsTest,
......@@ -148,4 +187,10 @@ INSTANTIATE_TEST_CASE_P(
10, kFSsim_thresh),
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
12, kFSsim_thresh)));
INSTANTIATE_TEST_CASE_P(
PSNRHVS, HBDMetricsTest,
::testing::Values(MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
10, kPhvs_thresh),
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
12, kPhvs_thresh)));
} // namespace
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment