libjxl

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

quantizer.cc (5630B)


      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/quantizer.h"
      7 
      8 #include <string.h>
      9 
     10 #include <algorithm>
     11 
     12 #include "lib/jxl/base/compiler_specific.h"
     13 #include "lib/jxl/field_encodings.h"
     14 #include "lib/jxl/fields.h"
     15 #include "lib/jxl/image.h"
     16 #include "lib/jxl/image_ops.h"
     17 #include "lib/jxl/quant_weights.h"
     18 
     19 namespace jxl {
     20 
     21 static const int32_t kDefaultQuant = 64;
     22 
     23 constexpr int32_t Quantizer::kQuantMax;
     24 
     25 Quantizer::Quantizer(const DequantMatrices* dequant)
     26     : Quantizer(dequant, kDefaultQuant, kGlobalScaleDenom / kDefaultQuant) {}
     27 
     28 Quantizer::Quantizer(const DequantMatrices* dequant, int quant_dc,
     29                      int global_scale)
     30     : global_scale_(global_scale), quant_dc_(quant_dc), dequant_(dequant) {
     31   JXL_ASSERT(dequant_ != nullptr);
     32   RecomputeFromGlobalScale();
     33   inv_quant_dc_ = inv_global_scale_ / quant_dc_;
     34 
     35   memcpy(zero_bias_, kZeroBiasDefault, sizeof(kZeroBiasDefault));
     36 }
     37 
     38 void Quantizer::ComputeGlobalScaleAndQuant(float quant_dc, float quant_median,
     39                                            float quant_median_absd) {
     40   // Target value for the median value in the quant field.
     41   const float kQuantFieldTarget = 5;
     42   // We reduce the median of the quant field by the median absolute deviation:
     43   // higher resolution on highly varying quant fields.
     44   float scale = kGlobalScaleDenom * (quant_median - quant_median_absd) /
     45                 kQuantFieldTarget;
     46   // Ensure that new_global_scale is positive and no more than 1<<15.
     47   if (scale < 1) scale = 1;
     48   if (scale > (1 << 15)) scale = 1 << 15;
     49   int new_global_scale = static_cast<int>(scale);
     50   // Ensure that quant_dc_ will always be at least
     51   // 0.625 * kGlobalScaleDenom/kGlobalScaleNumerator = 10.
     52   const int scaled_quant_dc =
     53       static_cast<int>(quant_dc * kGlobalScaleNumerator * 1.6);
     54   if (new_global_scale > scaled_quant_dc) {
     55     new_global_scale = scaled_quant_dc;
     56     if (new_global_scale <= 0) new_global_scale = 1;
     57   }
     58   global_scale_ = new_global_scale;
     59   // Code below uses inv_global_scale_.
     60   RecomputeFromGlobalScale();
     61 
     62   float fval = quant_dc * inv_global_scale_ + 0.5f;
     63   fval = std::min<float>(1 << 16, fval);
     64   const int new_quant_dc = static_cast<int>(fval);
     65   quant_dc_ = new_quant_dc;
     66 
     67   // quant_dc_ was updated, recompute values.
     68   RecomputeFromGlobalScale();
     69 }
     70 
     71 void Quantizer::SetQuantFieldRect(const ImageF& qf, const Rect& rect,
     72                                   ImageI* JXL_RESTRICT raw_quant_field) const {
     73   for (size_t y = 0; y < rect.ysize(); ++y) {
     74     const float* JXL_RESTRICT row_qf = rect.ConstRow(qf, y);
     75     int32_t* JXL_RESTRICT row_qi = rect.Row(raw_quant_field, y);
     76     for (size_t x = 0; x < rect.xsize(); ++x) {
     77       int val = ClampVal(row_qf[x] * inv_global_scale_ + 0.5f);
     78       row_qi[x] = val;
     79     }
     80   }
     81 }
     82 
     83 void Quantizer::SetQuantField(const float quant_dc, const ImageF& qf,
     84                               ImageI* JXL_RESTRICT raw_quant_field) {
     85   std::vector<float> data(qf.xsize() * qf.ysize());
     86   for (size_t y = 0; y < qf.ysize(); ++y) {
     87     const float* JXL_RESTRICT row_qf = qf.Row(y);
     88     for (size_t x = 0; x < qf.xsize(); ++x) {
     89       float quant = row_qf[x];
     90       data[qf.xsize() * y + x] = quant;
     91     }
     92   }
     93   std::nth_element(data.begin(), data.begin() + data.size() / 2, data.end());
     94   const float quant_median = data[data.size() / 2];
     95   std::vector<float> deviations(data.size());
     96   for (size_t i = 0; i < data.size(); i++) {
     97     deviations[i] = fabsf(data[i] - quant_median);
     98   }
     99   std::nth_element(deviations.begin(),
    100                    deviations.begin() + deviations.size() / 2,
    101                    deviations.end());
    102   const float quant_median_absd = deviations[deviations.size() / 2];
    103   ComputeGlobalScaleAndQuant(quant_dc, quant_median, quant_median_absd);
    104   if (raw_quant_field) {
    105     JXL_CHECK(SameSize(*raw_quant_field, qf));
    106     SetQuantFieldRect(qf, Rect(qf), raw_quant_field);
    107   }
    108 }
    109 
    110 void Quantizer::SetQuant(float quant_dc, float quant_ac,
    111                          ImageI* JXL_RESTRICT raw_quant_field) {
    112   ComputeGlobalScaleAndQuant(quant_dc, quant_ac, 0);
    113   int32_t val = ClampVal(quant_ac * inv_global_scale_ + 0.5f);
    114   FillImage(val, raw_quant_field);
    115 }
    116 
    117 Status QuantizerParams::VisitFields(Visitor* JXL_RESTRICT visitor) {
    118   JXL_QUIET_RETURN_IF_ERROR(visitor->U32(
    119       BitsOffset(11, 1), BitsOffset(11, 2049), BitsOffset(12, 4097),
    120       BitsOffset(16, 8193), 1, &global_scale));
    121   JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), BitsOffset(5, 1),
    122                                          BitsOffset(8, 1), BitsOffset(16, 1), 1,
    123                                          &quant_dc));
    124   return true;
    125 }
    126 
    127 QuantizerParams Quantizer::GetParams() const {
    128   QuantizerParams params;
    129   params.global_scale = global_scale_;
    130   params.quant_dc = quant_dc_;
    131   return params;
    132 }
    133 
    134 Status Quantizer::Decode(BitReader* reader) {
    135   QuantizerParams params;
    136   JXL_RETURN_IF_ERROR(Bundle::Read(reader, &params));
    137   global_scale_ = static_cast<int>(params.global_scale);
    138   quant_dc_ = static_cast<int>(params.quant_dc);
    139   RecomputeFromGlobalScale();
    140   return true;
    141 }
    142 
    143 void Quantizer::DumpQuantizationMap(const ImageI& raw_quant_field) const {
    144   printf("Global scale: %d (%.7f)\nDC quant: %d\n", global_scale_,
    145          global_scale_ * 1.0 / kGlobalScaleDenom, quant_dc_);
    146   printf("AC quantization Map:\n");
    147   for (size_t y = 0; y < raw_quant_field.ysize(); ++y) {
    148     for (size_t x = 0; x < raw_quant_field.xsize(); ++x) {
    149       printf(" %3d", raw_quant_field.Row(y)[x]);
    150     }
    151     printf("\n");
    152   }
    153 }
    154 
    155 }  // namespace jxl