/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_ |