/src/libjxl/lib/jxl/modular/transform/squeeze.h
Line | Count | Source |
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_MODULAR_TRANSFORM_SQUEEZE_H_ |
7 | | #define LIB_JXL_MODULAR_TRANSFORM_SQUEEZE_H_ |
8 | | |
9 | | // Haar-like transform: halves the resolution in one direction |
10 | | // A B -> (A+B)>>1 in one channel (average) -> same range as |
11 | | // original channel |
12 | | // A-B - tendency in a new channel ('residual' needed to make |
13 | | // the transform reversible) |
14 | | // -> theoretically range could be 2.5 |
15 | | // times larger (2 times without the |
16 | | // 'tendency'), but there should be lots |
17 | | // of zeroes |
18 | | // Repeated application (alternating horizontal and vertical squeezes) results |
19 | | // in downscaling |
20 | | // |
21 | | // The default coefficient ordering is low-frequency to high-frequency, as in |
22 | | // M. Antonini, M. Barlaud, P. Mathieu and I. Daubechies, "Image coding using |
23 | | // wavelet transform", IEEE Transactions on Image Processing, vol. 1, no. 2, pp. |
24 | | // 205-220, April 1992, doi: 10.1109/83.136597. |
25 | | |
26 | | #include <cstdlib> |
27 | | #include <vector> |
28 | | |
29 | | #include "lib/jxl/base/data_parallel.h" |
30 | | #include "lib/jxl/base/status.h" |
31 | | #include "lib/jxl/modular/modular_image.h" |
32 | | #include "lib/jxl/modular/transform/squeeze_params.h" |
33 | | |
34 | | namespace jxl { |
35 | | |
36 | | constexpr size_t kMaxFirstPreviewSize = 8; |
37 | | |
38 | | /* |
39 | | int avg=(A+B)>>1; |
40 | | int diff=(A-B); |
41 | | int rA=(diff+(avg<<1)+(diff&1))>>1; |
42 | | int rB=rA-diff; |
43 | | |
44 | | */ |
45 | | // |A B|C D|E F| |
46 | | // p a n p=avg(A,B), a=avg(C,D), n=avg(E,F) |
47 | | // |
48 | | // Goal: estimate C-D (avoiding ringing artifacts) |
49 | | // (ensuring that in smooth areas, a zero residual corresponds to a smooth |
50 | | // gradient) |
51 | | |
52 | | // best estimate for C: (B + 2*a)/3 |
53 | | // best estimate for D: (n + 3*a)/4 |
54 | | // best estimate for C-D: 4*B - 3*n - a /12 |
55 | | |
56 | | // avoid ringing by 1) only doing this if B <= a <= n or B >= a >= n |
57 | | // (otherwise, this is not a smooth area and we cannot really estimate C-D) |
58 | | // 2) making sure that B <= C <= D <= n or B >= C >= D >= n |
59 | | |
60 | | inline pixel_type_w SmoothTendency(pixel_type_w B, pixel_type_w a, |
61 | 10.3M | pixel_type_w n) { |
62 | 10.3M | pixel_type_w diff = 0; |
63 | 10.3M | if (B >= a && a >= n) { |
64 | 8.09M | diff = (4 * B - 3 * n - a + 6) / 12; |
65 | | // 2C = a<<1 + diff - diff&1 <= 2B so diff - diff&1 <= 2B - 2a |
66 | | // 2D = a<<1 - diff - diff&1 >= 2n so diff + diff&1 <= 2a - 2n |
67 | 8.09M | if (diff - (diff & 1) > 2 * (B - a)) diff = 2 * (B - a) + 1; |
68 | 8.09M | if (diff + (diff & 1) > 2 * (a - n)) diff = 2 * (a - n); |
69 | 8.09M | } else if (B <= a && a <= n) { |
70 | 456k | diff = (4 * B - 3 * n - a - 6) / 12; |
71 | | // 2C = a<<1 + diff + diff&1 >= 2B so diff + diff&1 >= 2B - 2a |
72 | | // 2D = a<<1 - diff + diff&1 <= 2n so diff - diff&1 >= 2a - 2n |
73 | 456k | if (diff + (diff & 1) < 2 * (B - a)) diff = 2 * (B - a) - 1; |
74 | 456k | if (diff - (diff & 1) < 2 * (a - n)) diff = 2 * (a - n); |
75 | 456k | } |
76 | 10.3M | return diff; |
77 | 10.3M | } |
78 | | |
79 | | void DefaultSqueezeParameters(std::vector<SqueezeParams> *parameters, |
80 | | const Image &image); |
81 | | |
82 | | Status CheckMetaSqueezeParams(const SqueezeParams ¶meter, int num_channels); |
83 | | |
84 | | Status MetaSqueeze(Image &image, std::vector<SqueezeParams> *parameters); |
85 | | |
86 | | Status InvSqueeze(Image &input, const std::vector<SqueezeParams> ¶meters, |
87 | | ThreadPool *pool); |
88 | | |
89 | | } // namespace jxl |
90 | | |
91 | | #endif // LIB_JXL_MODULAR_TRANSFORM_SQUEEZE_H_ |