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