2016-02-09 21:35:15 +03:00
|
|
|
/*
|
2016-09-02 22:04:54 +03:00
|
|
|
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
|
2016-02-09 21:35:15 +03:00
|
|
|
*
|
2016-09-02 22:04:54 +03:00
|
|
|
* This source code is subject to the terms of the BSD 2 Clause License and
|
|
|
|
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
|
|
|
|
* was not distributed with this source code in the LICENSE file, you can
|
|
|
|
* obtain it at www.aomedia.org/license/software. If the Alliance for Open
|
|
|
|
* Media Patent License 1.0 was not distributed with this source code in the
|
|
|
|
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
|
|
|
|
*/
|
2016-02-09 21:35:15 +03:00
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <new>
|
|
|
|
|
|
|
|
#include "third_party/googletest/src/include/gtest/gtest.h"
|
|
|
|
#include "test/acm_random.h"
|
|
|
|
#include "test/util.h"
|
2016-08-31 00:01:10 +03:00
|
|
|
#include "./aom_config.h"
|
2016-08-23 02:08:15 +03:00
|
|
|
#include "aom_dsp/psnr.h"
|
|
|
|
#include "aom_dsp/ssim.h"
|
|
|
|
#include "aom_ports/mem.h"
|
|
|
|
#include "aom_ports/msvc.h"
|
|
|
|
#include "aom_scale/yv12config.h"
|
2016-02-09 21:35:15 +03:00
|
|
|
|
2016-08-23 02:08:15 +03:00
|
|
|
using libaom_test::ACMRandom;
|
2016-02-09 21:35:15 +03:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
typedef double (*LBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
|
2016-02-05 22:30:12 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest);
|
2016-02-09 21:35:15 +03:00
|
|
|
typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
|
|
|
uint32_t bd);
|
2016-02-05 22:30:12 +03:00
|
|
|
|
2016-02-17 23:38:54 +03:00
|
|
|
double compute_hbd_psnr(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
|
|
|
uint32_t bd) {
|
2016-02-17 23:38:54 +03:00
|
|
|
PSNR_STATS psnr;
|
2016-08-31 00:01:10 +03:00
|
|
|
aom_calc_highbd_psnr(source, dest, &psnr, bd, in_bd);
|
2016-02-17 23:38:54 +03:00
|
|
|
return psnr.psnr[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
double compute_psnr(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest) {
|
2016-02-17 23:38:54 +03:00
|
|
|
PSNR_STATS psnr;
|
2016-08-31 00:01:10 +03:00
|
|
|
aom_calc_psnr(source, dest, &psnr);
|
2016-02-17 23:38:54 +03:00
|
|
|
return psnr.psnr[0];
|
|
|
|
}
|
2016-02-06 00:03:47 +03:00
|
|
|
|
|
|
|
double compute_hbd_psnrhvs(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
|
|
|
uint32_t bd) {
|
2016-02-06 00:03:47 +03:00
|
|
|
double tempy, tempu, tempv;
|
2016-08-31 00:01:10 +03:00
|
|
|
return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, bd, in_bd);
|
2016-02-06 00:03:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
double compute_psnrhvs(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest) {
|
2016-02-06 00:03:47 +03:00
|
|
|
double tempy, tempu, tempv;
|
2016-08-31 00:01:10 +03:00
|
|
|
return aom_psnrhvs(source, dest, &tempy, &tempu, &tempv, 8, 8);
|
2016-02-06 00:03:47 +03:00
|
|
|
}
|
|
|
|
|
2016-02-05 22:30:12 +03:00
|
|
|
double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
|
|
|
uint32_t bd) {
|
2016-02-05 22:30:12 +03:00
|
|
|
double tempy, tempu, tempv;
|
2016-08-31 00:01:10 +03:00
|
|
|
return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, bd, in_bd);
|
2016-02-05 22:30:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
double compute_fastssim(const YV12_BUFFER_CONFIG *source,
|
|
|
|
const YV12_BUFFER_CONFIG *dest) {
|
|
|
|
double tempy, tempu, tempv;
|
2016-08-31 00:01:10 +03:00
|
|
|
return aom_calc_fastssim(source, dest, &tempy, &tempu, &tempv, 8, 8);
|
2016-02-05 22:30:12 +03:00
|
|
|
}
|
|
|
|
|
2016-08-31 00:01:10 +03:00
|
|
|
double compute_hbd_aomssim(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest, uint32_t in_bd,
|
|
|
|
uint32_t bd) {
|
2016-02-05 22:30:12 +03:00
|
|
|
double ssim, weight;
|
2016-08-31 00:01:10 +03:00
|
|
|
ssim = aom_highbd_calc_ssim(source, dest, &weight, bd, in_bd);
|
2016-02-05 22:30:12 +03:00
|
|
|
return 100 * pow(ssim / weight, 8.0);
|
|
|
|
}
|
|
|
|
|
2016-08-31 00:01:10 +03:00
|
|
|
double compute_aomssim(const YV12_BUFFER_CONFIG *source,
|
2016-08-12 03:46:05 +03:00
|
|
|
const YV12_BUFFER_CONFIG *dest) {
|
2016-02-05 22:30:12 +03:00
|
|
|
double ssim, weight;
|
2016-08-31 00:01:10 +03:00
|
|
|
ssim = aom_calc_ssim(source, dest, &weight);
|
2016-02-05 22:30:12 +03:00
|
|
|
return 100 * pow(ssim / weight, 8.0);
|
|
|
|
}
|
2016-02-09 21:35:15 +03:00
|
|
|
|
|
|
|
class HBDMetricsTestBase {
|
|
|
|
public:
|
|
|
|
virtual ~HBDMetricsTestBase() {}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void RunAccuracyCheck() {
|
|
|
|
const int width = 1920;
|
|
|
|
const int height = 1080;
|
2016-08-30 21:48:44 +03:00
|
|
|
size_t i = 0;
|
2016-02-09 21:35:15 +03:00
|
|
|
const uint8_t kPixFiller = 128;
|
|
|
|
YV12_BUFFER_CONFIG lbd_src, lbd_dst;
|
|
|
|
YV12_BUFFER_CONFIG hbd_src, hbd_dst;
|
|
|
|
ACMRandom rnd(ACMRandom::DeterministicSeed());
|
2016-02-05 22:30:12 +03:00
|
|
|
double lbd_db, hbd_db;
|
2016-02-09 21:35:15 +03:00
|
|
|
|
|
|
|
memset(&lbd_src, 0, sizeof(lbd_src));
|
|
|
|
memset(&lbd_dst, 0, sizeof(lbd_dst));
|
|
|
|
memset(&hbd_src, 0, sizeof(hbd_src));
|
|
|
|
memset(&hbd_dst, 0, sizeof(hbd_dst));
|
|
|
|
|
2016-08-31 00:01:10 +03:00
|
|
|
aom_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16);
|
|
|
|
aom_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16);
|
|
|
|
aom_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16);
|
|
|
|
aom_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16);
|
2016-02-09 21:35:15 +03:00
|
|
|
|
|
|
|
memset(lbd_src.buffer_alloc, kPixFiller, lbd_src.buffer_alloc_sz);
|
|
|
|
while (i < lbd_src.buffer_alloc_sz) {
|
|
|
|
uint16_t spel, dpel;
|
|
|
|
spel = lbd_src.buffer_alloc[i];
|
|
|
|
// Create some distortion for dst buffer.
|
2016-02-05 22:30:12 +03:00
|
|
|
dpel = rnd.Rand8();
|
|
|
|
lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
|
2016-08-12 03:46:05 +03:00
|
|
|
((uint16_t *)(hbd_src.buffer_alloc))[i] = spel << (bit_depth_ - 8);
|
|
|
|
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
|
2016-02-09 21:35:15 +03:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2016-02-05 22:30:12 +03:00
|
|
|
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
|
2016-02-21 08:13:11 +03:00
|
|
|
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
|
2016-02-06 00:03:47 +03:00
|
|
|
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;
|
2016-08-12 03:46:05 +03:00
|
|
|
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
|
2016-02-06 00:03:47 +03:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
|
2016-02-21 08:13:11 +03:00
|
|
|
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
|
2016-02-06 00:03:47 +03:00
|
|
|
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
|
2016-02-09 21:35:15 +03:00
|
|
|
|
2016-02-06 00:03:47 +03:00
|
|
|
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;
|
2016-08-12 03:46:05 +03:00
|
|
|
((uint16_t *)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
|
2016-02-06 00:03:47 +03:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
|
2016-02-21 08:13:11 +03:00
|
|
|
hbd_db = hbd_metric_(&hbd_src, &hbd_dst, input_bit_depth_, bit_depth_);
|
2016-02-06 00:03:47 +03:00
|
|
|
EXPECT_LE(fabs(lbd_db - hbd_db), threshold_);
|
2016-02-09 21:35:15 +03:00
|
|
|
|
2016-08-31 00:01:10 +03:00
|
|
|
aom_free_frame_buffer(&lbd_src);
|
|
|
|
aom_free_frame_buffer(&lbd_dst);
|
|
|
|
aom_free_frame_buffer(&hbd_src);
|
|
|
|
aom_free_frame_buffer(&hbd_dst);
|
2016-02-09 21:35:15 +03:00
|
|
|
}
|
|
|
|
|
2016-02-21 08:13:11 +03:00
|
|
|
int input_bit_depth_;
|
2016-02-09 21:35:15 +03:00
|
|
|
int bit_depth_;
|
|
|
|
double threshold_;
|
|
|
|
LBDMetricFunc lbd_metric_;
|
|
|
|
HBDMetricFunc hbd_metric_;
|
|
|
|
};
|
|
|
|
|
2016-08-12 03:46:05 +03:00
|
|
|
typedef std::tr1::tuple<LBDMetricFunc, HBDMetricFunc, int, int, double>
|
|
|
|
MetricTestTParam;
|
|
|
|
class HBDMetricsTest : public HBDMetricsTestBase,
|
|
|
|
public ::testing::TestWithParam<MetricTestTParam> {
|
2016-02-09 21:35:15 +03:00
|
|
|
public:
|
|
|
|
virtual void SetUp() {
|
|
|
|
lbd_metric_ = GET_PARAM(0);
|
|
|
|
hbd_metric_ = GET_PARAM(1);
|
2016-02-21 08:13:11 +03:00
|
|
|
input_bit_depth_ = GET_PARAM(2);
|
|
|
|
bit_depth_ = GET_PARAM(3);
|
|
|
|
threshold_ = GET_PARAM(4);
|
2016-02-09 21:35:15 +03:00
|
|
|
}
|
|
|
|
virtual void TearDown() {}
|
|
|
|
};
|
|
|
|
|
2016-08-12 03:46:05 +03:00
|
|
|
TEST_P(HBDMetricsTest, RunAccuracyCheck) { RunAccuracyCheck(); }
|
2016-02-09 21:35:15 +03:00
|
|
|
|
|
|
|
// Allow small variation due to floating point operations.
|
|
|
|
static const double kSsim_thresh = 0.001;
|
2016-02-06 00:03:47 +03:00
|
|
|
// 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;
|
2016-02-09 21:35:15 +03:00
|
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
2016-08-31 00:01:10 +03:00
|
|
|
AOMSSIM, HBDMetricsTest,
|
|
|
|
::testing::Values(MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
2016-08-12 03:46:05 +03:00
|
|
|
8, 10, kSsim_thresh),
|
2016-08-31 00:01:10 +03:00
|
|
|
MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
2016-08-12 03:46:05 +03:00
|
|
|
10, 10, kPhvs_thresh),
|
2016-08-31 00:01:10 +03:00
|
|
|
MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
2016-08-12 03:46:05 +03:00
|
|
|
8, 12, kSsim_thresh),
|
2016-08-31 00:01:10 +03:00
|
|
|
MetricTestTParam(&compute_aomssim, &compute_hbd_aomssim,
|
2016-08-12 03:46:05 +03:00
|
|
|
12, 12, kPhvs_thresh)));
|
2016-02-05 22:30:12 +03:00
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
|
|
FASTSSIM, HBDMetricsTest,
|
2016-08-12 03:46:05 +03:00
|
|
|
::testing::Values(MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
|
|
|
8, 10, kFSsim_thresh),
|
|
|
|
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
|
|
|
10, 10, kFSsim_thresh),
|
|
|
|
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
|
|
|
8, 12, kFSsim_thresh),
|
|
|
|
MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim,
|
|
|
|
12, 12, kFSsim_thresh)));
|
2016-02-06 00:03:47 +03:00
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
|
|
PSNRHVS, HBDMetricsTest,
|
2016-08-12 03:46:05 +03:00
|
|
|
::testing::Values(MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
|
|
|
8, 10, kPhvs_thresh),
|
|
|
|
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
|
|
|
10, 10, kPhvs_thresh),
|
|
|
|
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
|
|
|
8, 12, kPhvs_thresh),
|
|
|
|
MetricTestTParam(&compute_psnrhvs, &compute_hbd_psnrhvs,
|
|
|
|
12, 12, kPhvs_thresh)));
|
2016-02-17 23:38:54 +03:00
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
|
|
PSNR, HBDMetricsTest,
|
|
|
|
::testing::Values(
|
2016-08-12 03:46:05 +03:00
|
|
|
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 10, kPhvs_thresh),
|
2016-02-21 08:13:11 +03:00
|
|
|
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 10, 10,
|
2016-02-17 23:38:54 +03:00
|
|
|
kPhvs_thresh),
|
2016-08-12 03:46:05 +03:00
|
|
|
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 8, 12, kPhvs_thresh),
|
2016-02-21 08:13:11 +03:00
|
|
|
MetricTestTParam(&compute_psnr, &compute_hbd_psnr, 12, 12,
|
2016-02-17 23:38:54 +03:00
|
|
|
kPhvs_thresh)));
|
2016-02-09 21:35:15 +03:00
|
|
|
} // namespace
|