Commit 89a1ab39 authored by Yaowu Xu's avatar Yaowu Xu Committed by Gerrit Code Review
Browse files

Merge "Enable computing PSNRHVS for hbd build" into nextgenv2

parents c1924b9f bb8ca088
...@@ -32,6 +32,22 @@ typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source, ...@@ -32,6 +32,22 @@ typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, const YV12_BUFFER_CONFIG *dest,
uint32_t bd); 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 vpx_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 vpx_psnrhvs(source, dest,
&tempy, &tempu, &tempv, 8);
}
double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source, double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, const YV12_BUFFER_CONFIG *dest,
uint32_t bit_depth) { uint32_t bit_depth) {
...@@ -62,6 +78,7 @@ double compute_vpxssim(const YV12_BUFFER_CONFIG *source, ...@@ -62,6 +78,7 @@ double compute_vpxssim(const YV12_BUFFER_CONFIG *source,
return 100 * pow(ssim / weight, 8.0); return 100 * pow(ssim / weight, 8.0);
} }
class HBDMetricsTestBase { class HBDMetricsTestBase {
public: public:
virtual ~HBDMetricsTestBase() {} virtual ~HBDMetricsTestBase() {}
...@@ -101,16 +118,40 @@ class HBDMetricsTestBase { ...@@ -101,16 +118,40 @@ class HBDMetricsTestBase {
lbd_db = lbd_metric_(&lbd_src, &lbd_dst); lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, bit_depth_); 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); i = 0;
printf("%10f \n", hbd_db); 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_);
vpx_free_frame_buffer(&lbd_src); vpx_free_frame_buffer(&lbd_src);
vpx_free_frame_buffer(&lbd_dst); vpx_free_frame_buffer(&lbd_dst);
vpx_free_frame_buffer(&hbd_src); vpx_free_frame_buffer(&hbd_src);
vpx_free_frame_buffer(&hbd_dst); vpx_free_frame_buffer(&hbd_dst);
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
} }
int bit_depth_; int bit_depth_;
...@@ -140,8 +181,10 @@ TEST_P(HBDMetricsTest, RunAccuracyCheck) { ...@@ -140,8 +181,10 @@ TEST_P(HBDMetricsTest, RunAccuracyCheck) {
// Allow small variation due to floating point operations. // Allow small variation due to floating point operations.
static const double kSsim_thresh = 0.001; static const double kSsim_thresh = 0.001;
// Allow some variation from accumulated errors in floating point operations. // Allow some additional errors accumulated in floating point operations.
static const double kFSsim_thresh = 0.01; 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( INSTANTIATE_TEST_CASE_P(
VPXSSIM, HBDMetricsTest, VPXSSIM, HBDMetricsTest,
...@@ -157,5 +200,13 @@ INSTANTIATE_TEST_CASE_P( ...@@ -157,5 +200,13 @@ INSTANTIATE_TEST_CASE_P(
kFSsim_thresh), kFSsim_thresh),
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 12, MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 12,
kFSsim_thresh))); 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 } // namespace
...@@ -4509,13 +4509,7 @@ int vp10_get_compressed_data(VP10_COMP *cpi, unsigned int *frame_flags, ...@@ -4509,13 +4509,7 @@ int vp10_get_compressed_data(VP10_COMP *cpi, unsigned int *frame_flags,
double y, u, v, frame_all; double y, u, v, frame_all;
frame_all = vpx_calc_fastssim(orig, recon, &y, &u, &v, bit_depth); frame_all = vpx_calc_fastssim(orig, recon, &y, &u, &v, bit_depth);
adjust_image_stat(y, u, v, frame_all, &cpi->fastssim); adjust_image_stat(y, u, v, frame_all, &cpi->fastssim);
} frame_all = vpx_psnrhvs(orig, recon, &y, &u, &v, bit_depth);
#if CONFIG_VP9_HIGHBITDEPTH
if (!cm->use_highbitdepth)
#endif
{
double y, u, v, frame_all;
frame_all = vpx_psnrhvs(orig, recon, &y, &u, &v);
adjust_image_stat(y, u, v, frame_all, &cpi->psnrhvs); adjust_image_stat(y, u, v, frame_all, &cpi->psnrhvs);
} }
} }
......
...@@ -4681,12 +4681,10 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags, ...@@ -4681,12 +4681,10 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
&v, bit_depth); &v, bit_depth);
adjust_image_stat(y, u, v, frame_all, &cpi->fastssim); adjust_image_stat(y, u, v, frame_all, &cpi->fastssim);
} }
#if CONFIG_VP9_HIGHBITDEPTH
if (!cm->use_highbitdepth)
#endif
{ {
double y, u, v, frame_all; double y, u, v, frame_all;
frame_all = vpx_psnrhvs(cpi->Source, cm->frame_to_show, &y, &u, &v); frame_all = vpx_psnrhvs(cpi->Source, cm->frame_to_show, &y, &u, &v,
bit_depth);
adjust_image_stat(y, u, v, frame_all, &cpi->psnrhvs); adjust_image_stat(y, u, v, frame_all, &cpi->psnrhvs);
} }
} }
......
...@@ -506,8 +506,6 @@ static double calc_ssim(const unsigned char *_src, int _systride, ...@@ -506,8 +506,6 @@ static double calc_ssim(const unsigned char *_src, int _systride,
} }
#define CONVERT_TO_SHORTPTR(x) ((uint16_t*)(((uintptr_t)(x)) << 1))
static double calc_hbd_ssim(const uint8_t *_src, int _systride, static double calc_hbd_ssim(const uint8_t *_src, int _systride,
const uint8_t *_dst, int _dystride, const uint8_t *_dst, int _dystride,
int _w, int _h, uint32_t bit_depth) { int _w, int _h, uint32_t bit_depth) {
......
...@@ -35,6 +35,17 @@ static void od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x, ...@@ -35,6 +35,17 @@ static void od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
for (j = 0; j< 8; j++) for (j = 0; j< 8; j++)
*(y + ystride*i + j) = (*(y + ystride*i + j) + 4) >> 3; *(y + ystride*i + j) = (*(y + ystride*i + j) + 4) >> 3;
} }
#if CONFIG_VP9_HIGHBITDEPTH
static void hbd_od_bin_fdct8x8(tran_low_t *y, int ystride, const int16_t *x,
int xstride) {
int i, j;
(void) xstride;
vpx_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 /* Normalized inverse quantization matrix for 8x8 DCT at the point of
* transparency. This is not the JPEG based matrix from the paper, * transparency. This is not the JPEG based matrix from the paper,
...@@ -91,18 +102,28 @@ static const double csf_cr420[8][8] = { ...@@ -91,18 +102,28 @@ static const double csf_cr420[8][8] = {
{0.593906509971, 0.802254508198, 0.706020324706, 0.587716619023, {0.593906509971, 0.802254508198, 0.706020324706, 0.587716619023,
0.478717061273, 0.393021669543, 0.330555063063, 0.285345396658}}; 0.478717061273, 0.393021669543, 0.330555063063, 0.285345396658}};
static double convert_score_db(double _score, double _weight) { static double convert_score_db(double _score, double _weight, int bit_depth) {
int16_t pix_max = 255;
assert(_score * _weight >= 0.0); assert(_score * _weight >= 0.0);
if (_weight * _score < 255 * 255 * 1e-10) if (bit_depth == 10)
pix_max = 1023;
else if (bit_depth == 12)
pix_max = 4095;
if (_weight * _score < pix_max * pix_max * 1e-10)
return MAX_PSNR; return MAX_PSNR;
return 10 * (log10(255 * 255) - log10(_weight * _score)); return 10 * (log10(pix_max * pix_max) - log10(_weight * _score));
} }
static double calc_psnrhvs(const unsigned char *_src, int _systride, static double calc_psnrhvs(const unsigned char *src, int _systride,
const unsigned char *_dst, int _dystride, const unsigned char *dst, int _dystride,
double _par, int _w, int _h, int _step, double _par, int _w, int _h, int _step,
const double _csf[8][8]) { const double _csf[8][8], uint32_t bit_depth) {
double ret; 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]; int16_t dct_s[8 * 8], dct_d[8 * 8];
tran_low_t dct_s_coef[8 * 8], dct_d_coef[8 * 8]; tran_low_t dct_s_coef[8 * 8], dct_d_coef[8 * 8];
double mask[8][8]; double mask[8][8];
...@@ -111,6 +132,7 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride, ...@@ -111,6 +132,7 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
int y; int y;
(void) _par; (void) _par;
ret = pixels = 0; ret = pixels = 0;
/*In the PSNR-HVS-M paper[1] the authors describe the construction of /*In the PSNR-HVS-M paper[1] the authors describe the construction of
their masking table as "we have used the quantization table for the their masking table as "we have used the quantization table for the
color component Y of JPEG [6] that has been also obtained on the color component Y of JPEG [6] that has been also obtained on the
...@@ -150,8 +172,13 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride, ...@@ -150,8 +172,13 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
int sub = ((i & 12) >> 2) + ((j & 12) >> 1); int sub = ((i & 12) >> 2) + ((j & 12) >> 1);
dct_s[i * 8 + j] = _src[(y + i) * _systride + (j + x)]; if (bit_depth == 8) {
dct_d[i * 8 + j] = _dst[(y + i) * _dystride + (j + x)]; 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]; s_gmean += dct_s[i * 8 + j];
d_gmean += dct_d[i * 8 + j]; d_gmean += dct_d[i * 8 + j];
s_means[sub] += dct_s[i * 8 + j]; s_means[sub] += dct_s[i * 8 + j];
...@@ -185,8 +212,16 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride, ...@@ -185,8 +212,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; s_gvar = (s_vars[0] + s_vars[1] + s_vars[2] + s_vars[3]) / s_gvar;
if (d_gvar > 0) if (d_gvar > 0)
d_gvar = (d_vars[0] + d_vars[1] + d_vars[2] + d_vars[3]) / d_gvar; d_gvar = (d_vars[0] + d_vars[1] + d_vars[2] + d_vars[3]) / d_gvar;
#if CONFIG_VP9_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_s_coef, 8, dct_s, 8);
od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8); od_bin_fdct8x8(dct_d_coef, 8, dct_d, 8);
}
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
for (j = (i == 0); j < 8; j++) for (j = (i == 0); j < 8; j++)
s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j]; s_mask += dct_s_coef[i * 8 + j] * dct_s_coef[i * 8 + j] * mask[i][j];
...@@ -200,7 +235,7 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride, ...@@ -200,7 +235,7 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
double err; double 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) if (i != 0 || j != 0)
err = err < s_mask / mask[i][j] ? 0 : err - s_mask / mask[i][j]; err = err < s_mask / mask[i][j] ? 0 : err - s_mask / mask[i][j];
ret += (err * _csf[i][j]) * (err * _csf[i][j]); ret += (err * _csf[i][j]) * (err * _csf[i][j]);
...@@ -212,25 +247,28 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride, ...@@ -212,25 +247,28 @@ static double calc_psnrhvs(const unsigned char *_src, int _systride,
ret /= pixels; ret /= pixels;
return ret; return ret;
} }
double vpx_psnrhvs(const YV12_BUFFER_CONFIG *source, double vpx_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, double *y_psnrhvs, 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; double psnrhvs;
const double par = 1.0; const double par = 1.0;
const int step = 7; const int step = 7;
vpx_clear_system_state(); vpx_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, *y_psnrhvs = calc_psnrhvs(source->y_buffer, source->y_stride, dest->y_buffer,
dest->y_stride, par, source->y_crop_width, 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, *u_psnrhvs = calc_psnrhvs(source->u_buffer, source->uv_stride, dest->u_buffer,
dest->uv_stride, par, source->uv_crop_width, 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, *v_psnrhvs = calc_psnrhvs(source->v_buffer, source->uv_stride, dest->v_buffer,
dest->uv_stride, par, source->uv_crop_width, 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)); psnrhvs = (*y_psnrhvs) * .8 + .1 * ((*u_psnrhvs) + (*v_psnrhvs));
return convert_score_db(psnrhvs, 1.0, bit_depth);
return convert_score_db(psnrhvs, 1.0);
} }
...@@ -77,7 +77,8 @@ double vpx_calc_fastssim(const YV12_BUFFER_CONFIG *source, ...@@ -77,7 +77,8 @@ double vpx_calc_fastssim(const YV12_BUFFER_CONFIG *source,
double vpx_psnrhvs(const YV12_BUFFER_CONFIG *source, double vpx_psnrhvs(const YV12_BUFFER_CONFIG *source,
const YV12_BUFFER_CONFIG *dest, const YV12_BUFFER_CONFIG *dest,
double *ssim_y, double *ssim_u, double *ssim_v); double *phvs_y, double *phvs_u,
double *phvs_v, uint32_t bit_depth);
#if CONFIG_VP9_HIGHBITDEPTH #if CONFIG_VP9_HIGHBITDEPTH
double vpx_highbd_calc_ssim(const YV12_BUFFER_CONFIG *source, double vpx_highbd_calc_ssim(const YV12_BUFFER_CONFIG *source,
......
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
#define ALIGN_POWER_OF_TWO(value, n) \ #define ALIGN_POWER_OF_TWO(value, n) \
(((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1)) (((value) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1))
#if CONFIG_VP9_HIGHBITDEPTH
#define CONVERT_TO_SHORTPTR(x) ((uint16_t*)(((uintptr_t)(x)) << 1)) #define CONVERT_TO_SHORTPTR(x) ((uint16_t*)(((uintptr_t)(x)) << 1))
#if CONFIG_VP9_HIGHBITDEPTH
#define CONVERT_TO_BYTEPTR(x) ((uint8_t*)(((uintptr_t)(x)) >> 1)) #define CONVERT_TO_BYTEPTR(x) ((uint8_t*)(((uintptr_t)(x)) >> 1))
#endif // CONFIG_VP9_HIGHBITDEPTH #endif // CONFIG_VP9_HIGHBITDEPTH
......
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