libjxl

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

epf.cc (5212B)


      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 // Edge-preserving smoothing: weighted average based on L1 patch similarity.
      7 
      8 #include "lib/jxl/epf.h"
      9 
     10 #include <math.h>
     11 #include <stdint.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 #include <algorithm>
     16 #include <atomic>
     17 #include <numeric>  // std::accumulate
     18 #include <vector>
     19 
     20 #include "lib/jxl/ac_strategy.h"
     21 #include "lib/jxl/base/compiler_specific.h"
     22 #include "lib/jxl/base/data_parallel.h"
     23 #include "lib/jxl/base/status.h"
     24 #include "lib/jxl/convolve.h"
     25 #include "lib/jxl/dec_cache.h"
     26 #include "lib/jxl/image.h"
     27 #include "lib/jxl/image_bundle.h"
     28 #include "lib/jxl/image_ops.h"
     29 #include "lib/jxl/loop_filter.h"
     30 #include "lib/jxl/quant_weights.h"
     31 #include "lib/jxl/quantizer.h"
     32 
     33 namespace jxl {
     34 
     35 // Mirror n floats starting at *p and store them before p.
     36 JXL_INLINE void LeftMirror(float* p, size_t n) {
     37   for (size_t i = 0; i < n; i++) {
     38     *(p - 1 - i) = p[i];
     39   }
     40 }
     41 
     42 // Mirror n floats starting at *(p - n) and store them at *p.
     43 JXL_INLINE void RightMirror(float* p, size_t n) {
     44   for (size_t i = 0; i < n; i++) {
     45     p[i] = *(p - 1 - i);
     46   }
     47 }
     48 
     49 void ComputeSigma(const LoopFilter& lf, const Rect& block_rect,
     50                   PassesDecoderState* state) {
     51   JXL_CHECK(lf.epf_iters > 0);
     52   const AcStrategyImage& ac_strategy = state->shared->ac_strategy;
     53   const float quant_scale = state->shared->quantizer.Scale();
     54 
     55   const size_t sigma_stride = state->sigma.PixelsPerRow();
     56   const size_t sharpness_stride = state->shared->epf_sharpness.PixelsPerRow();
     57 
     58   for (size_t by = 0; by < block_rect.ysize(); ++by) {
     59     float* JXL_RESTRICT sigma_row = block_rect.Row(&state->sigma, by);
     60     const uint8_t* JXL_RESTRICT sharpness_row =
     61         block_rect.ConstRow(state->shared->epf_sharpness, by);
     62     AcStrategyRow acs_row = ac_strategy.ConstRow(block_rect, by);
     63     const int32_t* const JXL_RESTRICT row_quant =
     64         block_rect.ConstRow(state->shared->raw_quant_field, by);
     65 
     66     for (size_t bx = 0; bx < block_rect.xsize(); bx++) {
     67       AcStrategy acs = acs_row[bx];
     68       size_t llf_x = acs.covered_blocks_x();
     69       if (!acs.IsFirstBlock()) continue;
     70       // quant_scale is smaller for low quality.
     71       // quant_scale is roughly 0.08 / butteraugli score.
     72       //
     73       // row_quant is smaller for low quality.
     74       // row_quant is a quantization multiplier of form 1.0 /
     75       // row_quant[bx]
     76       //
     77       // lf.epf_quant_mul is a parameter in the format
     78       // kInvSigmaNum is a constant
     79       float sigma_quant =
     80           lf.epf_quant_mul / (quant_scale * row_quant[bx] * kInvSigmaNum);
     81       for (size_t iy = 0; iy < acs.covered_blocks_y(); iy++) {
     82         for (size_t ix = 0; ix < acs.covered_blocks_x(); ix++) {
     83           float sigma =
     84               sigma_quant *
     85               lf.epf_sharp_lut[sharpness_row[bx + ix + iy * sharpness_stride]];
     86           // Avoid infinities.
     87           sigma = std::min(-1e-4f, sigma);  // TODO(veluca): remove this.
     88           sigma_row[bx + ix + kSigmaPadding +
     89                     (iy + kSigmaPadding) * sigma_stride] = 1.0f / sigma;
     90         }
     91       }
     92       // TODO(veluca): remove this padding.
     93       // Left padding with mirroring.
     94       if (bx + block_rect.x0() == 0) {
     95         for (size_t iy = 0; iy < acs.covered_blocks_y(); iy++) {
     96           LeftMirror(
     97               sigma_row + kSigmaPadding + (iy + kSigmaPadding) * sigma_stride,
     98               kSigmaBorder);
     99         }
    100       }
    101       // Right padding with mirroring.
    102       if (bx + block_rect.x0() + llf_x ==
    103           state->shared->frame_dim.xsize_blocks) {
    104         for (size_t iy = 0; iy < acs.covered_blocks_y(); iy++) {
    105           RightMirror(sigma_row + kSigmaPadding + bx + llf_x +
    106                           (iy + kSigmaPadding) * sigma_stride,
    107                       kSigmaBorder);
    108         }
    109       }
    110       // Offsets for row copying, in blocks.
    111       size_t offset_before = bx + block_rect.x0() == 0 ? 1 : bx + kSigmaPadding;
    112       size_t offset_after =
    113           bx + block_rect.x0() + llf_x == state->shared->frame_dim.xsize_blocks
    114               ? kSigmaPadding + llf_x + bx + kSigmaBorder
    115               : kSigmaPadding + llf_x + bx;
    116       size_t num = offset_after - offset_before;
    117       // Above
    118       if (by + block_rect.y0() == 0) {
    119         for (size_t iy = 0; iy < kSigmaBorder; iy++) {
    120           memcpy(
    121               sigma_row + offset_before +
    122                   (kSigmaPadding - 1 - iy) * sigma_stride,
    123               sigma_row + offset_before + (kSigmaPadding + iy) * sigma_stride,
    124               num * sizeof(*sigma_row));
    125         }
    126       }
    127       // Below
    128       if (by + block_rect.y0() + acs.covered_blocks_y() ==
    129           state->shared->frame_dim.ysize_blocks) {
    130         for (size_t iy = 0; iy < kSigmaBorder; iy++) {
    131           memcpy(
    132               sigma_row + offset_before +
    133                   sigma_stride * (acs.covered_blocks_y() + kSigmaPadding + iy),
    134               sigma_row + offset_before +
    135                   sigma_stride *
    136                       (acs.covered_blocks_y() + kSigmaPadding - 1 - iy),
    137               num * sizeof(*sigma_row));
    138         }
    139       }
    140     }
    141   }
    142 }
    143 
    144 }  // namespace jxl