libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

enc_comparator.cc (4829B)


      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 #include "lib/jxl/enc_comparator.h"
      7 
      8 #include <stddef.h>
      9 #include <stdint.h>
     10 
     11 #include <algorithm>
     12 
     13 #include "lib/jxl/base/compiler_specific.h"
     14 #include "lib/jxl/enc_gamma_correct.h"
     15 #include "lib/jxl/enc_image_bundle.h"
     16 
     17 namespace jxl {
     18 namespace {
     19 
     20 // color is linear, but blending happens in gamma-compressed space using
     21 // (gamma-compressed) grayscale background color, alpha image represents
     22 // weights of the sRGB colors in the [0 .. (1 << bit_depth) - 1] interval,
     23 // output image is in linear space.
     24 void AlphaBlend(const Image3F& in, const size_t c, float background_linear,
     25                 const ImageF& alpha, Image3F* out) {
     26   const float background = LinearToSrgb8Direct(background_linear);
     27 
     28   for (size_t y = 0; y < out->ysize(); ++y) {
     29     const float* JXL_RESTRICT row_a = alpha.ConstRow(y);
     30     const float* JXL_RESTRICT row_i = in.ConstPlaneRow(c, y);
     31     float* JXL_RESTRICT row_o = out->PlaneRow(c, y);
     32     for (size_t x = 0; x < out->xsize(); ++x) {
     33       const float a = row_a[x];
     34       if (a <= 0.f) {
     35         row_o[x] = background_linear;
     36       } else if (a >= 1.f) {
     37         row_o[x] = row_i[x];
     38       } else {
     39         const float w_fg = a;
     40         const float w_bg = 1.0f - w_fg;
     41         const float fg = w_fg * LinearToSrgb8Direct(row_i[x]);
     42         const float bg = w_bg * background;
     43         row_o[x] = Srgb8ToLinearDirect(fg + bg);
     44       }
     45     }
     46   }
     47 }
     48 
     49 void AlphaBlend(float background_linear, ImageBundle* io_linear_srgb) {
     50   // No alpha => all opaque.
     51   if (!io_linear_srgb->HasAlpha()) return;
     52 
     53   for (size_t c = 0; c < 3; ++c) {
     54     AlphaBlend(*io_linear_srgb->color(), c, background_linear,
     55                *io_linear_srgb->alpha(), io_linear_srgb->color());
     56   }
     57 }
     58 
     59 float ComputeScoreImpl(const ImageBundle& rgb0, const ImageBundle& rgb1,
     60                        Comparator* comparator, ImageF* distmap) {
     61   JXL_CHECK(comparator->SetReferenceImage(rgb0));
     62   float score;
     63   JXL_CHECK(comparator->CompareWith(rgb1, distmap, &score));
     64   return score;
     65 }
     66 
     67 }  // namespace
     68 
     69 Status ComputeScore(const ImageBundle& rgb0, const ImageBundle& rgb1,
     70                     Comparator* comparator, const JxlCmsInterface& cms,
     71                     float* score, ImageF* diffmap, ThreadPool* pool,
     72                     bool ignore_alpha) {
     73   // Convert to linear sRGB (unless already in that space)
     74   ImageMetadata metadata0 = *rgb0.metadata();
     75   ImageBundle store0(&metadata0);
     76   const ImageBundle* linear_srgb0;
     77   JXL_CHECK(TransformIfNeeded(rgb0, ColorEncoding::LinearSRGB(rgb0.IsGray()),
     78                               cms, pool, &store0, &linear_srgb0));
     79   ImageMetadata metadata1 = *rgb1.metadata();
     80   ImageBundle store1(&metadata1);
     81   const ImageBundle* linear_srgb1;
     82   JXL_CHECK(TransformIfNeeded(rgb1, ColorEncoding::LinearSRGB(rgb1.IsGray()),
     83                               cms, pool, &store1, &linear_srgb1));
     84 
     85   // No alpha: skip blending, only need a single call to Butteraugli.
     86   if (ignore_alpha || (!rgb0.HasAlpha() && !rgb1.HasAlpha())) {
     87     *score =
     88         ComputeScoreImpl(*linear_srgb0, *linear_srgb1, comparator, diffmap);
     89     return true;
     90   }
     91 
     92   // Blend on black and white backgrounds
     93 
     94   const float black = 0.0f;
     95   JXL_ASSIGN_OR_RETURN(ImageBundle blended_black0, linear_srgb0->Copy());
     96   JXL_ASSIGN_OR_RETURN(ImageBundle blended_black1, linear_srgb1->Copy());
     97   AlphaBlend(black, &blended_black0);
     98   AlphaBlend(black, &blended_black1);
     99 
    100   const float white = 1.0f;
    101   JXL_ASSIGN_OR_RETURN(ImageBundle blended_white0, linear_srgb0->Copy());
    102   JXL_ASSIGN_OR_RETURN(ImageBundle blended_white1, linear_srgb1->Copy());
    103 
    104   AlphaBlend(white, &blended_white0);
    105   AlphaBlend(white, &blended_white1);
    106 
    107   ImageF diffmap_black;
    108   ImageF diffmap_white;
    109   const float dist_black = ComputeScoreImpl(blended_black0, blended_black1,
    110                                             comparator, &diffmap_black);
    111   const float dist_white = ComputeScoreImpl(blended_white0, blended_white1,
    112                                             comparator, &diffmap_white);
    113 
    114   // diffmap and return values are the max of diffmap_black/white.
    115   if (diffmap != nullptr) {
    116     const size_t xsize = rgb0.xsize();
    117     const size_t ysize = rgb0.ysize();
    118     JXL_ASSIGN_OR_RETURN(*diffmap, ImageF::Create(xsize, ysize));
    119     for (size_t y = 0; y < ysize; ++y) {
    120       const float* JXL_RESTRICT row_black = diffmap_black.ConstRow(y);
    121       const float* JXL_RESTRICT row_white = diffmap_white.ConstRow(y);
    122       float* JXL_RESTRICT row_out = diffmap->Row(y);
    123       for (size_t x = 0; x < xsize; ++x) {
    124         row_out[x] = std::max(row_black[x], row_white[x]);
    125       }
    126     }
    127   }
    128   *score = std::max(dist_black, dist_white);
    129   return true;
    130 }
    131 
    132 }  // namespace jxl