hbd_metrics_test.cc 6.79 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 *  Copyright (c) 2016 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#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"
#include "./vpx_config.h"
#include "vpx_dsp/ssim.h"
#include "vpx_ports/mem.h"
#include "vpx_ports/msvc.h"
#include "vpx_scale/yv12config.h"


using libvpx_test::ACMRandom;

namespace {

typedef double (*LBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
30
                                const YV12_BUFFER_CONFIG *dest);
31 32
typedef double (*HBDMetricFunc)(const YV12_BUFFER_CONFIG *source,
                                const YV12_BUFFER_CONFIG *dest,
33 34
                                uint32_t bd);

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

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);
}

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
double compute_hbd_fastssim(const YV12_BUFFER_CONFIG *source,
                            const YV12_BUFFER_CONFIG *dest,
                            uint32_t bit_depth) {
  double tempy, tempu, tempv;
  return vpx_calc_fastssim(source, dest,
                               &tempy, &tempu, &tempv, bit_depth);
}

double compute_fastssim(const YV12_BUFFER_CONFIG *source,
                        const YV12_BUFFER_CONFIG *dest) {
  double tempy, tempu, tempv;
  return vpx_calc_fastssim(source, dest,
                           &tempy, &tempu, &tempv, 8);
}

double compute_hbd_vpxssim(const YV12_BUFFER_CONFIG *source,
                           const YV12_BUFFER_CONFIG *dest,
                            uint32_t bit_depth) {
  double ssim, weight;
  ssim = vpx_highbd_calc_ssim(source, dest, &weight, bit_depth);
  return 100 * pow(ssim / weight, 8.0);
}

double compute_vpxssim(const YV12_BUFFER_CONFIG *source,
  const YV12_BUFFER_CONFIG *dest) {
  double ssim, weight;
  ssim = vpx_calc_ssim(source, dest, &weight);
  return 100 * pow(ssim / weight, 8.0);
}
80

81

82 83 84 85 86 87 88 89 90 91 92 93 94
class HBDMetricsTestBase {
 public:
  virtual ~HBDMetricsTestBase() {}

 protected:
  void RunAccuracyCheck() {
    const int width = 1920;
    const int height = 1080;
    int i = 0;
    const uint8_t kPixFiller = 128;
    YV12_BUFFER_CONFIG lbd_src, lbd_dst;
    YV12_BUFFER_CONFIG hbd_src, hbd_dst;
    ACMRandom rnd(ACMRandom::DeterministicSeed());
95
    double lbd_db, hbd_db;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

    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));

    vpx_alloc_frame_buffer(&lbd_src, width, height, 1, 1, 0, 32, 16);
    vpx_alloc_frame_buffer(&lbd_dst, width, height, 1, 1, 0, 32, 16);
    vpx_alloc_frame_buffer(&hbd_src, width, height, 1, 1, 1, 32, 16);
    vpx_alloc_frame_buffer(&hbd_dst, width, height, 1, 1, 1, 32, 16);

    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.
112 113
      dpel = rnd.Rand8();
      lbd_dst.buffer_alloc[i] = (uint8_t)dpel;
114 115 116 117 118
      ((uint16_t*)(hbd_src.buffer_alloc))[i] = spel << (bit_depth_ - 8);
      ((uint16_t*)(hbd_dst.buffer_alloc))[i] = dpel << (bit_depth_ - 8);
      i++;
    }

119 120
    lbd_db = lbd_metric_(&lbd_src, &lbd_dst);
    hbd_db = hbd_metric_(&hbd_src, &hbd_dst, bit_depth_);
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
    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_);
136

137 138 139 140 141 142 143 144 145 146 147 148 149
    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_);
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

    vpx_free_frame_buffer(&lbd_src);
    vpx_free_frame_buffer(&lbd_dst);
    vpx_free_frame_buffer(&hbd_src);
    vpx_free_frame_buffer(&hbd_dst);
  }

  int bit_depth_;
  double threshold_;
  LBDMetricFunc lbd_metric_;
  HBDMetricFunc hbd_metric_;
};

typedef std::tr1::tuple<LBDMetricFunc,
                        HBDMetricFunc, int, double> MetricTestTParam;
class HBDMetricsTest
    : public HBDMetricsTestBase,
      public ::testing::TestWithParam<MetricTestTParam> {
 public:
  virtual void SetUp() {
    lbd_metric_ = GET_PARAM(0);
    hbd_metric_ = GET_PARAM(1);
    bit_depth_ = GET_PARAM(2);
    threshold_ = GET_PARAM(3);
  }
  virtual void TearDown() {}
};

TEST_P(HBDMetricsTest, RunAccuracyCheck) {
  RunAccuracyCheck();
}

// Allow small variation due to floating point operations.
static const double kSsim_thresh = 0.001;
184 185 186 187
// 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;
188 189

INSTANTIATE_TEST_CASE_P(
190
    VPXSSIM, HBDMetricsTest,
191
    ::testing::Values(
192
        MetricTestTParam(&compute_vpxssim, &compute_hbd_vpxssim, 10,
193
                         kSsim_thresh),
194
        MetricTestTParam(&compute_vpxssim, &compute_hbd_vpxssim, 12,
195
                         kSsim_thresh)));
196 197 198 199 200 201 202
INSTANTIATE_TEST_CASE_P(
    FASTSSIM, HBDMetricsTest,
    ::testing::Values(
        MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 10,
                         kFSsim_thresh),
        MetricTestTParam(&compute_fastssim, &compute_hbd_fastssim, 12,
                         kFSsim_thresh)));
203 204 205 206 207 208 209 210
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)));

211 212
}  // namespace