tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

picture_psnr_enc.c (8592B)


      1 // Copyright 2014 Google Inc. All Rights Reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style license
      4 // that can be found in the COPYING file in the root of the source
      5 // tree. An additional intellectual property rights grant can be found
      6 // in the file PATENTS. All contributing project authors may
      7 // be found in the AUTHORS file in the root of the source tree.
      8 // -----------------------------------------------------------------------------
      9 //
     10 // WebPPicture tools for measuring distortion
     11 //
     12 // Author: Skal (pascal.massimino@gmail.com)
     13 
     14 #include "src/webp/encode.h"
     15 
     16 #if !(defined(WEBP_DISABLE_STATS) || defined(WEBP_REDUCE_SIZE))
     17 
     18 #include <math.h>
     19 #include <stdlib.h>
     20 
     21 #include "src/webp/types.h"
     22 #include "src/dsp/dsp.h"
     23 #include "src/enc/vp8i_enc.h"
     24 #include "src/utils/utils.h"
     25 
     26 typedef double (*AccumulateFunc)(const uint8_t* src, int src_stride,
     27                                 const uint8_t* ref, int ref_stride,
     28                                 int w, int h);
     29 
     30 //------------------------------------------------------------------------------
     31 // local-min distortion
     32 //
     33 // For every pixel in the *reference* picture, we search for the local best
     34 // match in the compressed image. This is not a symmetrical measure.
     35 
     36 #define RADIUS 2  // search radius. Shouldn't be too large.
     37 
     38 static double AccumulateLSIM(const uint8_t* src, int src_stride,
     39                             const uint8_t* ref, int ref_stride,
     40                             int w, int h) {
     41  int x, y;
     42  double total_sse = 0.;
     43  for (y = 0; y < h; ++y) {
     44    const int y_0 = (y - RADIUS < 0) ? 0 : y - RADIUS;
     45    const int y_1 = (y + RADIUS + 1 >= h) ? h : y + RADIUS + 1;
     46    for (x = 0; x < w; ++x) {
     47      const int x_0 = (x - RADIUS < 0) ? 0 : x - RADIUS;
     48      const int x_1 = (x + RADIUS + 1 >= w) ? w : x + RADIUS + 1;
     49      double best_sse = 255. * 255.;
     50      const double value = (double)ref[y * ref_stride + x];
     51      int i, j;
     52      for (j = y_0; j < y_1; ++j) {
     53        const uint8_t* const s = src + j * src_stride;
     54        for (i = x_0; i < x_1; ++i) {
     55          const double diff = s[i] - value;
     56          const double sse = diff * diff;
     57          if (sse < best_sse) best_sse = sse;
     58        }
     59      }
     60      total_sse += best_sse;
     61    }
     62  }
     63  return total_sse;
     64 }
     65 #undef RADIUS
     66 
     67 static double AccumulateSSE(const uint8_t* src, int src_stride,
     68                            const uint8_t* ref, int ref_stride,
     69                            int w, int h) {
     70  int y;
     71  double total_sse = 0.;
     72  for (y = 0; y < h; ++y) {
     73    total_sse += VP8AccumulateSSE(src, ref, w);
     74    src += src_stride;
     75    ref += ref_stride;
     76  }
     77  return total_sse;
     78 }
     79 
     80 //------------------------------------------------------------------------------
     81 
     82 static double AccumulateSSIM(const uint8_t* src, int src_stride,
     83                             const uint8_t* ref, int ref_stride,
     84                             int w, int h) {
     85  const int w0 = (w < VP8_SSIM_KERNEL) ? w : VP8_SSIM_KERNEL;
     86  const int w1 = w - VP8_SSIM_KERNEL - 1;
     87  const int h0 = (h < VP8_SSIM_KERNEL) ? h : VP8_SSIM_KERNEL;
     88  const int h1 = h - VP8_SSIM_KERNEL - 1;
     89  int x, y;
     90  double sum = 0.;
     91  for (y = 0; y < h0; ++y) {
     92    for (x = 0; x < w; ++x) {
     93      sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
     94    }
     95  }
     96  for (; y < h1; ++y) {
     97    for (x = 0; x < w0; ++x) {
     98      sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
     99    }
    100    for (; x < w1; ++x) {
    101      const int off1 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * src_stride;
    102      const int off2 = x - VP8_SSIM_KERNEL + (y - VP8_SSIM_KERNEL) * ref_stride;
    103      sum += VP8SSIMGet(src + off1, src_stride, ref + off2, ref_stride);
    104    }
    105    for (; x < w; ++x) {
    106      sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
    107    }
    108  }
    109  for (; y < h; ++y) {
    110    for (x = 0; x < w; ++x) {
    111      sum += VP8SSIMGetClipped(src, src_stride, ref, ref_stride, x, y, w, h);
    112    }
    113  }
    114  return sum;
    115 }
    116 
    117 //------------------------------------------------------------------------------
    118 // Distortion
    119 
    120 // Max value returned in case of exact similarity.
    121 static const double kMinDistortion_dB = 99.;
    122 
    123 static double GetPSNR(double v, double size) {
    124  return (v > 0. && size > 0.) ? -4.3429448 * log(v / (size * 255 * 255.))
    125                               : kMinDistortion_dB;
    126 }
    127 
    128 static double GetLogSSIM(double v, double size) {
    129  v = (size > 0.) ? v / size : 1.;
    130  return (v < 1.) ? -10.0 * log10(1. - v) : kMinDistortion_dB;
    131 }
    132 
    133 int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
    134                        const uint8_t* ref, size_t ref_stride,
    135                        int width, int height, size_t x_step,
    136                        int type, float* distortion, float* result) {
    137  uint8_t* allocated = NULL;
    138  const AccumulateFunc metric = (type == 0) ? AccumulateSSE :
    139                                (type == 1) ? AccumulateSSIM :
    140                                              AccumulateLSIM;
    141  if (src == NULL || ref == NULL ||
    142      src_stride < x_step * width || ref_stride < x_step * width ||
    143      result == NULL || distortion == NULL) {
    144    return 0;
    145  }
    146 
    147  VP8SSIMDspInit();
    148  if (x_step != 1) {   // extract a packed plane if needed
    149    int x, y;
    150    uint8_t* tmp1;
    151    uint8_t* tmp2;
    152    allocated =
    153        (uint8_t*)WebPSafeMalloc(2ULL * width * height, sizeof(*allocated));
    154    if (allocated == NULL) return 0;
    155    tmp1 = allocated;
    156    tmp2 = tmp1 + (size_t)width * height;
    157    for (y = 0; y < height; ++y) {
    158      for (x = 0; x < width; ++x) {
    159        tmp1[x + y * width] = src[x * x_step + y * src_stride];
    160        tmp2[x + y * width] = ref[x * x_step + y * ref_stride];
    161      }
    162    }
    163    src = tmp1;
    164    ref = tmp2;
    165  }
    166  *distortion = (float)metric(src, width, ref, width, width, height);
    167  WebPSafeFree(allocated);
    168 
    169  *result = (type == 1) ? (float)GetLogSSIM(*distortion, (double)width * height)
    170                        : (float)GetPSNR(*distortion, (double)width * height);
    171  return 1;
    172 }
    173 
    174 #ifdef WORDS_BIGENDIAN
    175 #define BLUE_OFFSET 3   // uint32_t 0x000000ff is 0x00,00,00,ff in memory
    176 #else
    177 #define BLUE_OFFSET 0   // uint32_t 0x000000ff is 0xff,00,00,00 in memory
    178 #endif
    179 
    180 int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref,
    181                          int type, float results[5]) {
    182  int w, h, c;
    183  int ok = 0;
    184  WebPPicture p0, p1;
    185  double total_size = 0., total_distortion = 0.;
    186  if (src == NULL || ref == NULL ||
    187      src->width != ref->width || src->height != ref->height ||
    188      results == NULL) {
    189    return 0;
    190  }
    191 
    192  VP8SSIMDspInit();
    193  if (!WebPPictureInit(&p0) || !WebPPictureInit(&p1)) return 0;
    194  w = src->width;
    195  h = src->height;
    196  if (!WebPPictureView(src, 0, 0, w, h, &p0)) goto Error;
    197  if (!WebPPictureView(ref, 0, 0, w, h, &p1)) goto Error;
    198 
    199  // We always measure distortion in ARGB space.
    200  if (p0.use_argb == 0 && !WebPPictureYUVAToARGB(&p0)) goto Error;
    201  if (p1.use_argb == 0 && !WebPPictureYUVAToARGB(&p1)) goto Error;
    202  for (c = 0; c < 4; ++c) {
    203    float distortion;
    204    const size_t stride0 = 4 * (size_t)p0.argb_stride;
    205    const size_t stride1 = 4 * (size_t)p1.argb_stride;
    206    // results are reported as BGRA
    207    const int offset = c ^ BLUE_OFFSET;
    208    if (!WebPPlaneDistortion((const uint8_t*)p0.argb + offset, stride0,
    209                             (const uint8_t*)p1.argb + offset, stride1,
    210                             w, h, 4, type, &distortion, results + c)) {
    211      goto Error;
    212    }
    213    total_distortion += distortion;
    214    total_size += w * h;
    215  }
    216 
    217  results[4] = (type == 1) ? (float)GetLogSSIM(total_distortion, total_size)
    218                           : (float)GetPSNR(total_distortion, total_size);
    219  ok = 1;
    220 
    221 Error:
    222  WebPPictureFree(&p0);
    223  WebPPictureFree(&p1);
    224  return ok;
    225 }
    226 
    227 #undef BLUE_OFFSET
    228 
    229 #else  // defined(WEBP_DISABLE_STATS)
    230 int WebPPlaneDistortion(const uint8_t* src, size_t src_stride,
    231                        const uint8_t* ref, size_t ref_stride,
    232                        int width, int height, size_t x_step,
    233                        int type, float* distortion, float* result) {
    234  (void)src;
    235  (void)src_stride;
    236  (void)ref;
    237  (void)ref_stride;
    238  (void)width;
    239  (void)height;
    240  (void)x_step;
    241  (void)type;
    242  if (distortion == NULL || result == NULL) return 0;
    243  *distortion = 0.f;
    244  *result = 0.f;
    245  return 1;
    246 }
    247 
    248 int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref,
    249                          int type, float results[5]) {
    250  int i;
    251  (void)src;
    252  (void)ref;
    253  (void)type;
    254  if (results == NULL) return 0;
    255  for (i = 0; i < 5; ++i) results[i] = 0.f;
    256  return 1;
    257 }
    258 
    259 #endif  // !defined(WEBP_DISABLE_STATS)