libjxl

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

butteraugli_main.cc (6058B)


      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 <jxl/cms.h>
      7 #include <jxl/types.h>
      8 #include <stdint.h>
      9 #include <stdio.h>
     10 
     11 #include <cstdlib>
     12 #include <string>
     13 #include <vector>
     14 
     15 #include "jxl/cms_interface.h"
     16 #include "lib/extras/codec.h"
     17 #include "lib/extras/dec/color_hints.h"
     18 #include "lib/extras/metrics.h"
     19 #include "lib/extras/packed_image.h"
     20 #include "lib/extras/packed_image_convert.h"
     21 #include "lib/jxl/base/printf_macros.h"
     22 #include "lib/jxl/base/span.h"
     23 #include "lib/jxl/base/status.h"
     24 #include "lib/jxl/butteraugli/butteraugli.h"
     25 #include "lib/jxl/codec_in_out.h"
     26 #include "lib/jxl/color_encoding_internal.h"
     27 #include "lib/jxl/enc_butteraugli_comparator.h"
     28 #include "lib/jxl/image.h"
     29 #include "tools/file_io.h"
     30 #include "tools/thread_pool_internal.h"
     31 
     32 namespace {
     33 
     34 using jpegxl::tools::ThreadPoolInternal;
     35 using jxl::ButteraugliParams;
     36 using jxl::CodecInOut;
     37 using jxl::Image3F;
     38 using jxl::ImageF;
     39 using jxl::JxlButteraugliComparator;
     40 using jxl::Status;
     41 
     42 Status WriteImage(const Image3F& image, const std::string& filename) {
     43   ThreadPoolInternal pool(4);
     44   JxlPixelFormat format = {3, JXL_TYPE_UINT8, JXL_LITTLE_ENDIAN, 0};
     45   jxl::extras::PackedPixelFile ppf =
     46       jxl::extras::ConvertImage3FToPackedPixelFile(
     47           image, jxl::ColorEncoding::SRGB(), format, &pool);
     48   std::vector<uint8_t> encoded;
     49   return jxl::Encode(ppf, filename, &encoded, &pool) &&
     50          jpegxl::tools::WriteFile(filename, encoded);
     51 }
     52 
     53 Status RunButteraugli(const char* pathname1, const char* pathname2,
     54                       const std::string& distmap_filename,
     55                       const std::string& raw_distmap_filename,
     56                       const std::string& colorspace_hint, double p,
     57                       float intensity_target) {
     58   jxl::extras::ColorHints color_hints;
     59   if (!colorspace_hint.empty()) {
     60     color_hints.Add("color_space", colorspace_hint);
     61   }
     62 
     63   const char* pathname[2] = {pathname1, pathname2};
     64   CodecInOut io[2];
     65   ThreadPoolInternal pool(4);
     66   for (size_t i = 0; i < 2; ++i) {
     67     std::vector<uint8_t> encoded;
     68     if (!jpegxl::tools::ReadFile(pathname[i], &encoded)) {
     69       fprintf(stderr, "Failed to read image from %s\n", pathname[i]);
     70       return false;
     71     }
     72     if (!jxl::SetFromBytes(jxl::Bytes(encoded), color_hints, &io[i], &pool)) {
     73       fprintf(stderr, "Failed to decode image from %s\n", pathname[i]);
     74       return false;
     75     }
     76   }
     77 
     78   CodecInOut& io1 = io[0];
     79   CodecInOut& io2 = io[1];
     80   if (io1.xsize() != io2.xsize()) {
     81     fprintf(stderr, "Width mismatch: %" PRIuS " %" PRIuS "\n", io1.xsize(),
     82             io2.xsize());
     83     return false;
     84   }
     85   if (io1.ysize() != io2.ysize()) {
     86     fprintf(stderr, "Height mismatch: %" PRIuS " %" PRIuS "\n", io1.ysize(),
     87             io2.ysize());
     88     return false;
     89   }
     90 
     91   ImageF distmap;
     92   ButteraugliParams ba_params;
     93   ba_params.hf_asymmetry = 1.0f;
     94   ba_params.xmul = 1.0f;
     95   ba_params.intensity_target = intensity_target;
     96   const JxlCmsInterface& cms = *JxlGetDefaultCms();
     97   JxlButteraugliComparator comparator(ba_params, cms);
     98   float distance;
     99   JXL_CHECK(ComputeScore(io1.Main(), io2.Main(), &comparator, cms, &distance,
    100                          &distmap, &pool,
    101                          /* ignore_alpha */ false));
    102   printf("%.10f\n", distance);
    103 
    104   double pnorm = jxl::ComputeDistanceP(distmap, ba_params, p);
    105   printf("%g-norm: %f\n", p, pnorm);
    106 
    107   if (!distmap_filename.empty()) {
    108     float good = jxl::ButteraugliFuzzyInverse(1.5);
    109     float bad = jxl::ButteraugliFuzzyInverse(0.5);
    110     JXL_ASSIGN_OR_DIE(Image3F heatmap,
    111                       jxl::CreateHeatMapImage(distmap, good, bad));
    112     JXL_CHECK(WriteImage(heatmap, distmap_filename));
    113   }
    114   if (!raw_distmap_filename.empty()) {
    115     FILE* out = fopen(raw_distmap_filename.c_str(), "wb");
    116     JXL_CHECK(out != nullptr);
    117     fprintf(out, "Pf\n%" PRIuS " %" PRIuS "\n-1.0\n", distmap.xsize(),
    118             distmap.ysize());
    119     for (size_t y = distmap.ysize(); y-- > 0;) {
    120       fwrite(distmap.Row(y), 4, distmap.xsize(), out);
    121     }
    122     fclose(out);
    123   }
    124   return true;
    125 }
    126 
    127 }  // namespace
    128 
    129 int main(int argc, char** argv) {
    130   if (argc < 3) {
    131     fprintf(stderr,
    132             "Usage: %s <reference> <distorted>\n"
    133             "  [--distmap <distmap>]\n"
    134             "  [--rawdistmap <distmap.pfm>]\n"
    135             "  [--intensity_target <intensity_target>]\n"
    136             "  [--colorspace <colorspace_hint>]\n"
    137             "  [--pnorm <pth norm>]\n"
    138             "NOTE: images get converted to linear sRGB for butteraugli. Images"
    139             " without attached profiles (such as ppm or pfm) are interpreted"
    140             " as nonlinear sRGB. The hint format is RGB_D65_SRG_Rel_Lin for"
    141             " linear sRGB. Intensity target is viewing conditions screen nits"
    142             ", defaults to 80.\n",
    143             argv[0]);
    144     return 1;
    145   }
    146   std::string distmap;
    147   std::string raw_distmap;
    148   std::string colorspace;
    149   double p = 3;
    150   float intensity_target = 80.0;  // sRGB intensity target.
    151   for (int i = 3; i < argc; i++) {
    152     if (std::string(argv[i]) == "--distmap" && i + 1 < argc) {
    153       distmap = argv[++i];
    154     } else if (std::string(argv[i]) == "--rawdistmap" && i + 1 < argc) {
    155       raw_distmap = argv[++i];
    156     } else if (std::string(argv[i]) == "--colorspace" && i + 1 < argc) {
    157       colorspace = argv[++i];
    158     } else if (std::string(argv[i]) == "--intensity_target" && i + 1 < argc) {
    159       intensity_target = std::stof(std::string(argv[++i]));
    160     } else if (std::string(argv[i]) == "--pnorm" && i + 1 < argc) {
    161       char* end;
    162       p = strtod(argv[++i], &end);
    163       if (end == argv[i]) {
    164         fprintf(stderr, "Failed to parse pnorm \"%s\".\n", argv[i]);
    165         return 1;
    166       }
    167     } else {
    168       fprintf(stderr, "Unrecognized flag \"%s\".\n", argv[i]);
    169       return 1;
    170     }
    171   }
    172 
    173   Status result = RunButteraugli(argv[1], argv[2], distmap, raw_distmap,
    174                                  colorspace, p, intensity_target);
    175   return result ? 1 : 0;
    176 }