Coverage Report

Created: 2025-06-16 07:00

/src/libjxl/lib/jxl/quantizer.h
Line
Count
Source (jump to first uncovered line)
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
#ifndef LIB_JXL_QUANTIZER_H_
7
#define LIB_JXL_QUANTIZER_H_
8
9
#include <algorithm>
10
#include <cmath>
11
#include <cstddef>
12
#include <cstdint>
13
#include <cstdlib>
14
15
#include "lib/jxl/base/compiler_specific.h"
16
#include "lib/jxl/base/rect.h"
17
#include "lib/jxl/base/status.h"
18
#include "lib/jxl/dec_bit_reader.h"
19
#include "lib/jxl/field_encodings.h"
20
#include "lib/jxl/fields.h"
21
#include "lib/jxl/image.h"
22
#include "lib/jxl/quant_weights.h"
23
24
// Quantizes DC and AC coefficients, with separate quantization tables according
25
// to the quant_kind (which is currently computed from the AC strategy and the
26
// block index inside that strategy).
27
28
namespace jxl {
29
30
enum class AcStrategyType : uint32_t;
31
32
static constexpr int kGlobalScaleDenom = 1 << 16;
33
static constexpr int kGlobalScaleNumerator = 4096;
34
35
// zero-biases for quantizing channels X, Y, B
36
static constexpr float kZeroBiasDefault[3] = {0.5f, 0.5f, 0.5f};
37
38
// Returns adjusted version of a quantized integer, such that its value is
39
// closer to the expected value of the original.
40
// The residuals of AC coefficients that we quantize are not uniformly
41
// distributed. Numerical experiments show that they have a distribution with
42
// the "shape" of 1/(1+x^2) [up to some coefficients]. This means that the
43
// expected value of a coefficient that gets quantized to x will not be x
44
// itself, but (at least with reasonable approximation):
45
// - 0 if x is 0
46
// - x * biases[c] if x is 1 or -1
47
// - x - biases[3]/x otherwise
48
// This follows from computing the distribution of the quantization bias, which
49
// can be approximated fairly well by <constant>/x when |x| is at least two.
50
static constexpr float kBiasNumerator = 0.145f;
51
52
static constexpr float kDefaultQuantBias[4] = {
53
    1.0f - 0.05465007330715401f,
54
    1.0f - 0.07005449891748593f,
55
    1.0f - 0.049935103337343655f,
56
    0.145f,
57
};
58
59
struct QuantizerParams;
60
61
class Quantizer {
62
 public:
63
  explicit Quantizer(const DequantMatrices& dequant);
64
  Quantizer(const DequantMatrices& dequant, int quant_dc, int global_scale);
65
66
  static constexpr int32_t kQuantMax = 256;
67
68
398k
  static JXL_INLINE int32_t ClampVal(float val) {
69
398k
    return static_cast<int32_t>(
70
398k
        std::max(1.0f, std::min<float>(val, kQuantMax)));
71
398k
  }
72
73
186
  float ScaleGlobalScale(const float scale) {
74
186
    int new_global_scale = static_cast<int>(std::lround(global_scale_ * scale));
75
186
    float scale_out = new_global_scale * 1.0f / global_scale_;
76
186
    global_scale_ = new_global_scale;
77
186
    RecomputeFromGlobalScale();
78
186
    return scale_out;
79
186
  }
80
81
  // Recomputes other derived fields after global_scale_ has changed.
82
15.8k
  void RecomputeFromGlobalScale() {
83
15.8k
    global_scale_float_ = global_scale_ * (1.0 / kGlobalScaleDenom);
84
15.8k
    inv_global_scale_ = 1.0 * kGlobalScaleDenom / global_scale_;
85
15.8k
    inv_quant_dc_ = inv_global_scale_ / quant_dc_;
86
63.4k
    for (size_t c = 0; c < 3; c++) {
87
47.6k
      mul_dc_[c] = GetDcStep(c);
88
47.6k
      inv_mul_dc_[c] = GetInvDcStep(c);
89
47.6k
    }
90
15.8k
  }
91
92
  // Returns scaling factor such that Scale() * (RawDC() or RawQuantField())
93
  // pixels yields the same float values returned by GetQuantField.
94
1.25M
  JXL_INLINE float Scale() const { return global_scale_float_; }
95
96
  // Reciprocal of Scale().
97
3.48k
  JXL_INLINE float InvGlobalScale() const { return inv_global_scale_; }
98
99
  void SetQuantFieldRect(const ImageF& qf, const Rect& rect,
100
                         ImageI* JXL_RESTRICT raw_quant_field) const;
101
102
  Status SetQuantField(float quant_dc, const ImageF& qf,
103
                       ImageI* JXL_RESTRICT raw_quant_field);
104
105
  void SetQuant(float quant_dc, float quant_ac,
106
                ImageI* JXL_RESTRICT raw_quant_field);
107
108
  // Returns the DC quantization base value, which is currently global (not
109
  // adaptive). The actual scale factor used to dequantize pixels in channel c
110
  // is: inv_quant_dc() * dequant_->DCQuant(c).
111
0
  float inv_quant_dc() const { return inv_quant_dc_; }
112
113
  // Dequantize by multiplying with this times dequant_matrix.
114
241k
  float inv_quant_ac(int32_t quant) const { return inv_global_scale_ / quant; }
115
116
  QuantizerParams GetParams() const;
117
118
  Status Decode(BitReader* reader);
119
120
  void DumpQuantizationMap(const ImageI& raw_quant_field) const;
121
122
  JXL_INLINE const float* DequantMatrix(AcStrategyType quant_kind,
123
1.05M
                                        size_t c) const {
124
1.05M
    return dequant_->Matrix(quant_kind, c);
125
1.05M
  }
126
127
  JXL_INLINE const float* InvDequantMatrix(AcStrategyType quant_kind,
128
1.01M
                                           size_t c) const {
129
1.01M
    return dequant_->InvMatrix(quant_kind, c);
130
1.01M
  }
131
132
  // Calculates DC quantization step.
133
48.1k
  JXL_INLINE float GetDcStep(size_t c) const {
134
48.1k
    return inv_quant_dc_ * dequant_->DCQuant(c);
135
48.1k
  }
136
531k
  JXL_INLINE float GetInvDcStep(size_t c) const {
137
531k
    return dequant_->InvDCQuant(c) * (global_scale_float_ * quant_dc_);
138
531k
  }
139
140
5.51k
  JXL_INLINE const float* MulDC() const { return mul_dc_; }
141
0
  JXL_INLINE const float* InvMulDC() const { return inv_mul_dc_; }
142
143
0
  JXL_INLINE void ClearDCMul() {
144
0
    std::fill(mul_dc_, mul_dc_ + 4, 1.f);
145
0
    std::fill(inv_mul_dc_, inv_mul_dc_ + 4, 1.f);
146
0
  }
147
148
  void ComputeGlobalScaleAndQuant(float quant_dc, float quant_median,
149
                                  float quant_median_absd);
150
151
 private:
152
  float mul_dc_[4];
153
  float inv_mul_dc_[4];
154
155
  // These are serialized:
156
  int global_scale_;
157
  int quant_dc_;
158
159
  // These are derived from global_scale_:
160
  float inv_global_scale_;
161
  float global_scale_float_;  // reciprocal of inv_global_scale_
162
  float inv_quant_dc_;
163
164
  float zero_bias_[3];
165
  const DequantMatrices* dequant_;
166
};
167
168
struct QuantizerParams : public Fields {
169
4.96k
  QuantizerParams() { Bundle::Init(this); }
170
  JXL_FIELDS_NAME(QuantizerParams)
171
172
  Status VisitFields(Visitor* JXL_RESTRICT visitor) override;
173
174
  uint32_t global_scale;
175
  uint32_t quant_dc;
176
};
177
178
}  // namespace jxl
179
180
#endif  // LIB_JXL_QUANTIZER_H_