tor-browser

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

butteraugli.h (8267B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 //
      6 // Author: Jyrki Alakuijala (jyrki.alakuijala@gmail.com)
      7 
      8 #ifndef LIB_JXL_BUTTERAUGLI_BUTTERAUGLI_H_
      9 #define LIB_JXL_BUTTERAUGLI_BUTTERAUGLI_H_
     10 
     11 #include <jxl/memory_manager.h>
     12 
     13 #include <atomic>
     14 #include <cstddef>
     15 #include <cstdlib>
     16 #include <cstring>
     17 #include <memory>
     18 
     19 #include "lib/jxl/base/compiler_specific.h"
     20 #include "lib/jxl/base/status.h"
     21 #include "lib/jxl/image.h"
     22 
     23 #if !defined(BUTTERAUGLI_ENABLE_CHECKS)
     24 #define BUTTERAUGLI_ENABLE_CHECKS 0
     25 #endif
     26 
     27 #define BUTTERAUGLI_RESTRICT JXL_RESTRICT
     28 
     29 // This is the main interface to butteraugli image similarity
     30 // analysis function.
     31 
     32 namespace jxl {
     33 
     34 struct ButteraugliParams {
     35  // Multiplier for penalizing new HF artifacts more than blurring away
     36  // features. 1.0=neutral.
     37  float hf_asymmetry = 1.0f;
     38 
     39  // Multiplier for the psychovisual difference in the X channel.
     40  float xmul = 1.0f;
     41 
     42  // Number of nits that correspond to 1.0f input values.
     43  float intensity_target = 80.0f;
     44 };
     45 
     46 // ButteraugliInterface defines the public interface for butteraugli.
     47 //
     48 // It calculates the difference between rgb0 and rgb1.
     49 //
     50 // rgb0 and rgb1 contain the images. rgb0[c][px] and rgb1[c][px] contains
     51 // the red image for c == 0, green for c == 1, blue for c == 2. Location index
     52 // px is calculated as y * xsize + x.
     53 //
     54 // Value of pixels of images rgb0 and rgb1 need to be represented as raw
     55 // intensity. Most image formats store gamma corrected intensity in pixel
     56 // values. This gamma correction has to be removed, by applying the following
     57 // function to values in the 0-1 range:
     58 // butteraugli_val = pow(input_val, gamma);
     59 // A typical value of gamma is 2.2. It is usually stored in the image header.
     60 // Take care not to confuse that value with its inverse. The gamma value should
     61 // be always greater than one.
     62 // Butteraugli does not work as intended if the caller does not perform
     63 // gamma correction.
     64 //
     65 // hf_asymmetry is a multiplier for penalizing new HF artifacts more than
     66 // blurring away features (1.0 -> neutral).
     67 //
     68 // diffmap will contain an image of the size xsize * ysize, containing
     69 // localized differences for values px (indexed with the px the same as rgb0
     70 // and rgb1). diffvalue will give a global score of similarity.
     71 //
     72 // A diffvalue smaller than kButteraugliGood indicates that images can be
     73 // observed as the same image.
     74 // diffvalue larger than kButteraugliBad indicates that a difference between
     75 // the images can be observed.
     76 // A diffvalue between kButteraugliGood and kButteraugliBad indicates that
     77 // a subtle difference can be observed between the images.
     78 //
     79 // Returns true on success.
     80 bool ButteraugliInterface(const Image3F &rgb0, const Image3F &rgb1,
     81                          const ButteraugliParams &params, ImageF &diffmap,
     82                          double &diffvalue);
     83 
     84 // Deprecated (calls the previous function)
     85 bool ButteraugliInterface(const Image3F &rgb0, const Image3F &rgb1,
     86                          float hf_asymmetry, float xmul, ImageF &diffmap,
     87                          double &diffvalue);
     88 
     89 // Same as ButteraugliInterface, but reuses rgb0 and rgb1 for other purposes
     90 // inside the function after they are not needed any more, and it ignores
     91 // params.xmul.
     92 Status ButteraugliInterfaceInPlace(Image3F &&rgb0, Image3F &&rgb1,
     93                                   const ButteraugliParams &params,
     94                                   ImageF &diffmap, double &diffvalue);
     95 
     96 // Converts the butteraugli score into fuzzy class values that are continuous
     97 // at the class boundary. The class boundary location is based on human
     98 // raters, but the slope is arbitrary. Particularly, it does not reflect
     99 // the expectation value of probabilities of the human raters. It is just
    100 // expected that a smoother class boundary will allow for higher-level
    101 // optimization algorithms to work faster.
    102 //
    103 // Returns 2.0 for a perfect match, and 1.0 for 'ok', 0.0 for bad. Because the
    104 // scoring is fuzzy, a butteraugli score of 0.96 would return a class of
    105 // around 1.9.
    106 double ButteraugliFuzzyClass(double score);
    107 
    108 // Input values should be in range 0 (bad) to 2 (good). Use
    109 // kButteraugliNormalization as normalization.
    110 double ButteraugliFuzzyInverse(double seek);
    111 
    112 // Implementation details, don't use anything below or your code will
    113 // break in the future.
    114 
    115 #ifdef _MSC_VER
    116 #define BUTTERAUGLI_INLINE __forceinline
    117 #else
    118 #define BUTTERAUGLI_INLINE inline
    119 #endif
    120 
    121 #ifdef __clang__
    122 // Early versions of Clang did not support __builtin_assume_aligned.
    123 #define BUTTERAUGLI_HAS_ASSUME_ALIGNED __has_builtin(__builtin_assume_aligned)
    124 #elif defined(__GNUC__)
    125 #define BUTTERAUGLI_HAS_ASSUME_ALIGNED 1
    126 #else
    127 #define BUTTERAUGLI_HAS_ASSUME_ALIGNED 0
    128 #endif
    129 
    130 // Returns a void* pointer which the compiler then assumes is N-byte aligned.
    131 // Example: float* JXL_RESTRICT aligned = (float*)JXL_ASSUME_ALIGNED(in, 32);
    132 //
    133 // The assignment semantics are required by GCC/Clang. ICC provides an in-place
    134 // __assume_aligned, whereas MSVC's __assume appears unsuitable.
    135 #if BUTTERAUGLI_HAS_ASSUME_ALIGNED
    136 #define BUTTERAUGLI_ASSUME_ALIGNED(ptr, align) \
    137  __builtin_assume_aligned((ptr), (align))
    138 #else
    139 #define BUTTERAUGLI_ASSUME_ALIGNED(ptr, align) (ptr)
    140 #endif  // BUTTERAUGLI_HAS_ASSUME_ALIGNED
    141 
    142 struct PsychoImage {
    143  ImageF uhf[2];  // XY
    144  ImageF hf[2];   // XY
    145  Image3F mf;     // XYB
    146  Image3F lf;     // XYB
    147 };
    148 
    149 // Blur needs a transposed image.
    150 // Hold it here and only allocate on demand to reduce memory usage.
    151 struct BlurTemp {
    152  Status GetTransposed(const ImageF &in, ImageF **out) {
    153    JxlMemoryManager *memory_manager = in.memory_manager();
    154    if (transposed_temp.xsize() == 0) {
    155      JXL_ASSIGN_OR_RETURN(
    156          transposed_temp,
    157          ImageF::Create(memory_manager, in.ysize(), in.xsize()));
    158    }
    159    *out = &transposed_temp;
    160    return true;
    161  }
    162 
    163  ImageF transposed_temp;
    164 };
    165 
    166 class ButteraugliComparator {
    167 public:
    168  // Butteraugli is calibrated at xmul = 1.0. We add a multiplier here so that
    169  // we can test the hypothesis that a higher weighing of the X channel would
    170  // improve results at higher Butteraugli values.
    171  virtual ~ButteraugliComparator() = default;
    172 
    173  static StatusOr<std::unique_ptr<ButteraugliComparator>> Make(
    174      const Image3F &rgb0, const ButteraugliParams &params);
    175 
    176  // Computes the butteraugli map between the original image given in the
    177  // constructor and the distorted image give here.
    178  Status Diffmap(const Image3F &rgb1, ImageF &result) const;
    179 
    180  // Same as above, but OpsinDynamicsImage() was already applied.
    181  Status DiffmapOpsinDynamicsImage(const Image3F &xyb1, ImageF &result) const;
    182 
    183  // Same as above, but the frequency decomposition was already applied.
    184  Status DiffmapPsychoImage(const PsychoImage &pi1, ImageF &diffmap) const;
    185 
    186  Status Mask(ImageF *BUTTERAUGLI_RESTRICT mask) const;
    187 
    188 private:
    189  ButteraugliComparator(size_t xsize, size_t ysize,
    190                        const ButteraugliParams &params);
    191  Image3F *Temp() const;
    192  void ReleaseTemp() const;
    193 
    194  const size_t xsize_;
    195  const size_t ysize_;
    196  ButteraugliParams params_;
    197  PsychoImage pi0_;
    198 
    199  // Shared temporary image storage to reduce the number of allocations;
    200  // obtained via Temp(), must call ReleaseTemp when no longer needed.
    201  mutable Image3F temp_;
    202  mutable std::atomic_flag temp_in_use_ = ATOMIC_FLAG_INIT;
    203 
    204  mutable BlurTemp blur_temp_;
    205  std::unique_ptr<ButteraugliComparator> sub_;
    206 };
    207 
    208 // Deprecated.
    209 Status ButteraugliDiffmap(const Image3F &rgb0, const Image3F &rgb1,
    210                          double hf_asymmetry, double xmul, ImageF &diffmap);
    211 
    212 Status ButteraugliDiffmap(const Image3F &rgb0, const Image3F &rgb1,
    213                          const ButteraugliParams &params, ImageF &diffmap);
    214 
    215 double ButteraugliScoreFromDiffmap(const ImageF &diffmap,
    216                                   const ButteraugliParams *params = nullptr);
    217 
    218 // Generate rgb-representation of the distance between two images.
    219 StatusOr<Image3F> CreateHeatMapImage(const ImageF &distmap,
    220                                     double good_threshold,
    221                                     double bad_threshold);
    222 
    223 }  // namespace jxl
    224 
    225 #endif  // LIB_JXL_BUTTERAUGLI_BUTTERAUGLI_H_