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