Coverage Report

Created: 2026-06-15 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/noise_model.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2017, Alliance for Open Media. All rights reserved
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10
 */
11
12
#include "EbConfigMacros.h"
13
14
#if CONFIG_ENABLE_FILM_GRAIN
15
#include <math.h>
16
#include <stdio.h>
17
#include <stdlib.h>
18
#include "noise_model.h"
19
#include "definitions.h"
20
#include "sequence_control_set.h"
21
#include "noise_util.h"
22
#include "mathutils.h"
23
#include "svt_log.h"
24
#include "aom_dsp_rtcd.h"
25
#include "pic_operators.h"
26
27
static const int32_t k_max_lag = 4;
28
29
void svt_aom_un_pack2d(uint16_t* in16_bit_buffer, uint32_t in_stride, uint8_t* out8_bit_buffer, uint32_t out8_stride,
30
                       uint8_t* outn_bit_buffer, uint32_t outn_stride, uint32_t width, uint32_t height);
31
32
void svt_aom_pack2d_src(uint8_t* in8_bit_buffer, uint32_t in8_stride, uint8_t* inn_bit_buffer, uint32_t inn_stride,
33
                        uint16_t* out16_bit_buffer, uint32_t out_stride, uint32_t width, uint32_t height);
34
void svt_aom_compressed_pack_sb(uint8_t* in8_bit_buffer, uint32_t in8_stride, uint8_t* inn_bit_buffer,
35
                                uint32_t inn_stride, uint16_t* out16_bit_buffer, uint32_t out_stride, uint32_t width,
36
                                uint32_t height);
37
// Defines a function that can be used to obtain the mean of a block for the
38
// provided data type (uint8_t, or uint16_t)
39
#define GET_BLOCK_MEAN(INT_TYPE, suffix)                                                                            \
40
    static double get_block_mean_##suffix(                                                                          \
41
        const INT_TYPE* data, int32_t w, int32_t h, int32_t stride, int32_t x_o, int32_t y_o, int32_t block_size) { \
42
        const int32_t max_h      = AOMMIN(h - y_o, block_size);                                                     \
43
        const int32_t max_w      = AOMMIN(w - x_o, block_size);                                                     \
44
        double        block_mean = 0;                                                                               \
45
        for (int32_t y = 0; y < max_h; ++y) {                                                                       \
46
            for (int32_t x = 0; x < max_w; ++x) {                                                                   \
47
                block_mean += data[(y_o + y) * stride + x_o + x];                                                   \
48
            }                                                                                                       \
49
        }                                                                                                           \
50
        return block_mean / (max_w * max_h);                                                                        \
51
    }
52
53
GET_BLOCK_MEAN(uint8_t, lowbd);
54
GET_BLOCK_MEAN(uint16_t, highbd);
55
56
static INLINE double get_block_mean(const uint8_t* data, int32_t w, int32_t h, int32_t stride, int32_t x_o, int32_t y_o,
57
                                    int32_t block_size, int32_t use_highbd) {
58
    if (use_highbd) {
59
        return get_block_mean_highbd((const uint16_t*)data, w, h, stride, x_o, y_o, block_size);
60
    }
61
    return get_block_mean_lowbd(data, w, h, stride, x_o, y_o, block_size);
62
}
63
64
// Defines a function that can be used to obtain the variance of a block
65
// for the provided data type (uint8_t, or uint16_t)
66
#define GET_NOISE_VAR(INT_TYPE, suffix)                                                                             \
67
    static double get_noise_var_##suffix(const INT_TYPE* data,                                                      \
68
                                         const INT_TYPE* denoised,                                                  \
69
                                         int32_t         stride,                                                    \
70
                                         int32_t         w,                                                         \
71
                                         int32_t         h,                                                         \
72
                                         int32_t         x_o,                                                       \
73
                                         int32_t         y_o,                                                       \
74
                                         int32_t         block_size_x,                                              \
75
                                         int32_t         block_size_y) {                                                    \
76
        const int32_t max_h      = AOMMIN(h - y_o, block_size_y);                                                   \
77
        const int32_t max_w      = AOMMIN(w - x_o, block_size_x);                                                   \
78
        double        noise_var  = 0;                                                                               \
79
        double        noise_mean = 0;                                                                               \
80
        for (int32_t y = 0; y < max_h; ++y) {                                                                       \
81
            for (int32_t x = 0; x < max_w; ++x) {                                                                   \
82
                double noise = (double)data[(y_o + y) * stride + x_o + x] - denoised[(y_o + y) * stride + x_o + x]; \
83
                noise_mean += noise;                                                                                \
84
                noise_var += noise * noise;                                                                         \
85
            }                                                                                                       \
86
        }                                                                                                           \
87
        noise_mean /= (max_w * max_h);                                                                              \
88
        return noise_var / (max_w * max_h) - noise_mean * noise_mean;                                               \
89
    }
90
91
GET_NOISE_VAR(uint8_t, lowbd);
92
GET_NOISE_VAR(uint16_t, highbd);
93
94
static INLINE double get_noise_var(const uint8_t* data, const uint8_t* denoised, int32_t w, int32_t h, int32_t stride,
95
                                   int32_t x_o, int32_t y_o, int32_t block_size_x, int32_t block_size_y,
96
                                   int32_t use_highbd) {
97
    if (use_highbd) {
98
        return get_noise_var_highbd(
99
            (const uint16_t*)data, (const uint16_t*)denoised, w, h, stride, x_o, y_o, block_size_x, block_size_y);
100
    }
101
    return get_noise_var_lowbd(data, denoised, w, h, stride, x_o, y_o, block_size_x, block_size_y);
102
}
103
104
static void equation_system_free(AomEquationSystem* eqns) {
105
    if (!eqns) {
106
        return;
107
    }
108
    free(eqns->A);
109
    eqns->A = NULL;
110
    free(eqns->b);
111
    eqns->b = NULL;
112
    free(eqns->x);
113
    eqns->x = NULL;
114
    eqns->n = 0;
115
}
116
117
static void equation_system_clear(AomEquationSystem* eqns) {
118
    const int32_t n = eqns->n;
119
    memset(eqns->A, 0, sizeof(*eqns->A) * n * n);
120
    memset(eqns->x, 0, sizeof(*eqns->x) * n);
121
    memset(eqns->b, 0, sizeof(*eqns->b) * n);
122
}
123
124
static void equation_system_copy(AomEquationSystem* dst, const AomEquationSystem* src) {
125
    const int32_t n = dst->n;
126
    SVT_MEMCPY(dst->A, src->A, sizeof(*dst->A) * n * n);
127
    SVT_MEMCPY(dst->x, src->x, sizeof(*dst->x) * n);
128
    SVT_MEMCPY(dst->b, src->b, sizeof(*dst->b) * n);
129
}
130
131
static int32_t equation_system_init(AomEquationSystem* eqns, int32_t n) {
132
    eqns->A = (double*)malloc(sizeof(*eqns->A) * n * n);
133
    eqns->b = (double*)malloc(sizeof(*eqns->b) * n);
134
    eqns->x = (double*)malloc(sizeof(*eqns->x) * n);
135
    eqns->n = n;
136
    if (!eqns->A || !eqns->b || !eqns->x) {
137
        SVT_ERROR("Failed to allocate system of equations of size %d\n", n);
138
        equation_system_free(eqns);
139
        return 0;
140
    }
141
    equation_system_clear(eqns);
142
    return 1;
143
}
144
145
static int32_t equation_system_solve(AomEquationSystem* eqns) {
146
    const int32_t n   = eqns->n;
147
    double*       b   = (double*)malloc(sizeof(*b) * n);
148
    double*       A   = (double*)malloc(sizeof(*A) * n * n);
149
    int32_t       ret = 0;
150
    if (A == NULL || b == NULL) {
151
        SVT_ERROR("Unable to allocate temp values of size %dx%d\n", n, n);
152
        free(b);
153
        free(A);
154
        return 0;
155
    }
156
    SVT_MEMCPY(A, eqns->A, sizeof(*eqns->A) * n * n);
157
    SVT_MEMCPY(b, eqns->b, sizeof(*eqns->b) * n);
158
    ret = linsolve(n, A, eqns->n, b, eqns->x);
159
    free(b);
160
    free(A);
161
162
    if (ret == 0) {
163
        return 0;
164
    }
165
    return 1;
166
}
167
168
static void noise_strength_solver_clear(AomNoiseStrengthSolver* solver) {
169
    equation_system_clear(&solver->eqns);
170
    solver->num_equations = 0;
171
    solver->total         = 0;
172
}
173
174
0
static void noise_strength_solver_copy(AomNoiseStrengthSolver* dest, AomNoiseStrengthSolver* src) {
175
0
    equation_system_copy(&dest->eqns, &src->eqns);
176
0
    dest->num_equations = src->num_equations;
177
0
    dest->total         = src->total;
178
0
}
179
180
// Return the number of coefficients required for the given parameters
181
static int32_t num_coeffs(const AomNoiseModelParams params) {
182
    const int32_t n = 2 * params.lag + 1;
183
    switch (params.shape) {
184
    case AOM_NOISE_SHAPE_DIAMOND:
185
        return params.lag * (params.lag + 1);
186
    case AOM_NOISE_SHAPE_SQUARE:
187
        return (n * n) / 2;
188
    }
189
    return 0;
190
}
191
192
static int32_t noise_state_init(AomNoiseState* state, int32_t n, int32_t bit_depth) {
193
    const int32_t k_num_bins = 20;
194
    if (!equation_system_init(&state->eqns, n)) {
195
        SVT_ERROR("Failed initialization noise state with size %d\n", n);
196
        return 0;
197
    }
198
    state->ar_gain          = 1.0;
199
    state->num_observations = 0;
200
    return svt_aom_noise_strength_solver_init(&state->strength_solver, k_num_bins, bit_depth);
201
}
202
203
static void set_chroma_coefficient_fallback_soln(AomEquationSystem* eqns) {
204
    const double  k_tolerance = 1e-6;
205
    const int32_t last        = eqns->n - 1;
206
    // Set all of the AR coefficients to zero, but try to solve for correlation
207
    // with the luma channel
208
    memset(eqns->x, 0, sizeof(*eqns->x) * eqns->n);
209
    if (fabs(eqns->A[last * eqns->n + last]) > k_tolerance) {
210
        eqns->x[last] = eqns->b[last] / eqns->A[last * eqns->n + last];
211
    }
212
}
213
214
0
int32_t svt_aom_noise_strength_lut_init(AomNoiseStrengthLut* lut, int32_t num_points) {
215
0
    if (!lut) {
216
0
        return 0;
217
0
    }
218
0
    lut->points = (double (*)[2])malloc(num_points * sizeof(*lut->points));
219
0
    if (!lut->points) {
220
0
        return 0;
221
0
    }
222
0
    lut->num_points = num_points;
223
0
    memset(lut->points, 0, sizeof(*lut->points) * num_points);
224
0
    return 1;
225
0
}
226
227
0
void svt_aom_noise_strength_lut_free(AomNoiseStrengthLut* lut) {
228
0
    if (!lut) {
229
0
        return;
230
0
    }
231
0
    free(lut->points);
232
0
    lut->points     = NULL;
233
0
    lut->num_points = 0;
234
0
}
235
236
static double noise_strength_solver_get_bin_index(const AomNoiseStrengthSolver* solver, double value) {
237
    const double val   = fclamp(value, solver->min_intensity, solver->max_intensity);
238
    const double range = solver->max_intensity - solver->min_intensity;
239
    return (solver->num_bins - 1) * (val - solver->min_intensity) / range;
240
}
241
242
static double noise_strength_solver_get_value(const AomNoiseStrengthSolver* solver, double x) {
243
    const double  bin    = noise_strength_solver_get_bin_index(solver, x);
244
    const int32_t bin_i0 = (int32_t)floor(bin);
245
    const int32_t bin_i1 = AOMMIN(solver->num_bins - 1, bin_i0 + 1);
246
    const double  a      = bin - bin_i0;
247
    return (1.0 - a) * solver->eqns.x[bin_i0] + a * solver->eqns.x[bin_i1];
248
}
249
250
void svt_aom_noise_strength_solver_add_measurement(AomNoiseStrengthSolver* solver, double block_mean,
251
0
                                                   double noise_std) {
252
0
    const double  bin    = noise_strength_solver_get_bin_index(solver, block_mean);
253
0
    const int32_t bin_i0 = (int32_t)floor(bin);
254
0
    const int32_t bin_i1 = AOMMIN(solver->num_bins - 1, bin_i0 + 1);
255
0
    const double  a      = bin - bin_i0;
256
0
    const int32_t n      = solver->num_bins;
257
0
    solver->eqns.A[bin_i0 * n + bin_i0] += (1.0 - a) * (1.0 - a);
258
0
    solver->eqns.A[bin_i1 * n + bin_i0] += a * (1.0 - a);
259
0
    solver->eqns.A[bin_i1 * n + bin_i1] += a * a;
260
0
    solver->eqns.A[bin_i0 * n + bin_i1] += a * (1.0 - a);
261
0
    solver->eqns.b[bin_i0] += (1.0 - a) * noise_std;
262
0
    solver->eqns.b[bin_i1] += a * noise_std;
263
0
    solver->total += noise_std;
264
0
    solver->num_equations++;
265
0
}
266
267
0
int32_t svt_aom_noise_strength_solver_solve(AomNoiseStrengthSolver* solver) {
268
    // Add regularization proportional to the number of constraints
269
0
    const int32_t n       = solver->num_bins;
270
0
    const double  k_alpha = 2.0 * (double)(solver->num_equations) / n;
271
0
    int32_t       result  = 0;
272
0
    double        mean    = 0;
273
274
    // Do this in a non-destructive manner so it is not confusing to the caller
275
0
    double* old_a = solver->eqns.A;
276
0
    double* A     = (double*)malloc(sizeof(*A) * n * n);
277
0
    if (!A) {
278
0
        SVT_ERROR("Unable to allocate copy of A\n");
279
0
        return 0;
280
0
    }
281
0
    SVT_MEMCPY(A, old_a, sizeof(*A) * n * n);
282
283
0
    for (int32_t i = 0; i < n; ++i) {
284
0
        const int32_t i_lo = AOMMAX(0, i - 1);
285
0
        const int32_t i_hi = AOMMIN(n - 1, i + 1);
286
0
        A[i * n + i_lo] -= k_alpha;
287
0
        A[i * n + i] += 2 * k_alpha;
288
0
        A[i * n + i_hi] -= k_alpha;
289
0
    }
290
291
    // Small regularization to give average noise strength
292
0
    mean = solver->total / solver->num_equations;
293
0
    for (int32_t i = 0; i < n; ++i) {
294
0
        A[i * n + i] += 1.0 / 8192.;
295
0
        solver->eqns.b[i] += mean / 8192.;
296
0
    }
297
0
    solver->eqns.A = A;
298
0
    result         = equation_system_solve(&solver->eqns);
299
0
    solver->eqns.A = old_a;
300
301
0
    free(A);
302
0
    return result;
303
0
}
304
305
0
int32_t svt_aom_noise_strength_solver_init(AomNoiseStrengthSolver* solver, int32_t num_bins, int32_t bit_depth) {
306
0
    if (!solver) {
307
0
        return 0;
308
0
    }
309
0
    memset(solver, 0, sizeof(*solver));
310
0
    solver->num_bins      = num_bins;
311
0
    solver->min_intensity = 0;
312
0
    solver->max_intensity = (1 << bit_depth) - 1;
313
0
    solver->total         = 0;
314
0
    solver->num_equations = 0;
315
0
    return equation_system_init(&solver->eqns, num_bins);
316
0
}
317
318
0
double svt_aom_noise_strength_solver_get_center(const AomNoiseStrengthSolver* solver, int32_t i) {
319
0
    const double  range = solver->max_intensity - solver->min_intensity;
320
0
    const int32_t n     = solver->num_bins;
321
0
    return ((double)i) / (n - 1) * range + solver->min_intensity;
322
0
}
323
324
// Computes the residual if a point were to be removed from the lut. This is
325
// calculated as the area between the output of the solver and the line segment
326
// that would be formed between [x_{i - 1}, x_{i + 1}).
327
static void update_piecewise_linear_residual(const AomNoiseStrengthSolver* solver, const AomNoiseStrengthLut* lut,
328
                                             double* residual, int32_t start, int32_t end) {
329
    const double dx = 255. / solver->num_bins;
330
    for (int32_t i = AOMMAX(start, 1); i < AOMMIN(end, lut->num_points - 1); ++i) {
331
        const int32_t lower = AOMMAX(
332
            0, (int32_t)floor(noise_strength_solver_get_bin_index(solver, lut->points[i - 1][0])));
333
        const int32_t upper = AOMMIN(solver->num_bins - 1,
334
                                     (int32_t)ceil(noise_strength_solver_get_bin_index(solver, lut->points[i + 1][0])));
335
        double        r     = 0;
336
        for (int32_t j = lower; j <= upper; ++j) {
337
            const double x = svt_aom_noise_strength_solver_get_center(solver, j);
338
            if (x < lut->points[i - 1][0]) {
339
                continue;
340
            }
341
            if (x >= lut->points[i + 1][0]) {
342
                continue;
343
            }
344
            const double y          = solver->eqns.x[j];
345
            const double a          = (x - lut->points[i - 1][0]) / (lut->points[i + 1][0] - lut->points[i - 1][0]);
346
            const double estimate_y = lut->points[i - 1][1] * (1.0 - a) + lut->points[i + 1][1] * a;
347
            r += fabs(y - estimate_y);
348
        }
349
        residual[i] = r * dx;
350
    }
351
}
352
353
int32_t svt_aom_noise_strength_solver_fit_piecewise(const AomNoiseStrengthSolver* solver, int32_t max_output_points,
354
0
                                                    AomNoiseStrengthLut* lut) {
355
    // The tolerance is normalized to be give consistent results between
356
    // different bit-depths.
357
0
    const double k_tolerance = solver->max_intensity * 0.00625 / 255.0;
358
0
    if (!svt_aom_noise_strength_lut_init(lut, solver->num_bins)) {
359
0
        SVT_ERROR("Failed to init lut\n");
360
0
        return 0;
361
0
    }
362
0
    for (int32_t i = 0; i < solver->num_bins; ++i) {
363
0
        lut->points[i][0] = svt_aom_noise_strength_solver_get_center(solver, i);
364
0
        lut->points[i][1] = solver->eqns.x[i];
365
0
    }
366
0
    if (max_output_points < 0) {
367
0
        max_output_points = solver->num_bins;
368
0
    }
369
0
    double* residual = malloc(solver->num_bins * sizeof(*residual));
370
0
    ASSERT(residual != NULL);
371
0
    memset(residual, 0, sizeof(*residual) * solver->num_bins);
372
373
0
    update_piecewise_linear_residual(solver, lut, residual, 0, solver->num_bins);
374
375
    // Greedily remove points if there are too many or if it doesn't hurt local
376
    // approximation (never remove the end points)
377
0
    while (lut->num_points > 2) {
378
0
        int32_t min_index = 1;
379
0
        for (int32_t j = 1; j < lut->num_points - 1; ++j) {
380
0
            if (residual[j] < residual[min_index]) {
381
0
                min_index = j;
382
0
            }
383
0
        }
384
0
        const double dx           = lut->points[min_index + 1][0] - lut->points[min_index - 1][0];
385
0
        const double avg_residual = residual[min_index] / dx;
386
0
        if (lut->num_points <= max_output_points && avg_residual > k_tolerance) {
387
0
            break;
388
0
        }
389
0
        const int32_t num_remaining = lut->num_points - min_index - 1;
390
0
        memmove(lut->points + min_index, lut->points + min_index + 1, sizeof(lut->points[0]) * num_remaining);
391
0
        lut->num_points--;
392
393
0
        update_piecewise_linear_residual(solver, lut, residual, min_index - 1, min_index + 1);
394
0
    }
395
0
    free(residual);
396
0
    return 1;
397
0
}
398
399
int32_t svt_aom_flat_block_finder_init(AomFlatBlockFinder* block_finder, int32_t block_size, int32_t bit_depth,
400
0
                                       int32_t use_highbd) {
401
0
    const int32_t     n = block_size * block_size;
402
0
    AomEquationSystem eqns;
403
0
    if (!equation_system_init(&eqns, kLowPolyNumParams)) {
404
0
        SVT_ERROR("Failed to init equation system for block_size=%d\n", block_size);
405
0
        return 0;
406
0
    }
407
408
0
    double* at_a_inv = (double*)malloc(kLowPolyNumParams * kLowPolyNumParams * sizeof(*at_a_inv));
409
0
    double* A        = (double*)malloc(kLowPolyNumParams * n * sizeof(*A));
410
0
    if (at_a_inv == NULL || A == NULL) {
411
0
        SVT_ERROR("Failed to alloc A or at_a_inv for block_size=%d\n", block_size);
412
0
        free(at_a_inv);
413
0
        free(A);
414
0
        equation_system_free(&eqns);
415
0
        return 0;
416
0
    }
417
418
0
    block_finder->A             = A;
419
0
    block_finder->at_a_inv      = at_a_inv;
420
0
    block_finder->block_size    = block_size;
421
0
    block_finder->normalization = (1 << bit_depth) - 1;
422
0
    block_finder->use_highbd    = use_highbd;
423
424
0
    for (int32_t y = 0; y < block_size; ++y) {
425
0
        const double yd = ((double)y - block_size / 2.) / (block_size / 2.);
426
0
        for (int32_t x = 0; x < block_size; ++x) {
427
0
            const double  xd               = ((double)x - block_size / 2.) / (block_size / 2.);
428
0
            const double  coords[3]        = {yd, xd, 1};
429
0
            const int32_t row              = y * block_size + x;
430
0
            A[kLowPolyNumParams * row + 0] = yd;
431
0
            A[kLowPolyNumParams * row + 1] = xd;
432
0
            A[kLowPolyNumParams * row + 2] = 1;
433
434
0
            for (int i = 0; i < kLowPolyNumParams; ++i) {
435
0
                for (int j = 0; j < kLowPolyNumParams; ++j) {
436
0
                    eqns.A[kLowPolyNumParams * i + j] += coords[i] * coords[j];
437
0
                }
438
0
            }
439
0
        }
440
0
    }
441
442
    // Lazy inverse using existing equation solver.
443
0
    for (int i = 0; i < kLowPolyNumParams; ++i) {
444
0
        memset(eqns.b, 0, sizeof(*eqns.b) * kLowPolyNumParams);
445
0
        eqns.b[i] = 1;
446
0
        equation_system_solve(&eqns);
447
448
0
        for (int j = 0; j < kLowPolyNumParams; ++j) {
449
0
            at_a_inv[j * kLowPolyNumParams + i] = eqns.x[j];
450
0
        }
451
0
    }
452
0
    equation_system_free(&eqns);
453
0
    return 1;
454
0
}
455
456
0
void svt_aom_flat_block_finder_free(AomFlatBlockFinder* block_finder) {
457
0
    if (!block_finder) {
458
0
        return;
459
0
    }
460
0
    free(block_finder->A);
461
0
    free(block_finder->at_a_inv);
462
0
    memset(block_finder, 0, sizeof(*block_finder));
463
0
}
464
465
void svt_aom_flat_block_finder_extract_block_c(const AomFlatBlockFinder* block_finder, const uint8_t* const data,
466
                                               int32_t w, int32_t h, int32_t stride, int32_t offsx, int32_t offsy,
467
0
                                               double* plane, double* block) {
468
0
    const int32_t block_size = block_finder->block_size;
469
0
    const int32_t n          = block_size * block_size;
470
0
    const double* A          = block_finder->A;
471
0
    const double* at_a_inv   = block_finder->at_a_inv;
472
0
    const double  recp_norm  = 1 / block_finder->normalization;
473
0
    double        plane_coords[kLowPolyNumParams];
474
0
    double        at_a_inv__b[kLowPolyNumParams];
475
0
    int32_t       xi, yi, i;
476
477
0
    if (block_finder->use_highbd) {
478
0
        const uint16_t* const data16 = (const uint16_t* const)data;
479
0
        for (yi = 0; yi < block_size; ++yi) {
480
0
            const int32_t y = clamp(offsy + yi, 0, h - 1);
481
0
            for (xi = 0; xi < block_size; ++xi) {
482
0
                const int32_t x             = clamp(offsx + xi, 0, w - 1);
483
0
                block[yi * block_size + xi] = ((double)data16[y * stride + x]) * recp_norm;
484
0
            }
485
0
        }
486
0
    } else {
487
0
        for (yi = 0; yi < block_size; ++yi) {
488
0
            const int32_t y = clamp(offsy + yi, 0, h - 1);
489
0
            for (xi = 0; xi < block_size; ++xi) {
490
0
                const int32_t x             = clamp(offsx + xi, 0, w - 1);
491
0
                block[yi * block_size + xi] = ((double)data[y * stride + x]) * recp_norm;
492
0
            }
493
0
        }
494
0
    }
495
0
#if (kLowPolyNumParams == 3)
496
0
    multiply_mat_1_n_3(block, A, at_a_inv__b, n);
497
0
    multiply_mat_3_3_1(at_a_inv, at_a_inv__b, plane_coords);
498
0
    multiply_mat_n_3_1(A, plane_coords, plane, n);
499
#else
500
    multiply_mat(block, A, at_a_inv__b, 1, n, kLowPolyNumParams);
501
    multiply_mat(at_a_inv, at_a_inv__b, plane_coords, kLowPolyNumParams, kLowPolyNumParams, 1);
502
    multiply_mat(A, plane_coords, plane, n, kLowPolyNumParams, 1);
503
#endif
504
505
0
    for (i = 0; i < n; ++i) {
506
0
        block[i] -= plane[i];
507
0
    }
508
0
}
509
510
typedef struct {
511
    int32_t index;
512
    float   score;
513
} IndexAndscore;
514
515
static int compare_scores(const void* a, const void* b) {
516
    const float diff = ((IndexAndscore*)a)->score - ((IndexAndscore*)b)->score;
517
    return diff < 0 ? -1 : diff > 0;
518
}
519
520
int32_t svt_aom_flat_block_finder_run(const AomFlatBlockFinder* block_finder, const uint8_t* const data, int32_t w,
521
0
                                      int32_t h, int32_t stride, uint8_t* flat_blocks) {
522
    // The gradient-based features used in this code are based on:
523
    //  A. Kokaram, D. Kelly, H. Denman and A. Crawford, "Measuring noise
524
    //  correlation for improved video denoising," 2012 19th, ICIP.
525
    // The thresholds are more lenient to allow for correct grain modeling
526
    // if extreme cases.
527
0
    const int32_t  block_size        = block_finder->block_size;
528
0
    const int32_t  n                 = block_size * block_size;
529
0
    const double   k_trace_threshold = 0.15 / (32 * 32);
530
0
    const double   k_ratio_threshold = 1.25;
531
0
    const double   k_norm_threshold  = 0.08 / (32 * 32);
532
0
    const double   k_var_threshold   = 0.005 / (double)n;
533
0
    const int32_t  num_blocks_w      = (w + block_size - 1) / block_size;
534
0
    const int32_t  num_blocks_h      = (h + block_size - 1) / block_size;
535
0
    int32_t        num_flat          = 0;
536
0
    double*        plane             = (double*)malloc(n * sizeof(*plane));
537
0
    double*        block             = (double*)malloc(n * sizeof(*block));
538
0
    IndexAndscore* scores            = (IndexAndscore*)malloc(num_blocks_w * num_blocks_h * sizeof(*scores));
539
0
    if (plane == NULL || block == NULL || scores == NULL) {
540
0
        SVT_ERROR("Failed to allocate memory for block of size %d\n", n);
541
0
        free(plane);
542
0
        free(block);
543
0
        free(scores);
544
0
        return -1;
545
0
    }
546
547
#ifdef NOISE_MODEL_LOG_SCORE
548
    SVT_ERROR("score = [");
549
#endif
550
0
    for (int32_t by = 0; by < num_blocks_h; ++by) {
551
0
        for (int32_t bx = 0; bx < num_blocks_w; ++bx) {
552
            // Compute gradient covariance matrix.
553
0
            double g_xx = 0, g_xy = 0, g_yy = 0;
554
0
            double var  = 0;
555
0
            double mean = 0;
556
0
            svt_aom_flat_block_finder_extract_block(
557
0
                block_finder, data, w, h, stride, bx * block_size, by * block_size, plane, block);
558
559
0
            for (int32_t yi = 1; yi < block_size - 1; ++yi) {
560
0
                for (int32_t xi = 1; xi < block_size - 1; ++xi) {
561
0
                    const double gx = (block[yi * block_size + xi + 1] - block[yi * block_size + xi - 1]) / 2;
562
0
                    const double gy = (block[yi * block_size + xi + block_size] -
563
0
                                       block[yi * block_size + xi - block_size]) /
564
0
                        2;
565
0
                    g_xx += gx * gx;
566
0
                    g_xy += gx * gy;
567
0
                    g_yy += gy * gy;
568
569
0
                    mean += block[yi * block_size + xi];
570
0
                    var += block[yi * block_size + xi] * block[yi * block_size + xi];
571
0
                }
572
0
            }
573
0
            mean /= (block_size - 2) * (block_size - 2);
574
575
            // Normalize gradients by BlockSize.
576
0
            g_xx /= ((block_size - 2) * (block_size - 2));
577
0
            g_xy /= ((block_size - 2) * (block_size - 2));
578
0
            g_yy /= ((block_size - 2) * (block_size - 2));
579
0
            var = var / ((block_size - 2) * (block_size - 2)) - mean * mean;
580
581
0
            {
582
0
                const double  trace   = g_xx + g_yy;
583
0
                const double  det     = g_xx * g_yy - g_xy * g_xy;
584
0
                const double  e1      = (trace + sqrt(trace * trace - 4 * det)) / 2.;
585
0
                const double  e2      = (trace - sqrt(trace * trace - 4 * det)) / 2.;
586
0
                const double  norm    = e1; // Spectral norm
587
0
                const double  ratio   = (e1 / AOMMAX(e2, 1e-6));
588
0
                const int32_t is_flat = (trace < k_trace_threshold) && (ratio < k_ratio_threshold) &&
589
0
                    (norm < k_norm_threshold) && (var > k_var_threshold);
590
                // The following weights are used to combine the above features to give
591
                // a sigmoid score for flatness. If the input was normalized to [0,100]
592
                // the magnitude of these values would be close to 1 (e.g., weights
593
                // corresponding to variance would be a factor of 10000x smaller).
594
                // The weights are given in the following order:
595
                //    [{var}, {ratio}, {trace}, {norm}, offset]
596
                // with one of the most discriminative being simply the variance.
597
0
                const double weights[5]              = {-6682, -0.2056, 13087, -12434, 2.5694};
598
0
                const float  score                   = (float)(1.0 /
599
0
                                            (1 +
600
0
                                             exp(-(weights[0] * var + weights[1] * ratio + weights[2] * trace +
601
0
                                                   weights[3] * norm + weights[4]))));
602
0
                flat_blocks[by * num_blocks_w + bx]  = is_flat ? 255 : 0;
603
0
                scores[by * num_blocks_w + bx].score = var > k_var_threshold ? score : 0;
604
0
                scores[by * num_blocks_w + bx].index = by * num_blocks_w + bx;
605
#ifdef NOISE_MODEL_LOG_SCORE
606
                SVT_ERROR("%g %g %g %g %g %d ", score, var, ratio, trace, norm, is_flat);
607
#endif
608
0
                num_flat += is_flat;
609
0
            }
610
0
        }
611
#ifdef NOISE_MODEL_LOG_SCORE
612
        SVT_ERROR("\n");
613
#endif
614
0
    }
615
#ifdef NOISE_MODEL_LOG_SCORE
616
    SVT_ERROR("];\n");
617
#endif
618
    // Find the top-scored blocks (most likely to be flat) and set the flat blocks
619
    // be the union of the thresholded results and the top 10th percentile of the
620
    // scored results.
621
0
    qsort(scores, num_blocks_w * num_blocks_h, sizeof(*scores), &compare_scores);
622
0
    const int32_t top_nth_percentile = num_blocks_w * num_blocks_h * 90 / 100;
623
0
    const float   score_threshold    = scores[top_nth_percentile].score;
624
0
    for (int32_t i = 0; i < num_blocks_w * num_blocks_h; ++i) {
625
0
        if (scores[i].score >= score_threshold) {
626
0
            num_flat += flat_blocks[scores[i].index] == 0;
627
0
            flat_blocks[scores[i].index] |= 1;
628
0
        }
629
0
    }
630
0
    free(block);
631
0
    free(plane);
632
0
    free(scores);
633
0
    return num_flat;
634
0
}
635
636
0
int32_t svt_aom_noise_model_init(AomNoiseModel* model, const AomNoiseModelParams params) {
637
0
    const int32_t n         = num_coeffs(params);
638
0
    const int32_t lag       = params.lag;
639
0
    const int32_t bit_depth = params.bit_depth;
640
0
    int32_t       i         = 0;
641
642
0
    memset(model, 0, sizeof(*model));
643
0
    if (params.lag < 1) {
644
0
        SVT_ERROR("Invalid noise param: lag = %d must be >= 1\n", params.lag);
645
0
        return 0;
646
0
    }
647
0
    if (params.lag > k_max_lag) {
648
0
        SVT_ERROR("Invalid noise param: lag = %d must be <= %d\n", params.lag, k_max_lag);
649
0
        return 0;
650
0
    }
651
0
    SVT_MEMCPY(&model->params, &params, sizeof(params));
652
653
0
    for (int c = 0; c < 3; ++c) {
654
0
        if (!noise_state_init(&model->combined_state[c], n + (c > 0), bit_depth)) {
655
0
            SVT_ERROR("Failed to allocate noise state for channel %d\n", c);
656
0
            svt_aom_noise_model_free(model);
657
0
            return 0;
658
0
        }
659
0
        if (!noise_state_init(&model->latest_state[c], n + (c > 0), bit_depth)) {
660
0
            SVT_ERROR("Failed to allocate noise state for channel %d\n", c);
661
0
            svt_aom_noise_model_free(model);
662
0
            return 0;
663
0
        }
664
0
    }
665
0
    model->n      = n;
666
0
    model->coords = (int32_t (*)[2])malloc(sizeof(*model->coords) * n);
667
0
    if (!model->coords) {
668
0
        SVT_ERROR("Failed to allocate memory for coords\n");
669
0
        svt_aom_noise_model_free(model);
670
0
        return 0;
671
0
    }
672
0
    for (int32_t y = -lag; y <= 0; ++y) {
673
0
        const int32_t max_x = y == 0 ? -1 : lag;
674
0
        for (int32_t x = -lag; x <= max_x; ++x) {
675
0
            switch (params.shape) {
676
0
            case AOM_NOISE_SHAPE_DIAMOND:
677
0
                if (abs(x) <= y + lag) {
678
0
                    model->coords[i][0] = x;
679
0
                    model->coords[i][1] = y;
680
0
                    ++i;
681
0
                }
682
0
                break;
683
0
            case AOM_NOISE_SHAPE_SQUARE:
684
0
                model->coords[i][0] = x;
685
0
                model->coords[i][1] = y;
686
0
                ++i;
687
0
                break;
688
0
            default:
689
0
                SVT_ERROR("Invalid shape\n");
690
0
                svt_aom_noise_model_free(model);
691
0
                return 0;
692
0
            }
693
0
        }
694
0
    }
695
0
    assert(i == n);
696
0
    return 1;
697
0
}
698
699
0
void svt_aom_noise_model_free(AomNoiseModel* model) {
700
0
    int32_t c = 0;
701
0
    if (!model) {
702
0
        return;
703
0
    }
704
705
0
    free(model->coords);
706
0
    for (c = 0; c < 3; ++c) {
707
0
        equation_system_free(&model->latest_state[c].eqns);
708
0
        equation_system_free(&model->combined_state[c].eqns);
709
710
0
        equation_system_free(&model->latest_state[c].strength_solver.eqns);
711
0
        equation_system_free(&model->combined_state[c].strength_solver.eqns);
712
0
    }
713
0
    memset(model, 0, sizeof(*model));
714
0
}
715
716
// Extracts the neighborhood defined by coords around point (x, y) from
717
// the difference between the data and denoised images. Also extracts the
718
// entry (possibly downsampled) for (x, y) in the alt_data (e.g., luma).
719
#define EXTRACT_AR_ROW(INT_TYPE, suffix)                                                 \
720
    static double extract_ar_row_##suffix(int32_t (*coords)[2],                          \
721
                                          int32_t               num_coords,              \
722
                                          const INT_TYPE* const data,                    \
723
                                          const INT_TYPE* const denoised,                \
724
                                          int32_t               stride,                  \
725
                                          const int32_t         sub_log2[2],             \
726
                                          const INT_TYPE* const alt_data,                \
727
                                          const INT_TYPE* const alt_denoised,            \
728
                                          int32_t               alt_stride,              \
729
                                          int32_t               x,                       \
730
                                          int32_t               y,                       \
731
                                          double*               buffer) {                              \
732
        for (int32_t i = 0; i < num_coords; ++i) {                                       \
733
            const int32_t x_i = x + coords[i][0], y_i = y + coords[i][1];                \
734
            buffer[i] = (double)data[y_i * stride + x_i] - denoised[y_i * stride + x_i]; \
735
        }                                                                                \
736
        const double val = (double)data[y * stride + x] - denoised[y * stride + x];      \
737
                                                                                         \
738
        if (alt_data && alt_denoised) {                                                  \
739
            double  avg_data = 0, avg_denoised = 0;                                      \
740
            int32_t num_samples = 0;                                                     \
741
            for (int32_t dy_i = 0; dy_i < (1 << sub_log2[1]); dy_i++) {                  \
742
                const int32_t y_up = (y << sub_log2[1]) + dy_i;                          \
743
                for (int32_t dx_i = 0; dx_i < (1 << sub_log2[0]); dx_i++) {              \
744
                    const int32_t x_up = (x << sub_log2[0]) + dx_i;                      \
745
                    avg_data += alt_data[y_up * alt_stride + x_up];                      \
746
                    avg_denoised += alt_denoised[y_up * alt_stride + x_up];              \
747
                    num_samples++;                                                       \
748
                }                                                                        \
749
            }                                                                            \
750
            assert(num_samples > 0);                                                     \
751
            buffer[num_coords] = (avg_data - avg_denoised) / num_samples;                \
752
        }                                                                                \
753
        return val;                                                                      \
754
    }
755
756
EXTRACT_AR_ROW(uint8_t, lowbd);
757
EXTRACT_AR_ROW(uint16_t, highbd);
758
759
void svt_av1_add_block_observations_internal_c(uint32_t n, const double val, const double recp_sqr_norm, double* buffer,
760
0
                                               double* buffer_norm, double* b, double* A) {
761
0
    uint32_t i;
762
0
    for (i = 0; i + 8 - 1 < n; i += 8) {
763
0
        buffer_norm[i + 0] = buffer[i + 0] * recp_sqr_norm;
764
0
        buffer_norm[i + 1] = buffer[i + 1] * recp_sqr_norm;
765
0
        buffer_norm[i + 2] = buffer[i + 2] * recp_sqr_norm;
766
0
        buffer_norm[i + 3] = buffer[i + 3] * recp_sqr_norm;
767
0
        buffer_norm[i + 4] = buffer[i + 4] * recp_sqr_norm;
768
0
        buffer_norm[i + 5] = buffer[i + 5] * recp_sqr_norm;
769
0
        buffer_norm[i + 6] = buffer[i + 6] * recp_sqr_norm;
770
0
        buffer_norm[i + 7] = buffer[i + 7] * recp_sqr_norm;
771
0
        b[i + 0] += buffer_norm[i + 0] * val;
772
0
        b[i + 1] += buffer_norm[i + 1] * val;
773
0
        b[i + 2] += buffer_norm[i + 2] * val;
774
0
        b[i + 3] += buffer_norm[i + 3] * val;
775
0
        b[i + 4] += buffer_norm[i + 4] * val;
776
0
        b[i + 5] += buffer_norm[i + 5] * val;
777
0
        b[i + 6] += buffer_norm[i + 6] * val;
778
0
        b[i + 7] += buffer_norm[i + 7] * val;
779
0
    }
780
0
    for (; i < n; ++i) {
781
0
        buffer_norm[i] = buffer[i] * recp_sqr_norm;
782
0
        b[i] += buffer_norm[i] * val;
783
0
    }
784
785
0
    for (i = 0; i < n; ++i) {
786
0
        uint32_t     j             = 0;
787
0
        const double buffer_norm_i = buffer_norm[i];
788
789
0
        for (j = 0; j + 8 - 1 < n; j += 8) {
790
0
            A[i * n + j + 0] += (buffer_norm_i * buffer[j + 0]);
791
0
            A[i * n + j + 1] += (buffer_norm_i * buffer[j + 1]);
792
0
            A[i * n + j + 2] += (buffer_norm_i * buffer[j + 2]);
793
0
            A[i * n + j + 3] += (buffer_norm_i * buffer[j + 3]);
794
0
            A[i * n + j + 4] += (buffer_norm_i * buffer[j + 4]);
795
0
            A[i * n + j + 5] += (buffer_norm_i * buffer[j + 5]);
796
0
            A[i * n + j + 6] += (buffer_norm_i * buffer[j + 6]);
797
0
            A[i * n + j + 7] += (buffer_norm_i * buffer[j + 7]);
798
0
        }
799
0
        for (; j < n; ++j) {
800
0
            A[i * n + j] += (buffer_norm_i * buffer[j]);
801
0
        }
802
0
    }
803
0
}
804
805
static int32_t add_block_observations(AomNoiseModel* noise_model, int32_t c, const uint8_t* const data,
806
                                      const uint8_t* const denoised, int32_t w, int32_t h, int32_t stride,
807
                                      int32_t sub_log2[2], const uint8_t* const alt_data,
808
                                      const uint8_t* const alt_denoised, int32_t alt_stride,
809
                                      const uint8_t* const flat_blocks, int32_t block_size, int32_t num_blocks_w,
810
                                      int32_t num_blocks_h) {
811
    const int32_t lag           = noise_model->params.lag;
812
    const int32_t num_coords    = noise_model->n;
813
    const double  normalization = (1 << noise_model->params.bit_depth) - 1;
814
    const double  recp_sqr_norm = 1 / (normalization * normalization);
815
    double*       A             = noise_model->latest_state[c].eqns.A;
816
    double*       b             = noise_model->latest_state[c].eqns.b;
817
    const int32_t n             = noise_model->latest_state[c].eqns.n;
818
    double*       buffer;
819
    double*       buffer_norm;
820
821
    EB_MALLOC_ALIGNED(buffer, sizeof(*buffer) * (num_coords + 1));
822
823
    if (!buffer) {
824
        SVT_ERROR("Unable to allocate buffer of size %d\n", sizeof(*buffer) * (num_coords + 1));
825
        return 0;
826
    }
827
828
    EB_MALLOC_ALIGNED(buffer_norm, sizeof(*buffer_norm) * (n));
829
830
    if (!buffer_norm) {
831
        EB_FREE_ALIGNED(buffer);
832
        SVT_ERROR("Unable to allocate buffer of size %d\n", sizeof(*buffer_norm) * (n));
833
        return 0;
834
    }
835
836
    for (int32_t by = 0; by < num_blocks_h; ++by) {
837
        const int32_t y_o = by * (block_size >> sub_log2[1]);
838
        for (int32_t bx = 0; bx < num_blocks_w; ++bx) {
839
            const int32_t x_o = bx * (block_size >> sub_log2[0]);
840
            if (!flat_blocks[by * num_blocks_w + bx]) {
841
                continue;
842
            }
843
            int32_t y_start = (by > 0 && flat_blocks[(by - 1) * num_blocks_w + bx]) ? 0 : lag;
844
            int32_t x_start = (bx > 0 && flat_blocks[by * num_blocks_w + bx - 1]) ? 0 : lag;
845
            int32_t y_end   = AOMMIN((h >> sub_log2[1]) - by * (block_size >> sub_log2[1]), block_size >> sub_log2[1]);
846
            int32_t x_end   = AOMMIN((w >> sub_log2[0]) - bx * (block_size >> sub_log2[0]) - lag,
847
                                   (bx + 1 < num_blocks_w && flat_blocks[by * num_blocks_w + bx + 1])
848
                                         ? (block_size >> sub_log2[0])
849
                                         : ((block_size >> sub_log2[0]) - lag));
850
            for (int32_t y = y_start; y < y_end; ++y) {
851
                for (int32_t x = x_start; x < x_end; ++x) {
852
                    const double val = noise_model->params.use_highbd
853
                        ? extract_ar_row_highbd(noise_model->coords,
854
                                                num_coords,
855
                                                (const uint16_t* const)data,
856
                                                (const uint16_t* const)denoised,
857
                                                stride,
858
                                                sub_log2,
859
                                                (const uint16_t* const)alt_data,
860
                                                (const uint16_t* const)alt_denoised,
861
                                                alt_stride,
862
                                                x + x_o,
863
                                                y + y_o,
864
                                                buffer)
865
                        : extract_ar_row_lowbd(noise_model->coords,
866
                                               num_coords,
867
                                               data,
868
                                               denoised,
869
                                               stride,
870
                                               sub_log2,
871
                                               alt_data,
872
                                               alt_denoised,
873
                                               alt_stride,
874
                                               x + x_o,
875
                                               y + y_o,
876
                                               buffer);
877
878
                    svt_av1_add_block_observations_internal(n, val, recp_sqr_norm, buffer, buffer_norm, b, A);
879
                }
880
            }
881
            //There is situation when x_start is greater than x_end,
882
            //use max() to cap negative result and do not increment num_observations
883
            noise_model->latest_state[c].num_observations += AOMMAX((y_end - y_start), 0) *
884
                AOMMAX((x_end - x_start), 0);
885
        }
886
    }
887
    EB_FREE_ALIGNED(buffer);
888
    EB_FREE_ALIGNED(buffer_norm);
889
    return 1;
890
}
891
892
static void add_noise_std_observations(AomNoiseModel* noise_model, int32_t c, const double* coeffs,
893
                                       const uint8_t* const data, const uint8_t* const denoised, int32_t w, int32_t h,
894
                                       int32_t stride, const int32_t sub_log2[2], const uint8_t* const alt_data,
895
                                       int32_t alt_stride, const uint8_t* const flat_blocks, int32_t block_size,
896
                                       int32_t num_blocks_w, int32_t num_blocks_h) {
897
    const int32_t           num_coords            = noise_model->n;
898
    AomNoiseStrengthSolver* noise_strength_solver = &noise_model->latest_state[c].strength_solver;
899
900
    const AomNoiseStrengthSolver* noise_strength_luma = &noise_model->latest_state[0].strength_solver;
901
    const double                  luma_gain           = noise_model->latest_state[0].ar_gain;
902
    const double                  noise_gain          = noise_model->latest_state[c].ar_gain;
903
    for (int32_t by = 0; by < num_blocks_h; ++by) {
904
        const int32_t y_o = by * (block_size >> sub_log2[1]);
905
        for (int32_t bx = 0; bx < num_blocks_w; ++bx) {
906
            const int32_t x_o = bx * (block_size >> sub_log2[0]);
907
            if (!flat_blocks[by * num_blocks_w + bx]) {
908
                continue;
909
            }
910
            const int32_t num_samples_h = AOMMIN((h >> sub_log2[1]) - by * (block_size >> sub_log2[1]),
911
                                                 block_size >> sub_log2[1]);
912
            const int32_t num_samples_w = AOMMIN((w >> sub_log2[0]) - bx * (block_size >> sub_log2[0]),
913
                                                 (block_size >> sub_log2[0]));
914
            // Make sure that we have a reasonable amount of samples to consider the
915
            // block
916
            if (num_samples_w * num_samples_h > block_size) {
917
                const double block_mean = get_block_mean(alt_data ? alt_data : data,
918
                                                         w,
919
                                                         h,
920
                                                         alt_data ? alt_stride : stride,
921
                                                         x_o << sub_log2[0],
922
                                                         y_o << sub_log2[1],
923
                                                         block_size,
924
                                                         noise_model->params.use_highbd);
925
                const double noise_var = get_noise_var(data,
926
                                                       denoised,
927
                                                       stride,
928
                                                       w >> sub_log2[0],
929
                                                       h >> sub_log2[1],
930
                                                       x_o,
931
                                                       y_o,
932
                                                       block_size >> sub_log2[0],
933
                                                       block_size >> sub_log2[1],
934
                                                       noise_model->params.use_highbd);
935
                // We want to remove the part of the noise that came from being
936
                // correlated with luma. Note that the noise solver for luma must
937
                // have already been run.
938
                const double luma_strength = c > 0
939
                    ? luma_gain * noise_strength_solver_get_value(noise_strength_luma, block_mean)
940
                    : 0;
941
                const double corr          = c > 0 ? coeffs[num_coords] : 0;
942
                // Chroma noise:
943
                //    N(0, noise_var) = N(0, uncorr_var) + corr * N(0, luma_strength^2)
944
                // The uncorrelated component:
945
                //   uncorr_var = noise_var - (corr * luma_strength)^2
946
                // But don't allow fully correlated noise (hence the max), since the
947
                // synthesis cannot model it.
948
                const double uncorr_std = sqrt(AOMMAX(noise_var / 16, noise_var - pow(corr * luma_strength, 2)));
949
                // After we've removed correlation with luma, undo the gain that will
950
                // come from running the IIR filter.
951
                const double adjusted_strength = uncorr_std / noise_gain;
952
                svt_aom_noise_strength_solver_add_measurement(noise_strength_solver, block_mean, adjusted_strength);
953
            }
954
        }
955
    }
956
}
957
958
static int32_t ar_equation_system_solve(AomNoiseState* state, int32_t is_chroma) {
959
    const int32_t ret = equation_system_solve(&state->eqns);
960
    state->ar_gain    = 1.0;
961
    if (!ret) {
962
        return ret;
963
    }
964
965
    // Update the AR gain from the equation system as it will be used to fit
966
    // the noise strength as a function of intensity.  In the Yule-Walker
967
    // equations, the diagonal should be the variance of the correlated noise.
968
    // In the case of the least squares estimate, there will be some variability
969
    // in the diagonal. So use the mean of the diagonal as the estimate of
970
    // overall variance (this works for least squares or Yule-Walker formulation).
971
    double        var = 0;
972
    const int32_t n   = state->eqns.n;
973
    for (int32_t i = 0; i < (state->eqns.n - is_chroma); ++i) {
974
        var += state->eqns.A[i * n + i] / state->num_observations;
975
    }
976
    var /= (n - is_chroma);
977
978
    // Keep track of E(Y^2) = <b, x> + E(X^2)
979
    // In the case that we are using chroma and have an estimate of correlation
980
    // with luma we adjust that estimate slightly to remove the correlated bits by
981
    // subtracting out the last column of a scaled by our correlation estimate
982
    // from b. E(y^2) = <b - A(:, end)*x(end), x>
983
    double sum_covar = 0;
984
    for (int32_t i = 0; i < state->eqns.n - is_chroma; ++i) {
985
        double bi = state->eqns.b[i];
986
        if (is_chroma) {
987
            bi -= state->eqns.A[i * n + (n - 1)] * state->eqns.x[n - 1];
988
        }
989
        sum_covar += (bi * state->eqns.x[i]) / state->num_observations;
990
    }
991
    // Now, get an estimate of the variance of uncorrelated noise signal and use
992
    // it to determine the gain of the AR filter.
993
    const double noise_var = AOMMAX(var - sum_covar, 1e-6);
994
    state->ar_gain         = AOMMAX(1, sqrt(AOMMAX(var / noise_var, 1e-6)));
995
    return ret;
996
}
997
998
/*!\brief Updates the noise model with a new frame observation.
999
 *
1000
 * Updates the noise model with measurements from the given input frame and a
1001
 * denoised variant of it. Noise is sampled from flat blocks using the flat
1002
 * block map.
1003
 *
1004
 * Returns a noise_status indicating if the update was successful. If the
1005
 * Update was successful, the combined_state is updated with measurements from
1006
 * the provided frame. If status is OK or DIFFERENT_NOISE_TYPE, the latest noise
1007
 * state will be updated with measurements from the provided frame.
1008
 *
1009
 * \param[in,out] noise_model     The noise model to be updated
1010
 * \param[in]     data            Raw frame data
1011
 * \param[in]     denoised        Denoised frame data.
1012
 * \param[in]     w               Frame width
1013
 * \param[in]     h               Frame height
1014
 * \param[in]     strides         Stride of the planes
1015
 * \param[in]     chroma_sub_log2 Chroma subsampling for planes != 0.
1016
 * \param[in]     flat_blocks     A map to blocks that have been determined flat
1017
 * \param[in]     block_size      The size of blocks.
1018
 */
1019
static AomNoiseStatus noise_model_update(AomNoiseModel* const noise_model, const uint8_t* const data[3],
1020
                                         const uint8_t* const denoised[3], int32_t w, int32_t h,
1021
                                         const int32_t stride[3], int32_t chroma_sub_log2[2],
1022
0
                                         const uint8_t* const flat_blocks, int32_t block_size) {
1023
0
    const int32_t num_blocks_w = (w + block_size - 1) / block_size;
1024
0
    const int32_t num_blocks_h = (h + block_size - 1) / block_size;
1025
    //  int32_t y_model_different = 0;
1026
0
    int32_t num_blocks = 0;
1027
0
    int32_t i = 0, channel = 0;
1028
1029
0
    if (block_size <= 1) {
1030
0
        SVT_ERROR("BlockSize = %d must be > 1\n", block_size);
1031
0
        return AOM_NOISE_STATUS_INVALID_ARGUMENT;
1032
0
    }
1033
1034
0
    if (block_size < noise_model->params.lag * 2 + 1) {
1035
0
        SVT_ERROR("BlockSize = %d must be >= %d\n", block_size, noise_model->params.lag * 2 + 1);
1036
0
        return AOM_NOISE_STATUS_INVALID_ARGUMENT;
1037
0
    }
1038
1039
    // Clear the latest equation system
1040
0
    for (i = 0; i < 3; ++i) {
1041
0
        equation_system_clear(&noise_model->latest_state[i].eqns);
1042
0
        noise_model->latest_state[i].num_observations = 0;
1043
0
        noise_strength_solver_clear(&noise_model->latest_state[i].strength_solver);
1044
0
    }
1045
1046
    // Check that we have enough flat blocks
1047
0
    for (i = 0; i < num_blocks_h * num_blocks_w; ++i) {
1048
0
        if (flat_blocks[i]) {
1049
0
            num_blocks++;
1050
0
        }
1051
0
    }
1052
1053
0
    if (num_blocks <= 1) {
1054
0
        SVT_ERROR("Not enough flat blocks to update noise estimate\n");
1055
0
        return AOM_NOISE_STATUS_INSUFFICIENT_FLAT_BLOCKS;
1056
0
    }
1057
1058
0
    for (channel = 0; channel < 3; ++channel) {
1059
0
        int32_t        no_subsampling[2] = {0, 0};
1060
0
        const uint8_t* alt_data          = channel > 0 ? data[0] : 0;
1061
0
        const uint8_t* alt_denoised      = channel > 0 ? denoised[0] : 0;
1062
0
        int32_t*       sub               = channel > 0 ? chroma_sub_log2 : no_subsampling;
1063
0
        const int32_t  is_chroma         = channel != 0;
1064
0
        if (!data[channel] || !denoised[channel]) {
1065
0
            break;
1066
0
        }
1067
0
        if (!add_block_observations(noise_model,
1068
0
                                    channel,
1069
0
                                    data[channel],
1070
0
                                    denoised[channel],
1071
0
                                    w,
1072
0
                                    h,
1073
0
                                    stride[channel],
1074
0
                                    sub,
1075
0
                                    alt_data,
1076
0
                                    alt_denoised,
1077
0
                                    stride[0],
1078
0
                                    flat_blocks,
1079
0
                                    block_size,
1080
0
                                    num_blocks_w,
1081
0
                                    num_blocks_h)) {
1082
0
            SVT_ERROR("Adding block observation failed\n");
1083
0
            return AOM_NOISE_STATUS_INTERNAL_ERROR;
1084
0
        }
1085
1086
0
        if (!ar_equation_system_solve(&noise_model->latest_state[channel], is_chroma)) {
1087
0
            if (is_chroma) {
1088
0
                set_chroma_coefficient_fallback_soln(&noise_model->latest_state[channel].eqns);
1089
0
            } else {
1090
                //SVT_INFO("Solving latest noise equation system failed %d!\n", channel);
1091
0
                return AOM_NOISE_STATUS_INSUFFICIENT_NOISE_PIXELS;
1092
0
            }
1093
0
        }
1094
1095
0
        add_noise_std_observations(noise_model,
1096
0
                                   channel,
1097
0
                                   noise_model->latest_state[channel].eqns.x,
1098
0
                                   data[channel],
1099
0
                                   denoised[channel],
1100
0
                                   w,
1101
0
                                   h,
1102
0
                                   stride[channel],
1103
0
                                   sub,
1104
0
                                   alt_data,
1105
0
                                   stride[0],
1106
0
                                   flat_blocks,
1107
0
                                   block_size,
1108
0
                                   num_blocks_w,
1109
0
                                   num_blocks_h);
1110
1111
0
        if (!svt_aom_noise_strength_solver_solve(&noise_model->latest_state[channel].strength_solver)) {
1112
0
            SVT_ERROR("Solving latest noise strength failed!\n");
1113
0
            return AOM_NOISE_STATUS_INTERNAL_ERROR;
1114
0
        }
1115
1116
        // Check noise characteristics and return if error.
1117
        //    if (channel == 0 &&
1118
        //        noise_model->combined_state[channel].strength_solver.num_equations >
1119
        //            0 &&
1120
        //        is_noise_model_different(noise_model)) {
1121
        //      y_model_different = 1;
1122
        //    }
1123
1124
0
        noise_model->combined_state[channel].num_observations = noise_model->latest_state[channel].num_observations;
1125
0
        equation_system_copy(&noise_model->combined_state[channel].eqns, &noise_model->latest_state[channel].eqns);
1126
0
        if (!ar_equation_system_solve(&noise_model->combined_state[channel], is_chroma)) {
1127
0
            if (is_chroma) {
1128
0
                set_chroma_coefficient_fallback_soln(&noise_model->combined_state[channel].eqns);
1129
0
            } else {
1130
0
                SVT_ERROR("Solving combined noise equation system failed %d!\n", channel);
1131
0
                return AOM_NOISE_STATUS_INTERNAL_ERROR;
1132
0
            }
1133
0
        }
1134
1135
0
        noise_strength_solver_copy(&noise_model->combined_state[channel].strength_solver,
1136
0
                                   &noise_model->latest_state[channel].strength_solver);
1137
1138
0
        if (!svt_aom_noise_strength_solver_solve(&noise_model->combined_state[channel].strength_solver)) {
1139
0
            SVT_ERROR("Solving combined noise strength failed!\n");
1140
0
            return AOM_NOISE_STATUS_INTERNAL_ERROR;
1141
0
        }
1142
0
    }
1143
1144
0
    return AOM_NOISE_STATUS_OK;
1145
0
}
1146
1147
0
void svt_aom_noise_model_save_latest(AomNoiseModel* noise_model) {
1148
0
    for (int32_t c = 0; c < 3; c++) {
1149
0
        equation_system_copy(&noise_model->combined_state[c].eqns, &noise_model->latest_state[c].eqns);
1150
0
        equation_system_copy(&noise_model->combined_state[c].strength_solver.eqns,
1151
0
                             &noise_model->latest_state[c].strength_solver.eqns);
1152
0
        noise_model->combined_state[c].strength_solver.num_equations =
1153
0
            noise_model->latest_state[c].strength_solver.num_equations;
1154
0
        noise_model->combined_state[c].num_observations = noise_model->latest_state[c].num_observations;
1155
0
        noise_model->combined_state[c].ar_gain          = noise_model->latest_state[c].ar_gain;
1156
0
    }
1157
0
}
1158
1159
0
int32_t svt_aom_noise_model_get_grain_parameters(AomNoiseModel* const noise_model, AomFilmGrain* film_grain) {
1160
0
    if (noise_model->params.lag > 3) {
1161
0
        SVT_ERROR("params.lag = %d > 3\n", noise_model->params.lag);
1162
0
        return 0;
1163
0
    }
1164
0
    uint16_t random_seed = film_grain->random_seed;
1165
0
    memset(film_grain, 0, sizeof(*film_grain));
1166
0
    film_grain->random_seed = random_seed;
1167
1168
0
    film_grain->apply_grain       = 1;
1169
0
    film_grain->update_parameters = 1;
1170
0
    film_grain->ignore_ref        = 0;
1171
1172
0
    film_grain->ar_coeff_lag = noise_model->params.lag;
1173
1174
    // Convert the scaling functions to 8 bit values
1175
0
    AomNoiseStrengthLut scaling_points[3] = {{.points = NULL, .num_points = 0}};
1176
0
    svt_aom_noise_strength_solver_fit_piecewise(
1177
0
        &noise_model->combined_state[0].strength_solver, 14, scaling_points + 0);
1178
0
    svt_aom_noise_strength_solver_fit_piecewise(
1179
0
        &noise_model->combined_state[1].strength_solver, 10, scaling_points + 1);
1180
0
    svt_aom_noise_strength_solver_fit_piecewise(
1181
0
        &noise_model->combined_state[2].strength_solver, 10, scaling_points + 2);
1182
1183
    // Both the domain and the range of the scaling functions in the film_grain
1184
    // are normalized to 8-bit (e.g., they are implicitly scaled during grain
1185
    // synthesis).
1186
0
    const double strength_divisor  = 1 << (noise_model->params.bit_depth - 8);
1187
0
    double       max_scaling_value = 1e-4;
1188
0
    for (int32_t c = 0; c < 3; ++c) {
1189
0
        for (int32_t i = 0; i < scaling_points[c].num_points; ++i) {
1190
0
            scaling_points[c].points[i][0] = AOMMIN(255, scaling_points[c].points[i][0] / strength_divisor);
1191
0
            scaling_points[c].points[i][1] = AOMMIN(255, scaling_points[c].points[i][1] / strength_divisor);
1192
0
            max_scaling_value              = AOMMAX(scaling_points[c].points[i][1], max_scaling_value);
1193
0
        }
1194
0
    }
1195
1196
    // Scaling_shift values are in the range [8,11]
1197
0
    const int32_t max_scaling_value_log2 = clamp((int32_t)floor(log2(max_scaling_value) + 1), 2, 5);
1198
0
    film_grain->scaling_shift            = 5 + (8 - max_scaling_value_log2);
1199
1200
0
    const double scale_factor = 1 << (8 - max_scaling_value_log2);
1201
0
    film_grain->num_y_points  = scaling_points[0].num_points;
1202
0
    film_grain->num_cb_points = scaling_points[1].num_points;
1203
0
    film_grain->num_cr_points = scaling_points[2].num_points;
1204
1205
0
    int32_t (*film_grain_scaling[3])[2] = {
1206
0
        film_grain->scaling_points_y,
1207
0
        film_grain->scaling_points_cb,
1208
0
        film_grain->scaling_points_cr,
1209
0
    };
1210
0
    for (int32_t c = 0; c < 3; c++) {
1211
0
        for (int32_t i = 0; i < scaling_points[c].num_points; ++i) {
1212
0
            film_grain_scaling[c][i][0] = (int32_t)(scaling_points[c].points[i][0] + 0.5);
1213
0
            film_grain_scaling[c][i][1] = clamp((int32_t)(scale_factor * scaling_points[c].points[i][1] + 0.5), 0, 255);
1214
0
        }
1215
0
    }
1216
0
    svt_aom_noise_strength_lut_free(scaling_points + 0);
1217
0
    svt_aom_noise_strength_lut_free(scaling_points + 1);
1218
0
    svt_aom_noise_strength_lut_free(scaling_points + 2);
1219
1220
    // Convert the ar_coeffs into 8-bit values
1221
0
    const int32_t n_coeff   = noise_model->combined_state[0].eqns.n;
1222
0
    double        max_coeff = 1e-4, min_coeff = -1e-4;
1223
0
    double        y_corr[2]         = {0, 0};
1224
0
    double        avg_luma_strength = 0;
1225
0
    for (int32_t c = 0; c < 3; c++) {
1226
0
        AomEquationSystem* eqns = &noise_model->combined_state[c].eqns;
1227
0
        for (int32_t i = 0; i < n_coeff; ++i) {
1228
0
            max_coeff = AOMMAX(max_coeff, eqns->x[i]);
1229
0
            min_coeff = AOMMIN(min_coeff, eqns->x[i]);
1230
0
        }
1231
        // Since the correlation between luma/chroma was computed in an already
1232
        // scaled space, we adjust it in the un-scaled space.
1233
0
        AomNoiseStrengthSolver* solver = &noise_model->combined_state[c].strength_solver;
1234
        // Compute a weighted average of the strength for the channel.
1235
0
        double average_strength = 0, total_weight = 0;
1236
0
        for (int32_t i = 0; i < solver->eqns.n; ++i) {
1237
0
            double w = 0;
1238
0
            for (int32_t j = 0; j < solver->eqns.n; ++j) {
1239
0
                w += solver->eqns.A[i * solver->eqns.n + j];
1240
0
            }
1241
0
            w = sqrt(w);
1242
0
            average_strength += solver->eqns.x[i] * w;
1243
0
            total_weight += w;
1244
0
        }
1245
0
        if (total_weight == 0) {
1246
0
            average_strength = 1;
1247
0
        } else {
1248
0
            average_strength /= total_weight;
1249
0
        }
1250
0
        if (c == 0) {
1251
0
            avg_luma_strength = average_strength;
1252
0
        } else {
1253
0
            y_corr[c - 1] = avg_luma_strength * eqns->x[n_coeff] / average_strength;
1254
0
            max_coeff     = AOMMAX(max_coeff, y_corr[c - 1]);
1255
0
            min_coeff     = AOMMIN(min_coeff, y_corr[c - 1]);
1256
0
        }
1257
0
    }
1258
    // Shift value: AR coeffs range (values 6-9)
1259
    // 6: [-2, 2),  7: [-1, 1), 8: [-0.5, 0.5), 9: [-0.25, 0.25)
1260
0
    film_grain->ar_coeff_shift = clamp(7 - (int32_t)AOMMAX(1 + floor(log2(max_coeff)), ceil(log2(-min_coeff))), 6, 9);
1261
0
    double   scale_ar_coeff    = 1 << film_grain->ar_coeff_shift;
1262
0
    int32_t* ar_coeffs[3]      = {
1263
0
        film_grain->ar_coeffs_y,
1264
0
        film_grain->ar_coeffs_cb,
1265
0
        film_grain->ar_coeffs_cr,
1266
0
    };
1267
0
    for (int32_t c = 0; c < 3; ++c) {
1268
0
        AomEquationSystem* eqns = &noise_model->combined_state[c].eqns;
1269
0
        for (int32_t i = 0; i < n_coeff; ++i) {
1270
0
            ar_coeffs[c][i] = clamp((int32_t)round(scale_ar_coeff * eqns->x[i]), -128, 127);
1271
0
        }
1272
0
        if (c > 0) {
1273
0
            ar_coeffs[c][n_coeff] = clamp((int32_t)round(scale_ar_coeff * y_corr[c - 1]), -128, 127);
1274
0
        }
1275
0
    }
1276
1277
    // At the moment, the noise modeling code assumes that the chroma scaling
1278
    // functions are a function of luma.
1279
0
    film_grain->cb_mult      = 128; // 8 bits
1280
0
    film_grain->cb_luma_mult = 192; // 8 bits
1281
0
    film_grain->cb_offset    = 256; // 9 bits
1282
1283
0
    film_grain->cr_mult      = 128; // 8 bits
1284
0
    film_grain->cr_luma_mult = 192; // 8 bits
1285
0
    film_grain->cr_offset    = 256; // 9 bits
1286
1287
0
    film_grain->chroma_scaling_from_luma = 0;
1288
0
    film_grain->grain_scale_shift        = 0;
1289
0
    film_grain->overlap_flag             = 1;
1290
0
    return 1;
1291
0
}
1292
1293
0
void svt_av1_pointwise_multiply_c(const float* a, float* b, float* c, double* b_d, double* c_d, int32_t n) {
1294
0
    for (int32_t i = 0; i < n; i++) {
1295
0
        b[i] = a[i] * (float)b_d[i];
1296
0
        c[i] = a[i] * (float)c_d[i];
1297
0
    }
1298
0
}
1299
1300
//window_function[y * block_size + x] = (float)(cos((.5 + y) * PI / block_size - PI / 2) * cos((.5 + x) * PI / block_size - PI / 2));
1301
static const float window_function_half_cos_window_2[4] = {
1302
    0.500000f,
1303
    0.500000f,
1304
    0.500000f,
1305
    0.500000f,
1306
};
1307
static const float window_function_half_cos_window_4[16] = {
1308
    0.14644662f,
1309
    0.35355338f,
1310
    0.35355338f,
1311
    0.14644662f,
1312
    0.35355338f,
1313
    0.85355341f,
1314
    0.85355341f,
1315
    0.35355338f,
1316
    0.35355338f,
1317
    0.85355341f,
1318
    0.85355341f,
1319
    0.35355338f,
1320
    0.14644662f,
1321
    0.35355338f,
1322
    0.35355338f,
1323
    0.14644662f,
1324
};
1325
static const float window_function_half_cos_window_8[64] = {
1326
    0.03806023f, 0.10838638f, 0.16221167f, 0.19134171f, 0.19134171f, 0.16221167f, 0.10838638f, 0.03806023f,
1327
    0.10838638f, 0.30865827f, 0.46193975f, 0.54489511f, 0.54489511f, 0.46193975f, 0.30865827f, 0.10838638f,
1328
    0.16221167f, 0.46193975f, 0.69134170f, 0.81549317f, 0.81549317f, 0.69134170f, 0.46193975f, 0.16221167f,
1329
    0.19134171f, 0.54489511f, 0.81549317f, 0.96193975f, 0.96193975f, 0.81549317f, 0.54489511f, 0.19134171f,
1330
    0.19134171f, 0.54489511f, 0.81549317f, 0.96193975f, 0.96193975f, 0.81549317f, 0.54489511f, 0.19134171f,
1331
    0.16221167f, 0.46193975f, 0.69134170f, 0.81549317f, 0.81549317f, 0.69134170f, 0.46193975f, 0.16221167f,
1332
    0.10838638f, 0.30865827f, 0.46193975f, 0.54489511f, 0.54489511f, 0.46193975f, 0.30865827f, 0.10838638f,
1333
    0.03806023f, 0.10838638f, 0.16221167f, 0.19134171f, 0.19134171f, 0.16221167f, 0.10838638f, 0.03806023f,
1334
};
1335
static const float window_function_half_cos_window_16[256] = {
1336
    0.00960736f, 0.02845287f, 0.04620496f, 0.06218142f, 0.07576828f, 0.08644340f, 0.09379656f, 0.09754516f, 0.09754516f,
1337
    0.09379656f, 0.08644340f, 0.07576828f, 0.06218142f, 0.04620496f, 0.02845287f, 0.00960736f, 0.02845287f, 0.08426519f,
1338
    0.13683926f, 0.18415464f, 0.22439308f, 0.25600824f, 0.27778512f, 0.28888687f, 0.28888687f, 0.27778512f, 0.25600824f,
1339
    0.22439308f, 0.18415464f, 0.13683926f, 0.08426519f, 0.02845287f, 0.04620496f, 0.13683926f, 0.22221488f, 0.29905093f,
1340
    0.36439461f, 0.41573480f, 0.45109856f, 0.46912682f, 0.46912682f, 0.45109856f, 0.41573480f, 0.36439461f, 0.29905093f,
1341
    0.22221488f, 0.13683926f, 0.04620496f, 0.06218142f, 0.18415464f, 0.29905093f, 0.40245485f, 0.49039263f, 0.55948490f,
1342
    0.60707653f, 0.63133854f, 0.63133854f, 0.60707653f, 0.55948490f, 0.49039263f, 0.40245485f, 0.29905093f, 0.18415464f,
1343
    0.06218142f, 0.07576828f, 0.22439308f, 0.36439461f, 0.49039263f, 0.59754515f, 0.68173438f, 0.73972487f, 0.76928818f,
1344
    0.76928818f, 0.73972487f, 0.68173438f, 0.59754515f, 0.49039263f, 0.36439461f, 0.22439308f, 0.07576828f, 0.08644340f,
1345
    0.25600824f, 0.41573480f, 0.55948490f, 0.68173438f, 0.77778512f, 0.84394604f, 0.87767458f, 0.87767458f, 0.84394604f,
1346
    0.77778512f, 0.68173438f, 0.55948490f, 0.41573480f, 0.25600824f, 0.08644340f, 0.09379656f, 0.27778512f, 0.45109856f,
1347
    0.60707653f, 0.73972487f, 0.84394604f, 0.91573483f, 0.95233238f, 0.95233238f, 0.91573483f, 0.84394604f, 0.73972487f,
1348
    0.60707653f, 0.45109856f, 0.27778512f, 0.09379656f, 0.09754516f, 0.28888687f, 0.46912682f, 0.63133854f, 0.76928818f,
1349
    0.87767458f, 0.95233238f, 0.99039263f, 0.99039263f, 0.95233238f, 0.87767458f, 0.76928818f, 0.63133854f, 0.46912682f,
1350
    0.28888687f, 0.09754516f, 0.09754516f, 0.28888687f, 0.46912682f, 0.63133854f, 0.76928818f, 0.87767458f, 0.95233238f,
1351
    0.99039263f, 0.99039263f, 0.95233238f, 0.87767458f, 0.76928818f, 0.63133854f, 0.46912682f, 0.28888687f, 0.09754516f,
1352
    0.09379656f, 0.27778512f, 0.45109856f, 0.60707653f, 0.73972487f, 0.84394604f, 0.91573483f, 0.95233238f, 0.95233238f,
1353
    0.91573483f, 0.84394604f, 0.73972487f, 0.60707653f, 0.45109856f, 0.27778512f, 0.09379656f, 0.08644340f, 0.25600824f,
1354
    0.41573480f, 0.55948490f, 0.68173438f, 0.77778512f, 0.84394604f, 0.87767458f, 0.87767458f, 0.84394604f, 0.77778512f,
1355
    0.68173438f, 0.55948490f, 0.41573480f, 0.25600824f, 0.08644340f, 0.07576828f, 0.22439308f, 0.36439461f, 0.49039263f,
1356
    0.59754515f, 0.68173438f, 0.73972487f, 0.76928818f, 0.76928818f, 0.73972487f, 0.68173438f, 0.59754515f, 0.49039263f,
1357
    0.36439461f, 0.22439308f, 0.07576828f, 0.06218142f, 0.18415464f, 0.29905093f, 0.40245485f, 0.49039263f, 0.55948490f,
1358
    0.60707653f, 0.63133854f, 0.63133854f, 0.60707653f, 0.55948490f, 0.49039263f, 0.40245485f, 0.29905093f, 0.18415464f,
1359
    0.06218142f, 0.04620496f, 0.13683926f, 0.22221488f, 0.29905093f, 0.36439461f, 0.41573480f, 0.45109856f, 0.46912682f,
1360
    0.46912682f, 0.45109856f, 0.41573480f, 0.36439461f, 0.29905093f, 0.22221488f, 0.13683926f, 0.04620496f, 0.02845287f,
1361
    0.08426519f, 0.13683926f, 0.18415464f, 0.22439308f, 0.25600824f, 0.27778512f, 0.28888687f, 0.28888687f, 0.27778512f,
1362
    0.25600824f, 0.22439308f, 0.18415464f, 0.13683926f, 0.08426519f, 0.02845287f, 0.00960736f, 0.02845287f, 0.04620496f,
1363
    0.06218142f, 0.07576828f, 0.08644340f, 0.09379656f, 0.09754516f, 0.09754516f, 0.09379656f, 0.08644340f, 0.07576828f,
1364
    0.06218142f, 0.04620496f, 0.02845287f, 0.00960736f,
1365
};
1366
static const float window_function_half_cos_window_32[1024] = {
1367
    0.00240764f, 0.00719972f, 0.01192247f, 0.01653040f, 0.02097913f, 0.02522583f, 0.02922958f, 0.03295184f, 0.03635675f,
1368
    0.03941153f, 0.04208675f, 0.04435665f, 0.04619938f, 0.04759718f, 0.04853659f, 0.04900857f, 0.04900857f, 0.04853659f,
1369
    0.04759718f, 0.04619938f, 0.04435665f, 0.04208675f, 0.03941153f, 0.03635675f, 0.03295184f, 0.02922958f, 0.02522583f,
1370
    0.02097913f, 0.01653040f, 0.01192247f, 0.00719972f, 0.00240764f, 0.00719972f, 0.02152983f, 0.03565260f, 0.04943201f,
1371
    0.06273536f, 0.07543454f, 0.08740724f, 0.09853817f, 0.10872011f, 0.11785502f, 0.12585492f, 0.13264278f, 0.13815321f,
1372
    0.14233315f, 0.14514233f, 0.14655373f, 0.14655373f, 0.14514233f, 0.14233315f, 0.13815321f, 0.13264278f, 0.12585492f,
1373
    0.11785502f, 0.10872011f, 0.09853817f, 0.08740724f, 0.07543454f, 0.06273536f, 0.04943201f, 0.03565260f, 0.02152983f,
1374
    0.00719972f, 0.01192247f, 0.03565260f, 0.05903937f, 0.08185755f, 0.10388742f, 0.12491678f, 0.14474313f, 0.16317551f,
1375
    0.18003644f, 0.19516350f, 0.20841105f, 0.21965148f, 0.22877654f, 0.23569837f, 0.24035029f, 0.24268749f, 0.24268749f,
1376
    0.24035029f, 0.23569837f, 0.22877654f, 0.21965148f, 0.20841105f, 0.19516350f, 0.18003644f, 0.16317551f, 0.14474313f,
1377
    0.12491678f, 0.10388742f, 0.08185755f, 0.05903937f, 0.03565260f, 0.01192247f, 0.01653040f, 0.04943201f, 0.08185755f,
1378
    0.11349478f, 0.14403898f, 0.17319600f, 0.20068505f, 0.22624139f, 0.24961892f, 0.27059248f, 0.28896007f, 0.30454481f,
1379
    0.31719664f, 0.32679370f, 0.33324352f, 0.33648404f, 0.33648404f, 0.33324352f, 0.32679370f, 0.31719664f, 0.30454481f,
1380
    0.28896007f, 0.27059248f, 0.24961892f, 0.22624139f, 0.20068505f, 0.17319600f, 0.14403898f, 0.11349478f, 0.08185755f,
1381
    0.04943201f, 0.01653040f, 0.02097913f, 0.06273536f, 0.10388742f, 0.14403898f, 0.18280336f, 0.21980725f, 0.25469428f,
1382
    0.28712845f, 0.31679744f, 0.34341547f, 0.36672625f, 0.38650522f, 0.40256196f, 0.41474181f, 0.42292747f, 0.42704007f,
1383
    0.42704007f, 0.42292747f, 0.41474181f, 0.40256196f, 0.38650522f, 0.36672625f, 0.34341547f, 0.31679744f, 0.28712845f,
1384
    0.25469428f, 0.21980725f, 0.18280336f, 0.14403898f, 0.10388742f, 0.06273536f, 0.02097913f, 0.02522583f, 0.07543454f,
1385
    0.12491678f, 0.17319600f, 0.21980725f, 0.26430163f, 0.30625066f, 0.34525031f, 0.38092500f, 0.41293120f, 0.44096065f,
1386
    0.46474338f, 0.48405039f, 0.49869573f, 0.50853837f, 0.51348346f, 0.51348346f, 0.50853837f, 0.49869573f, 0.48405039f,
1387
    0.46474338f, 0.44096065f, 0.41293120f, 0.38092500f, 0.34525031f, 0.30625066f, 0.26430163f, 0.21980725f, 0.17319600f,
1388
    0.12491678f, 0.07543454f, 0.02522583f, 0.02922958f, 0.08740724f, 0.14474313f, 0.20068505f, 0.25469428f, 0.30625066f,
1389
    0.35485765f, 0.40004721f, 0.44138408f, 0.47847018f, 0.51094836f, 0.53850579f, 0.56087714f, 0.57784694f, 0.58925176f,
1390
    0.59498173f, 0.59498173f, 0.58925176f, 0.57784694f, 0.56087714f, 0.53850579f, 0.51094836f, 0.47847018f, 0.44138408f,
1391
    0.40004721f, 0.35485765f, 0.30625066f, 0.25469428f, 0.20068505f, 0.14474313f, 0.08740724f, 0.02922958f, 0.03295184f,
1392
    0.09853817f, 0.16317551f, 0.22624139f, 0.28712845f, 0.34525031f, 0.40004721f, 0.45099142f, 0.49759236f, 0.53940123f,
1393
    0.57601535f, 0.60708213f, 0.63230234f, 0.65143317f, 0.66429037f, 0.67075002f, 0.67075002f, 0.66429037f, 0.65143317f,
1394
    0.63230234f, 0.60708213f, 0.57601535f, 0.53940123f, 0.49759236f, 0.45099142f, 0.40004721f, 0.34525031f, 0.28712845f,
1395
    0.22624139f, 0.16317551f, 0.09853817f, 0.03295184f, 0.03635675f, 0.10872011f, 0.18003644f, 0.24961892f, 0.31679744f,
1396
    0.38092500f, 0.44138408f, 0.49759236f, 0.54900855f, 0.59513754f, 0.63553500f, 0.66981190f, 0.69763815f, 0.71874577f,
1397
    0.73293144f, 0.74005860f, 0.74005860f, 0.73293144f, 0.71874577f, 0.69763815f, 0.66981190f, 0.63553500f, 0.59513754f,
1398
    0.54900855f, 0.49759236f, 0.44138408f, 0.38092500f, 0.31679744f, 0.24961892f, 0.18003644f, 0.10872011f, 0.03635675f,
1399
    0.03941153f, 0.11785502f, 0.19516350f, 0.27059248f, 0.34341547f, 0.41293120f, 0.47847018f, 0.53940123f, 0.59513754f,
1400
    0.64514232f, 0.68893409f, 0.72609103f, 0.75625527f, 0.77913642f, 0.79451400f, 0.80224001f, 0.80224001f, 0.79451400f,
1401
    0.77913642f, 0.75625527f, 0.72609103f, 0.68893409f, 0.64514232f, 0.59513754f, 0.53940123f, 0.47847018f, 0.41293120f,
1402
    0.34341547f, 0.27059248f, 0.19516350f, 0.11785502f, 0.03941153f, 0.04208675f, 0.12585492f, 0.20841105f, 0.28896007f,
1403
    0.36672625f, 0.44096065f, 0.51094836f, 0.57601535f, 0.63553500f, 0.68893409f, 0.73569834f, 0.77537745f, 0.80758929f,
1404
    0.83202356f, 0.84844500f, 0.85669541f, 0.85669541f, 0.84844500f, 0.83202356f, 0.80758929f, 0.77537745f, 0.73569834f,
1405
    0.68893409f, 0.63553500f, 0.57601535f, 0.51094836f, 0.44096065f, 0.36672625f, 0.28896007f, 0.20841105f, 0.12585492f,
1406
    0.04208675f, 0.04435665f, 0.13264278f, 0.21965148f, 0.30454481f, 0.38650522f, 0.46474338f, 0.53850579f, 0.60708213f,
1407
    0.66981190f, 0.72609103f, 0.77537745f, 0.81719667f, 0.85114574f, 0.87689787f, 0.89420497f, 0.90290040f, 0.90290040f,
1408
    0.89420497f, 0.87689787f, 0.85114574f, 0.81719667f, 0.77537745f, 0.72609103f, 0.66981190f, 0.60708213f, 0.53850579f,
1409
    0.46474338f, 0.38650522f, 0.30454481f, 0.21965148f, 0.13264278f, 0.04435665f, 0.04619938f, 0.13815321f, 0.22877654f,
1410
    0.31719664f, 0.40256196f, 0.48405039f, 0.56087714f, 0.63230234f, 0.69763815f, 0.75625527f, 0.80758929f, 0.85114574f,
1411
    0.88650525f, 0.91332716f, 0.93135327f, 0.94040996f, 0.94040996f, 0.93135327f, 0.91332716f, 0.88650525f, 0.85114574f,
1412
    0.80758929f, 0.75625527f, 0.69763815f, 0.63230234f, 0.56087714f, 0.48405039f, 0.40256196f, 0.31719664f, 0.22877654f,
1413
    0.13815321f, 0.04619938f, 0.04759718f, 0.14233315f, 0.23569837f, 0.32679370f, 0.41474181f, 0.49869573f, 0.57784694f,
1414
    0.65143317f, 0.71874577f, 0.77913642f, 0.83202356f, 0.87689787f, 0.91332716f, 0.94096065f, 0.95953214f, 0.96886283f,
1415
    0.96886283f, 0.95953214f, 0.94096065f, 0.91332716f, 0.87689787f, 0.83202356f, 0.77913642f, 0.71874577f, 0.65143317f,
1416
    0.57784694f, 0.49869573f, 0.41474181f, 0.32679370f, 0.23569837f, 0.14233315f, 0.04759718f, 0.04853659f, 0.14514233f,
1417
    0.24035029f, 0.33324352f, 0.42292747f, 0.50853837f, 0.58925176f, 0.66429037f, 0.73293144f, 0.79451400f, 0.84844500f,
1418
    0.89420497f, 0.93135327f, 0.95953214f, 0.97847015f, 0.98798501f, 0.98798501f, 0.97847015f, 0.95953214f, 0.93135327f,
1419
    0.89420497f, 0.84844500f, 0.79451400f, 0.73293144f, 0.66429037f, 0.58925176f, 0.50853837f, 0.42292747f, 0.33324352f,
1420
    0.24035029f, 0.14514233f, 0.04853659f, 0.04900857f, 0.14655373f, 0.24268749f, 0.33648404f, 0.42704007f, 0.51348346f,
1421
    0.59498173f, 0.67075002f, 0.74005860f, 0.80224001f, 0.85669541f, 0.90290040f, 0.94040996f, 0.96886283f, 0.98798501f,
1422
    0.99759239f, 0.99759239f, 0.98798501f, 0.96886283f, 0.94040996f, 0.90290040f, 0.85669541f, 0.80224001f, 0.74005860f,
1423
    0.67075002f, 0.59498173f, 0.51348346f, 0.42704007f, 0.33648404f, 0.24268749f, 0.14655373f, 0.04900857f, 0.04900857f,
1424
    0.14655373f, 0.24268749f, 0.33648404f, 0.42704007f, 0.51348346f, 0.59498173f, 0.67075002f, 0.74005860f, 0.80224001f,
1425
    0.85669541f, 0.90290040f, 0.94040996f, 0.96886283f, 0.98798501f, 0.99759239f, 0.99759239f, 0.98798501f, 0.96886283f,
1426
    0.94040996f, 0.90290040f, 0.85669541f, 0.80224001f, 0.74005860f, 0.67075002f, 0.59498173f, 0.51348346f, 0.42704007f,
1427
    0.33648404f, 0.24268749f, 0.14655373f, 0.04900857f, 0.04853659f, 0.14514233f, 0.24035029f, 0.33324352f, 0.42292747f,
1428
    0.50853837f, 0.58925176f, 0.66429037f, 0.73293144f, 0.79451400f, 0.84844500f, 0.89420497f, 0.93135327f, 0.95953214f,
1429
    0.97847015f, 0.98798501f, 0.98798501f, 0.97847015f, 0.95953214f, 0.93135327f, 0.89420497f, 0.84844500f, 0.79451400f,
1430
    0.73293144f, 0.66429037f, 0.58925176f, 0.50853837f, 0.42292747f, 0.33324352f, 0.24035029f, 0.14514233f, 0.04853659f,
1431
    0.04759718f, 0.14233315f, 0.23569837f, 0.32679370f, 0.41474181f, 0.49869573f, 0.57784694f, 0.65143317f, 0.71874577f,
1432
    0.77913642f, 0.83202356f, 0.87689787f, 0.91332716f, 0.94096065f, 0.95953214f, 0.96886283f, 0.96886283f, 0.95953214f,
1433
    0.94096065f, 0.91332716f, 0.87689787f, 0.83202356f, 0.77913642f, 0.71874577f, 0.65143317f, 0.57784694f, 0.49869573f,
1434
    0.41474181f, 0.32679370f, 0.23569837f, 0.14233315f, 0.04759718f, 0.04619938f, 0.13815321f, 0.22877654f, 0.31719664f,
1435
    0.40256196f, 0.48405039f, 0.56087714f, 0.63230234f, 0.69763815f, 0.75625527f, 0.80758929f, 0.85114574f, 0.88650525f,
1436
    0.91332716f, 0.93135327f, 0.94040996f, 0.94040996f, 0.93135327f, 0.91332716f, 0.88650525f, 0.85114574f, 0.80758929f,
1437
    0.75625527f, 0.69763815f, 0.63230234f, 0.56087714f, 0.48405039f, 0.40256196f, 0.31719664f, 0.22877654f, 0.13815321f,
1438
    0.04619938f, 0.04435665f, 0.13264278f, 0.21965148f, 0.30454481f, 0.38650522f, 0.46474338f, 0.53850579f, 0.60708213f,
1439
    0.66981190f, 0.72609103f, 0.77537745f, 0.81719667f, 0.85114574f, 0.87689787f, 0.89420497f, 0.90290040f, 0.90290040f,
1440
    0.89420497f, 0.87689787f, 0.85114574f, 0.81719667f, 0.77537745f, 0.72609103f, 0.66981190f, 0.60708213f, 0.53850579f,
1441
    0.46474338f, 0.38650522f, 0.30454481f, 0.21965148f, 0.13264278f, 0.04435665f, 0.04208675f, 0.12585492f, 0.20841105f,
1442
    0.28896007f, 0.36672625f, 0.44096065f, 0.51094836f, 0.57601535f, 0.63553500f, 0.68893409f, 0.73569834f, 0.77537745f,
1443
    0.80758929f, 0.83202356f, 0.84844500f, 0.85669541f, 0.85669541f, 0.84844500f, 0.83202356f, 0.80758929f, 0.77537745f,
1444
    0.73569834f, 0.68893409f, 0.63553500f, 0.57601535f, 0.51094836f, 0.44096065f, 0.36672625f, 0.28896007f, 0.20841105f,
1445
    0.12585492f, 0.04208675f, 0.03941153f, 0.11785502f, 0.19516350f, 0.27059248f, 0.34341547f, 0.41293120f, 0.47847018f,
1446
    0.53940123f, 0.59513754f, 0.64514232f, 0.68893409f, 0.72609103f, 0.75625527f, 0.77913642f, 0.79451400f, 0.80224001f,
1447
    0.80224001f, 0.79451400f, 0.77913642f, 0.75625527f, 0.72609103f, 0.68893409f, 0.64514232f, 0.59513754f, 0.53940123f,
1448
    0.47847018f, 0.41293120f, 0.34341547f, 0.27059248f, 0.19516350f, 0.11785502f, 0.03941153f, 0.03635675f, 0.10872011f,
1449
    0.18003644f, 0.24961892f, 0.31679744f, 0.38092500f, 0.44138408f, 0.49759236f, 0.54900855f, 0.59513754f, 0.63553500f,
1450
    0.66981190f, 0.69763815f, 0.71874577f, 0.73293144f, 0.74005860f, 0.74005860f, 0.73293144f, 0.71874577f, 0.69763815f,
1451
    0.66981190f, 0.63553500f, 0.59513754f, 0.54900855f, 0.49759236f, 0.44138408f, 0.38092500f, 0.31679744f, 0.24961892f,
1452
    0.18003644f, 0.10872011f, 0.03635675f, 0.03295184f, 0.09853817f, 0.16317551f, 0.22624139f, 0.28712845f, 0.34525031f,
1453
    0.40004721f, 0.45099142f, 0.49759236f, 0.53940123f, 0.57601535f, 0.60708213f, 0.63230234f, 0.65143317f, 0.66429037f,
1454
    0.67075002f, 0.67075002f, 0.66429037f, 0.65143317f, 0.63230234f, 0.60708213f, 0.57601535f, 0.53940123f, 0.49759236f,
1455
    0.45099142f, 0.40004721f, 0.34525031f, 0.28712845f, 0.22624139f, 0.16317551f, 0.09853817f, 0.03295184f, 0.02922958f,
1456
    0.08740724f, 0.14474313f, 0.20068505f, 0.25469428f, 0.30625066f, 0.35485765f, 0.40004721f, 0.44138408f, 0.47847018f,
1457
    0.51094836f, 0.53850579f, 0.56087714f, 0.57784694f, 0.58925176f, 0.59498173f, 0.59498173f, 0.58925176f, 0.57784694f,
1458
    0.56087714f, 0.53850579f, 0.51094836f, 0.47847018f, 0.44138408f, 0.40004721f, 0.35485765f, 0.30625066f, 0.25469428f,
1459
    0.20068505f, 0.14474313f, 0.08740724f, 0.02922958f, 0.02522583f, 0.07543454f, 0.12491678f, 0.17319600f, 0.21980725f,
1460
    0.26430163f, 0.30625066f, 0.34525031f, 0.38092500f, 0.41293120f, 0.44096065f, 0.46474338f, 0.48405039f, 0.49869573f,
1461
    0.50853837f, 0.51348346f, 0.51348346f, 0.50853837f, 0.49869573f, 0.48405039f, 0.46474338f, 0.44096065f, 0.41293120f,
1462
    0.38092500f, 0.34525031f, 0.30625066f, 0.26430163f, 0.21980725f, 0.17319600f, 0.12491678f, 0.07543454f, 0.02522583f,
1463
    0.02097913f, 0.06273536f, 0.10388742f, 0.14403898f, 0.18280336f, 0.21980725f, 0.25469428f, 0.28712845f, 0.31679744f,
1464
    0.34341547f, 0.36672625f, 0.38650522f, 0.40256196f, 0.41474181f, 0.42292747f, 0.42704007f, 0.42704007f, 0.42292747f,
1465
    0.41474181f, 0.40256196f, 0.38650522f, 0.36672625f, 0.34341547f, 0.31679744f, 0.28712845f, 0.25469428f, 0.21980725f,
1466
    0.18280336f, 0.14403898f, 0.10388742f, 0.06273536f, 0.02097913f, 0.01653040f, 0.04943201f, 0.08185755f, 0.11349478f,
1467
    0.14403898f, 0.17319600f, 0.20068505f, 0.22624139f, 0.24961892f, 0.27059248f, 0.28896007f, 0.30454481f, 0.31719664f,
1468
    0.32679370f, 0.33324352f, 0.33648404f, 0.33648404f, 0.33324352f, 0.32679370f, 0.31719664f, 0.30454481f, 0.28896007f,
1469
    0.27059248f, 0.24961892f, 0.22624139f, 0.20068505f, 0.17319600f, 0.14403898f, 0.11349478f, 0.08185755f, 0.04943201f,
1470
    0.01653040f, 0.01192247f, 0.03565260f, 0.05903937f, 0.08185755f, 0.10388742f, 0.12491678f, 0.14474313f, 0.16317551f,
1471
    0.18003644f, 0.19516350f, 0.20841105f, 0.21965148f, 0.22877654f, 0.23569837f, 0.24035029f, 0.24268749f, 0.24268749f,
1472
    0.24035029f, 0.23569837f, 0.22877654f, 0.21965148f, 0.20841105f, 0.19516350f, 0.18003644f, 0.16317551f, 0.14474313f,
1473
    0.12491678f, 0.10388742f, 0.08185755f, 0.05903937f, 0.03565260f, 0.01192247f, 0.00719972f, 0.02152983f, 0.03565260f,
1474
    0.04943201f, 0.06273536f, 0.07543454f, 0.08740724f, 0.09853817f, 0.10872011f, 0.11785502f, 0.12585492f, 0.13264278f,
1475
    0.13815321f, 0.14233315f, 0.14514233f, 0.14655373f, 0.14655373f, 0.14514233f, 0.14233315f, 0.13815321f, 0.13264278f,
1476
    0.12585492f, 0.11785502f, 0.10872011f, 0.09853817f, 0.08740724f, 0.07543454f, 0.06273536f, 0.04943201f, 0.03565260f,
1477
    0.02152983f, 0.00719972f, 0.00240764f, 0.00719972f, 0.01192247f, 0.01653040f, 0.02097913f, 0.02522583f, 0.02922958f,
1478
    0.03295184f, 0.03635675f, 0.03941153f, 0.04208675f, 0.04435665f, 0.04619938f, 0.04759718f, 0.04853659f, 0.04900857f,
1479
    0.04900857f, 0.04853659f, 0.04759718f, 0.04619938f, 0.04435665f, 0.04208675f, 0.03941153f, 0.03635675f, 0.03295184f,
1480
    0.02922958f, 0.02522583f, 0.02097913f, 0.01653040f, 0.01192247f, 0.00719972f, 0.00240764f,
1481
};
1482
static const float window_function_half_cos_window_64[4096] = {
1483
    0.00060227f, 0.00180536f, 0.00300411f, 0.00419561f, 0.00537701f, 0.00654546f, 0.00769814f, 0.00883227f, 0.00994512f,
1484
    0.01103401f, 0.01209633f, 0.01312950f, 0.01413104f, 0.01509854f, 0.01602966f, 0.01692217f, 0.01777391f, 0.01858284f,
1485
    0.01934699f, 0.02006454f, 0.02073374f, 0.02135300f, 0.02192082f, 0.02243583f, 0.02289679f, 0.02330259f, 0.02365225f,
1486
    0.02394493f, 0.02417992f, 0.02435667f, 0.02447473f, 0.02453384f, 0.02453384f, 0.02447473f, 0.02435667f, 0.02417992f,
1487
    0.02394493f, 0.02365225f, 0.02330259f, 0.02289679f, 0.02243583f, 0.02192082f, 0.02135300f, 0.02073374f, 0.02006454f,
1488
    0.01934699f, 0.01858284f, 0.01777391f, 0.01692217f, 0.01602966f, 0.01509854f, 0.01413104f, 0.01312950f, 0.01209633f,
1489
    0.01103401f, 0.00994512f, 0.00883227f, 0.00769814f, 0.00654546f, 0.00537701f, 0.00419561f, 0.00300411f, 0.00180536f,
1490
    0.00060227f, 0.00180536f, 0.00541175f, 0.00900509f, 0.01257674f, 0.01611809f, 0.01962061f, 0.02307586f, 0.02647552f,
1491
    0.02981140f, 0.03307546f, 0.03625984f, 0.03935686f, 0.04235908f, 0.04525924f, 0.04805037f, 0.05072575f, 0.05327892f,
1492
    0.05570374f, 0.05799436f, 0.06014527f, 0.06215128f, 0.06400757f, 0.06570966f, 0.06725344f, 0.06863521f, 0.06985163f,
1493
    0.07089976f, 0.07177710f, 0.07248152f, 0.07301132f, 0.07336523f, 0.07354241f, 0.07354241f, 0.07336523f, 0.07301132f,
1494
    0.07248152f, 0.07177710f, 0.07089976f, 0.06985163f, 0.06863521f, 0.06725344f, 0.06570966f, 0.06400757f, 0.06215128f,
1495
    0.06014527f, 0.05799436f, 0.05570374f, 0.05327892f, 0.05072575f, 0.04805037f, 0.04525924f, 0.04235908f, 0.03935686f,
1496
    0.03625984f, 0.03307546f, 0.02981140f, 0.02647552f, 0.02307586f, 0.01962061f, 0.01611809f, 0.01257674f, 0.00900509f,
1497
    0.00541175f, 0.00180536f, 0.00300411f, 0.00900509f, 0.01498437f, 0.02092756f, 0.02682033f, 0.03264849f, 0.03839799f,
1498
    0.04405500f, 0.04960586f, 0.05503723f, 0.06033600f, 0.06548942f, 0.07048507f, 0.07531092f, 0.07995533f, 0.08440712f,
1499
    0.08865558f, 0.09269045f, 0.09650202f, 0.10008111f, 0.10341910f, 0.10650793f, 0.10934019f, 0.11190903f, 0.11420828f,
1500
    0.11623239f, 0.11797648f, 0.11943635f, 0.12060850f, 0.12149009f, 0.12207900f, 0.12237380f, 0.12237380f, 0.12207900f,
1501
    0.12149009f, 0.12060850f, 0.11943635f, 0.11797648f, 0.11623239f, 0.11420828f, 0.11190903f, 0.10934019f, 0.10650793f,
1502
    0.10341910f, 0.10008111f, 0.09650202f, 0.09269045f, 0.08865558f, 0.08440712f, 0.07995533f, 0.07531092f, 0.07048507f,
1503
    0.06548942f, 0.06033600f, 0.05503723f, 0.04960586f, 0.04405500f, 0.03839799f, 0.03264849f, 0.02682033f, 0.02092756f,
1504
    0.01498437f, 0.00900509f, 0.00300411f, 0.00419561f, 0.01257674f, 0.02092756f, 0.02922797f, 0.03745796f, 0.04559772f,
1505
    0.05362762f, 0.06152834f, 0.06928082f, 0.07686640f, 0.08426680f, 0.09146421f, 0.09844126f, 0.10518116f, 0.11166766f,
1506
    0.11788516f, 0.12381865f, 0.12945385f, 0.13477719f, 0.13977584f, 0.14443776f, 0.14875172f, 0.15270731f, 0.15629503f,
1507
    0.15950622f, 0.16233313f, 0.16476898f, 0.16680788f, 0.16844493f, 0.16967617f, 0.17049865f, 0.17091040f, 0.17091040f,
1508
    0.17049865f, 0.16967617f, 0.16844493f, 0.16680788f, 0.16476898f, 0.16233313f, 0.15950622f, 0.15629503f, 0.15270731f,
1509
    0.14875172f, 0.14443776f, 0.13977584f, 0.13477719f, 0.12945385f, 0.12381865f, 0.11788516f, 0.11166766f, 0.10518116f,
1510
    0.09844126f, 0.09146421f, 0.08426680f, 0.07686640f, 0.06928082f, 0.06152834f, 0.05362762f, 0.04559772f, 0.03745796f,
1511
    0.02922797f, 0.02092756f, 0.01257674f, 0.00419561f, 0.00537701f, 0.01611809f, 0.02682033f, 0.03745796f, 0.04800535f,
1512
    0.05843709f, 0.06872806f, 0.07885345f, 0.08878887f, 0.09851040f, 0.10799461f, 0.11721864f, 0.12616029f, 0.13479801f,
1513
    0.14311098f, 0.15107919f, 0.15868343f, 0.16590540f, 0.17272767f, 0.17913385f, 0.18510847f, 0.19063714f, 0.19570655f,
1514
    0.20030449f, 0.20441988f, 0.20804280f, 0.21116453f, 0.21377754f, 0.21587555f, 0.21745349f, 0.21850757f, 0.21903525f,
1515
    0.21903525f, 0.21850757f, 0.21745349f, 0.21587555f, 0.21377754f, 0.21116453f, 0.20804280f, 0.20441988f, 0.20030449f,
1516
    0.19570655f, 0.19063714f, 0.18510847f, 0.17913385f, 0.17272767f, 0.16590540f, 0.15868343f, 0.15107919f, 0.14311098f,
1517
    0.13479801f, 0.12616029f, 0.11721864f, 0.10799461f, 0.09851040f, 0.08878887f, 0.07885345f, 0.06872806f, 0.05843709f,
1518
    0.04800535f, 0.03745796f, 0.02682033f, 0.01611809f, 0.00537701f, 0.00654546f, 0.01962061f, 0.03264849f, 0.04559772f,
1519
    0.05843709f, 0.07113569f, 0.08366292f, 0.09598859f, 0.10808302f, 0.11991708f, 0.13146223f, 0.14269069f, 0.15357539f,
1520
    0.16409011f, 0.17420954f, 0.18390927f, 0.19316594f, 0.20195726f, 0.21026205f, 0.21806030f, 0.22533323f, 0.23206329f,
1521
    0.23823431f, 0.24383141f, 0.24884108f, 0.25325128f, 0.25705138f, 0.26023221f, 0.26278612f, 0.26470694f, 0.26599008f,
1522
    0.26663244f, 0.26663244f, 0.26599008f, 0.26470694f, 0.26278612f, 0.26023221f, 0.25705138f, 0.25325128f, 0.24884108f,
1523
    0.24383141f, 0.23823431f, 0.23206329f, 0.22533323f, 0.21806030f, 0.21026205f, 0.20195726f, 0.19316594f, 0.18390927f,
1524
    0.17420954f, 0.16409011f, 0.15357539f, 0.14269069f, 0.13146223f, 0.11991708f, 0.10808302f, 0.09598859f, 0.08366292f,
1525
    0.07113569f, 0.05843709f, 0.04559772f, 0.03264849f, 0.01962061f, 0.00654546f, 0.00769814f, 0.02307586f, 0.03839799f,
1526
    0.05362762f, 0.06872806f, 0.08366292f, 0.09839623f, 0.11289250f, 0.12711680f, 0.14103487f, 0.15461317f, 0.16781898f,
1527
    0.18062052f, 0.19298692f, 0.20488839f, 0.21629629f, 0.22718309f, 0.23752259f, 0.24728988f, 0.25646144f, 0.26501513f,
1528
    0.27293041f, 0.28018814f, 0.28677091f, 0.29266280f, 0.29784966f, 0.30231896f, 0.30605996f, 0.30906361f, 0.31132272f,
1529
    0.31283182f, 0.31358728f, 0.31358728f, 0.31283182f, 0.31132272f, 0.30906361f, 0.30605996f, 0.30231896f, 0.29784966f,
1530
    0.29266280f, 0.28677091f, 0.28018814f, 0.27293041f, 0.26501513f, 0.25646144f, 0.24728988f, 0.23752259f, 0.22718309f,
1531
    0.21629629f, 0.20488839f, 0.19298692f, 0.18062052f, 0.16781898f, 0.15461317f, 0.14103487f, 0.12711680f, 0.11289250f,
1532
    0.09839623f, 0.08366292f, 0.06872806f, 0.05362762f, 0.03839799f, 0.02307586f, 0.00769814f, 0.00883227f, 0.02647552f,
1533
    0.04405500f, 0.06152834f, 0.07885345f, 0.09598859f, 0.11289250f, 0.12952444f, 0.14584434f, 0.16181289f, 0.17739162f,
1534
    0.19254299f, 0.20723051f, 0.22141880f, 0.23507367f, 0.24816222f, 0.26065293f, 0.27251571f, 0.28372195f, 0.29424471f,
1535
    0.30405861f, 0.31313998f, 0.32146698f, 0.32901955f, 0.33577949f, 0.34173048f, 0.34685823f, 0.35115036f, 0.35459653f,
1536
    0.35718846f, 0.35891989f, 0.35978663f, 0.35978663f, 0.35891989f, 0.35718846f, 0.35459653f, 0.35115036f, 0.34685823f,
1537
    0.34173048f, 0.33577949f, 0.32901955f, 0.32146698f, 0.31313998f, 0.30405861f, 0.29424471f, 0.28372195f, 0.27251571f,
1538
    0.26065293f, 0.24816222f, 0.23507367f, 0.22141880f, 0.20723051f, 0.19254299f, 0.17739162f, 0.16181289f, 0.14584434f,
1539
    0.12952444f, 0.11289250f, 0.09598859f, 0.07885345f, 0.06152834f, 0.04405500f, 0.02647552f, 0.00883227f, 0.00994512f,
1540
    0.02981140f, 0.04960586f, 0.06928082f, 0.08878887f, 0.10808302f, 0.12711680f, 0.14584434f, 0.16422053f, 0.18220109f,
1541
    0.19974270f, 0.21680313f, 0.23334126f, 0.24931726f, 0.26469263f, 0.27943033f, 0.29349485f, 0.30685231f, 0.31947055f,
1542
    0.33131915f, 0.34236956f, 0.35259521f, 0.36197138f, 0.37047556f, 0.37808722f, 0.38478804f, 0.39056188f, 0.39539480f,
1543
    0.39927521f, 0.40219373f, 0.40414330f, 0.40511927f, 0.40511927f, 0.40414330f, 0.40219373f, 0.39927521f, 0.39539480f,
1544
    0.39056188f, 0.38478804f, 0.37808722f, 0.37047556f, 0.36197138f, 0.35259521f, 0.34236956f, 0.33131915f, 0.31947055f,
1545
    0.30685231f, 0.29349485f, 0.27943033f, 0.26469263f, 0.24931726f, 0.23334126f, 0.21680313f, 0.19974270f, 0.18220109f,
1546
    0.16422053f, 0.14584434f, 0.12711680f, 0.10808302f, 0.08878887f, 0.06928082f, 0.04960586f, 0.02981140f, 0.00994512f,
1547
    0.01103401f, 0.03307546f, 0.05503723f, 0.07686640f, 0.09851040f, 0.11991708f, 0.14103487f, 0.16181289f, 0.18220109f,
1548
    0.20215034f, 0.22161262f, 0.24054100f, 0.25888988f, 0.27661508f, 0.29367390f, 0.31002524f, 0.32562968f, 0.34044969f,
1549
    0.35444948f, 0.36759540f, 0.37985572f, 0.39120096f, 0.40160376f, 0.41103905f, 0.41948414f, 0.42691863f, 0.43332464f,
1550
    0.43868673f, 0.44299200f, 0.44623005f, 0.44839308f, 0.44947591f, 0.44947591f, 0.44839308f, 0.44623005f, 0.44299200f,
1551
    0.43868673f, 0.43332464f, 0.42691863f, 0.41948414f, 0.41103905f, 0.40160376f, 0.39120096f, 0.37985572f, 0.36759540f,
1552
    0.35444948f, 0.34044969f, 0.32562968f, 0.31002524f, 0.29367390f, 0.27661508f, 0.25888988f, 0.24054100f, 0.22161262f,
1553
    0.20215034f, 0.18220109f, 0.16181289f, 0.14103487f, 0.11991708f, 0.09851040f, 0.07686640f, 0.05503723f, 0.03307546f,
1554
    0.01103401f, 0.01209633f, 0.03625984f, 0.06033600f, 0.08426680f, 0.10799461f, 0.13146223f, 0.15461317f, 0.17739162f,
1555
    0.19974270f, 0.22161262f, 0.24294862f, 0.26369935f, 0.28381482f, 0.30324653f, 0.32194772f, 0.33987328f, 0.35698009f,
1556
    0.37322688f, 0.38857454f, 0.40298608f, 0.41642681f, 0.42886430f, 0.44026864f, 0.45061234f, 0.45987046f, 0.46802074f,
1557
    0.47504348f, 0.48092180f, 0.48564157f, 0.48919138f, 0.49156266f, 0.49274975f, 0.49274975f, 0.49156266f, 0.48919138f,
1558
    0.48564157f, 0.48092180f, 0.47504348f, 0.46802074f, 0.45987046f, 0.45061234f, 0.44026864f, 0.42886430f, 0.41642681f,
1559
    0.40298608f, 0.38857454f, 0.37322688f, 0.35698009f, 0.33987328f, 0.32194772f, 0.30324653f, 0.28381482f, 0.26369935f,
1560
    0.24294862f, 0.22161262f, 0.19974270f, 0.17739162f, 0.15461317f, 0.13146223f, 0.10799461f, 0.08426680f, 0.06033600f,
1561
    0.03625984f, 0.01209633f, 0.01312950f, 0.03935686f, 0.06548942f, 0.09146421f, 0.11721864f, 0.14269069f, 0.16781898f,
1562
    0.19254299f, 0.21680313f, 0.24054100f, 0.26369935f, 0.28622246f, 0.30805603f, 0.32914743f, 0.34944591f, 0.36890256f,
1563
    0.38747045f, 0.40510494f, 0.42176345f, 0.43740594f, 0.45199466f, 0.46549448f, 0.47787288f, 0.48910004f, 0.49914894f,
1564
    0.50799531f, 0.51561791f, 0.52199835f, 0.52712119f, 0.53097421f, 0.53354800f, 0.53483647f, 0.53483647f, 0.53354800f,
1565
    0.53097421f, 0.52712119f, 0.52199835f, 0.51561791f, 0.50799531f, 0.49914894f, 0.48910004f, 0.47787288f, 0.46549448f,
1566
    0.45199466f, 0.43740594f, 0.42176345f, 0.40510494f, 0.38747045f, 0.36890256f, 0.34944591f, 0.32914743f, 0.30805603f,
1567
    0.28622246f, 0.26369935f, 0.24054100f, 0.21680313f, 0.19254299f, 0.16781898f, 0.14269069f, 0.11721864f, 0.09146421f,
1568
    0.06548942f, 0.03935686f, 0.01312950f, 0.01413104f, 0.04235908f, 0.07048507f, 0.09844126f, 0.12616029f, 0.15357539f,
1569
    0.18062052f, 0.20723051f, 0.23334126f, 0.25888988f, 0.28381482f, 0.30805603f, 0.33155507f, 0.35425538f, 0.37610227f,
1570
    0.39704308f, 0.41702741f, 0.43600705f, 0.45393634f, 0.47077203f, 0.48647359f, 0.50100321f, 0.51432586f, 0.52640945f,
1571
    0.53722489f, 0.54674608f, 0.55495018f, 0.56181729f, 0.56733096f, 0.57147783f, 0.57424802f, 0.57563478f, 0.57563478f,
1572
    0.57424802f, 0.57147783f, 0.56733096f, 0.56181729f, 0.55495018f, 0.54674608f, 0.53722489f, 0.52640945f, 0.51432586f,
1573
    0.50100321f, 0.48647359f, 0.47077203f, 0.45393634f, 0.43600705f, 0.41702741f, 0.39704308f, 0.37610227f, 0.35425538f,
1574
    0.33155507f, 0.30805603f, 0.28381482f, 0.25888988f, 0.23334126f, 0.20723051f, 0.18062052f, 0.15357539f, 0.12616029f,
1575
    0.09844126f, 0.07048507f, 0.04235908f, 0.01413104f, 0.01509854f, 0.04525924f, 0.07531092f, 0.10518116f, 0.13479801f,
1576
    0.16409011f, 0.19298692f, 0.22141880f, 0.24931726f, 0.27661508f, 0.30324653f, 0.32914743f, 0.35425538f, 0.37850991f,
1577
    0.40185258f, 0.42422712f, 0.44557968f, 0.46585882f, 0.48501563f, 0.50300401f, 0.51978058f, 0.53530502f, 0.54953980f,
1578
    0.56245071f, 0.57400662f, 0.58417976f, 0.59294546f, 0.60028279f, 0.60617393f, 0.61060476f, 0.61356461f, 0.61504632f,
1579
    0.61504632f, 0.61356461f, 0.61060476f, 0.60617393f, 0.60028279f, 0.59294546f, 0.58417976f, 0.57400662f, 0.56245071f,
1580
    0.54953980f, 0.53530502f, 0.51978058f, 0.50300401f, 0.48501563f, 0.46585882f, 0.44557968f, 0.42422712f, 0.40185258f,
1581
    0.37850991f, 0.35425538f, 0.32914743f, 0.30324653f, 0.27661508f, 0.24931726f, 0.22141880f, 0.19298692f, 0.16409011f,
1582
    0.13479801f, 0.10518116f, 0.07531092f, 0.04525924f, 0.01509854f, 0.01602966f, 0.04805037f, 0.07995533f, 0.11166766f,
1583
    0.14311098f, 0.17420954f, 0.20488839f, 0.23507367f, 0.26469263f, 0.29367390f, 0.32194772f, 0.34944591f, 0.37610227f,
1584
    0.40185258f, 0.42663476f, 0.45038915f, 0.47305852f, 0.49458826f, 0.51492649f, 0.53402418f, 0.55183542f, 0.56831717f,
1585
    0.58342987f, 0.59713697f, 0.60940558f, 0.62020600f, 0.62951237f, 0.63730216f, 0.64355659f, 0.64826065f, 0.65140307f,
1586
    0.65297610f, 0.65297610f, 0.65140307f, 0.64826065f, 0.64355659f, 0.63730216f, 0.62951237f, 0.62020600f, 0.60940558f,
1587
    0.59713697f, 0.58342987f, 0.56831717f, 0.55183542f, 0.53402418f, 0.51492649f, 0.49458826f, 0.47305852f, 0.45038915f,
1588
    0.42663476f, 0.40185258f, 0.37610227f, 0.34944591f, 0.32194772f, 0.29367390f, 0.26469263f, 0.23507367f, 0.20488839f,
1589
    0.17420954f, 0.14311098f, 0.11166766f, 0.07995533f, 0.04805037f, 0.01602966f, 0.01692217f, 0.05072575f, 0.08440712f,
1590
    0.11788516f, 0.15107919f, 0.18390927f, 0.21629629f, 0.24816222f, 0.27943033f, 0.31002524f, 0.33987328f, 0.36890256f,
1591
    0.39704308f, 0.42422712f, 0.45038915f, 0.47546616f, 0.49939772f, 0.52212620f, 0.54359680f, 0.56375790f, 0.58256078f,
1592
    0.59996027f, 0.61591434f, 0.63038468f, 0.64333636f, 0.65473819f, 0.66456270f, 0.67278618f, 0.67938888f, 0.68435490f,
1593
    0.68767220f, 0.68933284f, 0.68933284f, 0.68767220f, 0.68435490f, 0.67938888f, 0.67278618f, 0.66456270f, 0.65473819f,
1594
    0.64333636f, 0.63038468f, 0.61591434f, 0.59996027f, 0.58256078f, 0.56375790f, 0.54359680f, 0.52212620f, 0.49939772f,
1595
    0.47546616f, 0.45038915f, 0.42422712f, 0.39704308f, 0.36890256f, 0.33987328f, 0.31002524f, 0.27943033f, 0.24816222f,
1596
    0.21629629f, 0.18390927f, 0.15107919f, 0.11788516f, 0.08440712f, 0.05072575f, 0.01692217f, 0.01777391f, 0.05327892f,
1597
    0.08865558f, 0.12381865f, 0.15868343f, 0.19316594f, 0.22718309f, 0.26065293f, 0.29349485f, 0.32562968f, 0.35698009f,
1598
    0.38747045f, 0.41702741f, 0.44557968f, 0.47305852f, 0.49939772f, 0.52453381f, 0.54840630f, 0.57095760f, 0.59213340f,
1599
    0.61188275f, 0.63015795f, 0.64691508f, 0.66211373f, 0.67571729f, 0.68769300f, 0.69801199f, 0.70664942f, 0.71358448f,
1600
    0.71880043f, 0.72228467f, 0.72402894f, 0.72402894f, 0.72228467f, 0.71880043f, 0.71358448f, 0.70664942f, 0.69801199f,
1601
    0.68769300f, 0.67571729f, 0.66211373f, 0.64691508f, 0.63015795f, 0.61188275f, 0.59213340f, 0.57095760f, 0.54840630f,
1602
    0.52453381f, 0.49939772f, 0.47305852f, 0.44557968f, 0.41702741f, 0.38747045f, 0.35698009f, 0.32562968f, 0.29349485f,
1603
    0.26065293f, 0.22718309f, 0.19316594f, 0.15868343f, 0.12381865f, 0.08865558f, 0.05327892f, 0.01777391f, 0.01858284f,
1604
    0.05570374f, 0.09269045f, 0.12945385f, 0.16590540f, 0.20195726f, 0.23752259f, 0.27251571f, 0.30685231f, 0.34044969f,
1605
    0.37322688f, 0.40510494f, 0.43600705f, 0.46585882f, 0.49458826f, 0.52212620f, 0.54840630f, 0.57336521f, 0.59694290f,
1606
    0.61908245f, 0.63973057f, 0.65883756f, 0.67635733f, 0.69224769f, 0.70647043f, 0.71899116f, 0.72977978f, 0.73881030f,
1607
    0.74606097f, 0.75151426f, 0.75515717f, 0.75698078f, 0.75698078f, 0.75515717f, 0.75151426f, 0.74606097f, 0.73881030f,
1608
    0.72977978f, 0.71899116f, 0.70647043f, 0.69224769f, 0.67635733f, 0.65883756f, 0.63973057f, 0.61908245f, 0.59694290f,
1609
    0.57336521f, 0.54840630f, 0.52212620f, 0.49458826f, 0.46585882f, 0.43600705f, 0.40510494f, 0.37322688f, 0.34044969f,
1610
    0.30685231f, 0.27251571f, 0.23752259f, 0.20195726f, 0.16590540f, 0.12945385f, 0.09269045f, 0.05570374f, 0.01858284f,
1611
    0.01934699f, 0.05799436f, 0.09650202f, 0.13477719f, 0.17272767f, 0.21026205f, 0.24728988f, 0.28372195f, 0.31947055f,
1612
    0.35444948f, 0.38857454f, 0.42176345f, 0.45393634f, 0.48501563f, 0.51492649f, 0.54359680f, 0.57095760f, 0.59694290f,
1613
    0.62149006f, 0.64454007f, 0.66603726f, 0.68592995f, 0.70417017f, 0.72071397f, 0.73552155f, 0.74855715f, 0.75978941f,
1614
    0.76919127f, 0.77674013f, 0.78241771f, 0.78621036f, 0.78810900f, 0.78810900f, 0.78621036f, 0.78241771f, 0.77674013f,
1615
    0.76919127f, 0.75978941f, 0.74855715f, 0.73552155f, 0.72071397f, 0.70417017f, 0.68592995f, 0.66603726f, 0.64454007f,
1616
    0.62149006f, 0.59694290f, 0.57095760f, 0.54359680f, 0.51492649f, 0.48501563f, 0.45393634f, 0.42176345f, 0.38857454f,
1617
    0.35444948f, 0.31947055f, 0.28372195f, 0.24728988f, 0.21026205f, 0.17272767f, 0.13477719f, 0.09650202f, 0.05799436f,
1618
    0.01934699f, 0.02006454f, 0.06014527f, 0.10008111f, 0.13977584f, 0.17913385f, 0.21806030f, 0.25646144f, 0.29424471f,
1619
    0.33131915f, 0.36759540f, 0.40298608f, 0.43740594f, 0.47077203f, 0.50300401f, 0.53402418f, 0.56375790f, 0.59213340f,
1620
    0.61908245f, 0.64454007f, 0.66844493f, 0.69073945f, 0.71136993f, 0.73028660f, 0.74744403f, 0.76280075f, 0.77631980f,
1621
    0.78796870f, 0.79771924f, 0.80554801f, 0.81143618f, 0.81536955f, 0.81733859f, 0.81733859f, 0.81536955f, 0.81143618f,
1622
    0.80554801f, 0.79771924f, 0.78796870f, 0.77631980f, 0.76280075f, 0.74744403f, 0.73028660f, 0.71136993f, 0.69073945f,
1623
    0.66844493f, 0.64454007f, 0.61908245f, 0.59213340f, 0.56375790f, 0.53402418f, 0.50300401f, 0.47077203f, 0.43740594f,
1624
    0.40298608f, 0.36759540f, 0.33131915f, 0.29424471f, 0.25646144f, 0.21806030f, 0.17913385f, 0.13977584f, 0.10008111f,
1625
    0.06014527f, 0.02006454f, 0.02073374f, 0.06215128f, 0.10341910f, 0.14443776f, 0.18510847f, 0.22533323f, 0.26501513f,
1626
    0.30405861f, 0.34236956f, 0.37985572f, 0.41642681f, 0.45199466f, 0.48647359f, 0.51978058f, 0.55183542f, 0.58256078f,
1627
    0.61188275f, 0.63973057f, 0.66603726f, 0.69073945f, 0.71377754f, 0.73509610f, 0.75464374f, 0.77237338f, 0.78824228f,
1628
    0.80221230f, 0.81424963f, 0.82432544f, 0.83241534f, 0.83849984f, 0.84256440f, 0.84459913f, 0.84459913f, 0.84256440f,
1629
    0.83849984f, 0.83241534f, 0.82432544f, 0.81424963f, 0.80221230f, 0.78824228f, 0.77237338f, 0.75464374f, 0.73509610f,
1630
    0.71377754f, 0.69073945f, 0.66603726f, 0.63973057f, 0.61188275f, 0.58256078f, 0.55183542f, 0.51978058f, 0.48647359f,
1631
    0.45199466f, 0.41642681f, 0.37985572f, 0.34236956f, 0.30405861f, 0.26501513f, 0.22533323f, 0.18510847f, 0.14443776f,
1632
    0.10341910f, 0.06215128f, 0.02073374f, 0.02135300f, 0.06400757f, 0.10650793f, 0.14875172f, 0.19063714f, 0.23206329f,
1633
    0.27293041f, 0.31313998f, 0.35259521f, 0.39120096f, 0.42886430f, 0.46549448f, 0.50100321f, 0.53530502f, 0.56831717f,
1634
    0.59996027f, 0.63015795f, 0.65883756f, 0.68592995f, 0.71136993f, 0.73509610f, 0.75705135f, 0.77718282f, 0.79544204f,
1635
    0.81178492f, 0.82617211f, 0.83856905f, 0.84894574f, 0.85727727f, 0.86354351f, 0.86772943f, 0.86982495f, 0.86982495f,
1636
    0.86772943f, 0.86354351f, 0.85727727f, 0.84894574f, 0.83856905f, 0.82617211f, 0.81178492f, 0.79544204f, 0.77718282f,
1637
    0.75705135f, 0.73509610f, 0.71136993f, 0.68592995f, 0.65883756f, 0.63015795f, 0.59996027f, 0.56831717f, 0.53530502f,
1638
    0.50100321f, 0.46549448f, 0.42886430f, 0.39120096f, 0.35259521f, 0.31313998f, 0.27293041f, 0.23206329f, 0.19063714f,
1639
    0.14875172f, 0.10650793f, 0.06400757f, 0.02135300f, 0.02192082f, 0.06570966f, 0.10934019f, 0.15270731f, 0.19570655f,
1640
    0.23823431f, 0.28018814f, 0.32146698f, 0.36197138f, 0.40160376f, 0.44026864f, 0.47787288f, 0.51432586f, 0.54953980f,
1641
    0.58342987f, 0.61591434f, 0.64691508f, 0.67635733f, 0.70417017f, 0.73028660f, 0.75464374f, 0.77718282f, 0.79784966f,
1642
    0.81659436f, 0.83337182f, 0.84814167f, 0.86086822f, 0.87152088f, 0.88007390f, 0.88650686f, 0.89080405f, 0.89295530f,
1643
    0.89295530f, 0.89080405f, 0.88650686f, 0.88007390f, 0.87152088f, 0.86086822f, 0.84814167f, 0.83337182f, 0.81659436f,
1644
    0.79784966f, 0.77718282f, 0.75464374f, 0.73028660f, 0.70417017f, 0.67635733f, 0.64691508f, 0.61591434f, 0.58342987f,
1645
    0.54953980f, 0.51432586f, 0.47787288f, 0.44026864f, 0.40160376f, 0.36197138f, 0.32146698f, 0.28018814f, 0.23823431f,
1646
    0.19570655f, 0.15270731f, 0.10934019f, 0.06570966f, 0.02192082f, 0.02243583f, 0.06725344f, 0.11190903f, 0.15629503f,
1647
    0.20030449f, 0.24383141f, 0.28677091f, 0.32901955f, 0.37047556f, 0.41103905f, 0.45061234f, 0.48910004f, 0.52640945f,
1648
    0.56245071f, 0.59713697f, 0.63038468f, 0.66211373f, 0.69224769f, 0.72071397f, 0.74744403f, 0.77237338f, 0.79544204f,
1649
    0.81659436f, 0.83577949f, 0.85295111f, 0.86806792f, 0.88109350f, 0.89199638f, 0.90075046f, 0.90733445f, 0.91173267f,
1650
    0.91393441f, 0.91393441f, 0.91173267f, 0.90733445f, 0.90075046f, 0.89199638f, 0.88109350f, 0.86806792f, 0.85295111f,
1651
    0.83577949f, 0.81659436f, 0.79544204f, 0.77237338f, 0.74744403f, 0.72071397f, 0.69224769f, 0.66211373f, 0.63038468f,
1652
    0.59713697f, 0.56245071f, 0.52640945f, 0.48910004f, 0.45061234f, 0.41103905f, 0.37047556f, 0.32901955f, 0.28677091f,
1653
    0.24383141f, 0.20030449f, 0.15629503f, 0.11190903f, 0.06725344f, 0.02243583f, 0.02289679f, 0.06863521f, 0.11420828f,
1654
    0.15950622f, 0.20441988f, 0.24884108f, 0.29266280f, 0.33577949f, 0.37808722f, 0.41948414f, 0.45987046f, 0.49914894f,
1655
    0.53722489f, 0.57400662f, 0.60940558f, 0.64333636f, 0.67571729f, 0.70647043f, 0.73552155f, 0.76280075f, 0.78824228f,
1656
    0.81178492f, 0.83337182f, 0.85295111f, 0.87047559f, 0.88590294f, 0.89919615f, 0.91032308f, 0.91925693f, 0.92597628f,
1657
    0.93046480f, 0.93271178f, 0.93271178f, 0.93046480f, 0.92597628f, 0.91925693f, 0.91032308f, 0.89919615f, 0.88590294f,
1658
    0.87047559f, 0.85295111f, 0.83337182f, 0.81178492f, 0.78824228f, 0.76280075f, 0.73552155f, 0.70647043f, 0.67571729f,
1659
    0.64333636f, 0.60940558f, 0.57400662f, 0.53722489f, 0.49914894f, 0.45987046f, 0.41948414f, 0.37808722f, 0.33577949f,
1660
    0.29266280f, 0.24884108f, 0.20441988f, 0.15950622f, 0.11420828f, 0.06863521f, 0.02289679f, 0.02330259f, 0.06985163f,
1661
    0.11623239f, 0.16233313f, 0.20804280f, 0.25325128f, 0.29784966f, 0.34173048f, 0.38478804f, 0.42691863f, 0.46802074f,
1662
    0.50799531f, 0.54674608f, 0.58417976f, 0.62020600f, 0.65473819f, 0.68769300f, 0.71899116f, 0.74855715f, 0.77631980f,
1663
    0.80221230f, 0.82617211f, 0.84814167f, 0.86806792f, 0.88590294f, 0.90160376f, 0.91513252f, 0.92645669f, 0.93554890f,
1664
    0.94238728f, 0.94695538f, 0.94924217f, 0.94924217f, 0.94695538f, 0.94238728f, 0.93554890f, 0.92645669f, 0.91513252f,
1665
    0.90160376f, 0.88590294f, 0.86806792f, 0.84814167f, 0.82617211f, 0.80221230f, 0.77631980f, 0.74855715f, 0.71899116f,
1666
    0.68769300f, 0.65473819f, 0.62020600f, 0.58417976f, 0.54674608f, 0.50799531f, 0.46802074f, 0.42691863f, 0.38478804f,
1667
    0.34173048f, 0.29784966f, 0.25325128f, 0.20804280f, 0.16233313f, 0.11623239f, 0.06985163f, 0.02330259f, 0.02365225f,
1668
    0.07089976f, 0.11797648f, 0.16476898f, 0.21116453f, 0.25705138f, 0.30231896f, 0.34685823f, 0.39056188f, 0.43332464f,
1669
    0.47504348f, 0.51561791f, 0.55495018f, 0.59294546f, 0.62951237f, 0.66456270f, 0.69801199f, 0.72977978f, 0.75978941f,
1670
    0.78796870f, 0.81424963f, 0.83856905f, 0.86086822f, 0.88109350f, 0.89919615f, 0.91513252f, 0.92886430f, 0.94035834f,
1671
    0.94958699f, 0.95652801f, 0.96116465f, 0.96348578f, 0.96348578f, 0.96116465f, 0.95652801f, 0.94958699f, 0.94035834f,
1672
    0.92886430f, 0.91513252f, 0.89919615f, 0.88109350f, 0.86086822f, 0.83856905f, 0.81424963f, 0.78796870f, 0.75978941f,
1673
    0.72977978f, 0.69801199f, 0.66456270f, 0.62951237f, 0.59294546f, 0.55495018f, 0.51561791f, 0.47504348f, 0.43332464f,
1674
    0.39056188f, 0.34685823f, 0.30231896f, 0.25705138f, 0.21116453f, 0.16476898f, 0.11797648f, 0.07089976f, 0.02365225f,
1675
    0.02394493f, 0.07177710f, 0.11943635f, 0.16680788f, 0.21377754f, 0.26023221f, 0.30605996f, 0.35115036f, 0.39539480f,
1676
    0.43868673f, 0.48092180f, 0.52199835f, 0.56181729f, 0.60028279f, 0.63730216f, 0.67278618f, 0.70664942f, 0.73881030f,
1677
    0.76919127f, 0.79771924f, 0.82432544f, 0.84894574f, 0.87152088f, 0.89199638f, 0.91032308f, 0.92645669f, 0.94035834f,
1678
    0.95199466f, 0.96133751f, 0.96836442f, 0.97305840f, 0.97540826f, 0.97540826f, 0.97305840f, 0.96836442f, 0.96133751f,
1679
    0.95199466f, 0.94035834f, 0.92645669f, 0.91032308f, 0.89199638f, 0.87152088f, 0.84894574f, 0.82432544f, 0.79771924f,
1680
    0.76919127f, 0.73881030f, 0.70664942f, 0.67278618f, 0.63730216f, 0.60028279f, 0.56181729f, 0.52199835f, 0.48092180f,
1681
    0.43868673f, 0.39539480f, 0.35115036f, 0.30605996f, 0.26023221f, 0.21377754f, 0.16680788f, 0.11943635f, 0.07177710f,
1682
    0.02394493f, 0.02417992f, 0.07248152f, 0.12060850f, 0.16844493f, 0.21587555f, 0.26278612f, 0.30906361f, 0.35459653f,
1683
    0.39927521f, 0.44299200f, 0.48564157f, 0.52712119f, 0.56733096f, 0.60617393f, 0.64355659f, 0.67938888f, 0.71358448f,
1684
    0.74606097f, 0.77674013f, 0.80554801f, 0.83241534f, 0.85727727f, 0.88007390f, 0.90075046f, 0.91925693f, 0.93554890f,
1685
    0.94958699f, 0.96133751f, 0.97077203f, 0.97786790f, 0.98260796f, 0.98498088f, 0.98498088f, 0.98260796f, 0.97786790f,
1686
    0.97077203f, 0.96133751f, 0.94958699f, 0.93554890f, 0.91925693f, 0.90075046f, 0.88007390f, 0.85727727f, 0.83241534f,
1687
    0.80554801f, 0.77674013f, 0.74606097f, 0.71358448f, 0.67938888f, 0.64355659f, 0.60617393f, 0.56733096f, 0.52712119f,
1688
    0.48564157f, 0.44299200f, 0.39927521f, 0.35459653f, 0.30906361f, 0.26278612f, 0.21587555f, 0.16844493f, 0.12060850f,
1689
    0.07248152f, 0.02417992f, 0.02435667f, 0.07301132f, 0.12149009f, 0.16967617f, 0.21745349f, 0.26470694f, 0.31132272f,
1690
    0.35718846f, 0.40219373f, 0.44623005f, 0.48919138f, 0.53097421f, 0.57147783f, 0.61060476f, 0.64826065f, 0.68435490f,
1691
    0.71880043f, 0.75151426f, 0.78241771f, 0.81143618f, 0.83849984f, 0.86354351f, 0.88650686f, 0.90733445f, 0.92597628f,
1692
    0.94238728f, 0.95652801f, 0.96836442f, 0.97786790f, 0.98501563f, 0.98979038f, 0.99218065f, 0.99218065f, 0.98979038f,
1693
    0.98501563f, 0.97786790f, 0.96836442f, 0.95652801f, 0.94238728f, 0.92597628f, 0.90733445f, 0.88650686f, 0.86354351f,
1694
    0.83849984f, 0.81143618f, 0.78241771f, 0.75151426f, 0.71880043f, 0.68435490f, 0.64826065f, 0.61060476f, 0.57147783f,
1695
    0.53097421f, 0.48919138f, 0.44623005f, 0.40219373f, 0.35718846f, 0.31132272f, 0.26470694f, 0.21745349f, 0.16967617f,
1696
    0.12149009f, 0.07301132f, 0.02435667f, 0.02447473f, 0.07336523f, 0.12207900f, 0.17049865f, 0.21850757f, 0.26599008f,
1697
    0.31283182f, 0.35891989f, 0.40414330f, 0.44839308f, 0.49156266f, 0.53354800f, 0.57424802f, 0.61356461f, 0.65140307f,
1698
    0.68767220f, 0.72228467f, 0.75515717f, 0.78621036f, 0.81536955f, 0.84256440f, 0.86772943f, 0.89080405f, 0.91173267f,
1699
    0.93046480f, 0.94695538f, 0.96116465f, 0.97305840f, 0.98260796f, 0.98979038f, 0.99458826f, 0.99699008f, 0.99699008f,
1700
    0.99458826f, 0.98979038f, 0.98260796f, 0.97305840f, 0.96116465f, 0.94695538f, 0.93046480f, 0.91173267f, 0.89080405f,
1701
    0.86772943f, 0.84256440f, 0.81536955f, 0.78621036f, 0.75515717f, 0.72228467f, 0.68767220f, 0.65140307f, 0.61356461f,
1702
    0.57424802f, 0.53354800f, 0.49156266f, 0.44839308f, 0.40414330f, 0.35891989f, 0.31283182f, 0.26599008f, 0.21850757f,
1703
    0.17049865f, 0.12207900f, 0.07336523f, 0.02447473f, 0.02453384f, 0.07354241f, 0.12237380f, 0.17091040f, 0.21903525f,
1704
    0.26663244f, 0.31358728f, 0.35978663f, 0.40511927f, 0.44947591f, 0.49274975f, 0.53483647f, 0.57563478f, 0.61504632f,
1705
    0.65297610f, 0.68933284f, 0.72402894f, 0.75698078f, 0.78810900f, 0.81733859f, 0.84459913f, 0.86982495f, 0.89295530f,
1706
    0.91393441f, 0.93271178f, 0.94924217f, 0.96348578f, 0.97540826f, 0.98498088f, 0.99218065f, 0.99699008f, 0.99939775f,
1707
    0.99939775f, 0.99699008f, 0.99218065f, 0.98498088f, 0.97540826f, 0.96348578f, 0.94924217f, 0.93271178f, 0.91393441f,
1708
    0.89295530f, 0.86982495f, 0.84459913f, 0.81733859f, 0.78810900f, 0.75698078f, 0.72402894f, 0.68933284f, 0.65297610f,
1709
    0.61504632f, 0.57563478f, 0.53483647f, 0.49274975f, 0.44947591f, 0.40511927f, 0.35978663f, 0.31358728f, 0.26663244f,
1710
    0.21903525f, 0.17091040f, 0.12237380f, 0.07354241f, 0.02453384f, 0.02453384f, 0.07354241f, 0.12237380f, 0.17091040f,
1711
    0.21903525f, 0.26663244f, 0.31358728f, 0.35978663f, 0.40511927f, 0.44947591f, 0.49274975f, 0.53483647f, 0.57563478f,
1712
    0.61504632f, 0.65297610f, 0.68933284f, 0.72402894f, 0.75698078f, 0.78810900f, 0.81733859f, 0.84459913f, 0.86982495f,
1713
    0.89295530f, 0.91393441f, 0.93271178f, 0.94924217f, 0.96348578f, 0.97540826f, 0.98498088f, 0.99218065f, 0.99699008f,
1714
    0.99939775f, 0.99939775f, 0.99699008f, 0.99218065f, 0.98498088f, 0.97540826f, 0.96348578f, 0.94924217f, 0.93271178f,
1715
    0.91393441f, 0.89295530f, 0.86982495f, 0.84459913f, 0.81733859f, 0.78810900f, 0.75698078f, 0.72402894f, 0.68933284f,
1716
    0.65297610f, 0.61504632f, 0.57563478f, 0.53483647f, 0.49274975f, 0.44947591f, 0.40511927f, 0.35978663f, 0.31358728f,
1717
    0.26663244f, 0.21903525f, 0.17091040f, 0.12237380f, 0.07354241f, 0.02453384f, 0.02447473f, 0.07336523f, 0.12207900f,
1718
    0.17049865f, 0.21850757f, 0.26599008f, 0.31283182f, 0.35891989f, 0.40414330f, 0.44839308f, 0.49156266f, 0.53354800f,
1719
    0.57424802f, 0.61356461f, 0.65140307f, 0.68767220f, 0.72228467f, 0.75515717f, 0.78621036f, 0.81536955f, 0.84256440f,
1720
    0.86772943f, 0.89080405f, 0.91173267f, 0.93046480f, 0.94695538f, 0.96116465f, 0.97305840f, 0.98260796f, 0.98979038f,
1721
    0.99458826f, 0.99699008f, 0.99699008f, 0.99458826f, 0.98979038f, 0.98260796f, 0.97305840f, 0.96116465f, 0.94695538f,
1722
    0.93046480f, 0.91173267f, 0.89080405f, 0.86772943f, 0.84256440f, 0.81536955f, 0.78621036f, 0.75515717f, 0.72228467f,
1723
    0.68767220f, 0.65140307f, 0.61356461f, 0.57424802f, 0.53354800f, 0.49156266f, 0.44839308f, 0.40414330f, 0.35891989f,
1724
    0.31283182f, 0.26599008f, 0.21850757f, 0.17049865f, 0.12207900f, 0.07336523f, 0.02447473f, 0.02435667f, 0.07301132f,
1725
    0.12149009f, 0.16967617f, 0.21745349f, 0.26470694f, 0.31132272f, 0.35718846f, 0.40219373f, 0.44623005f, 0.48919138f,
1726
    0.53097421f, 0.57147783f, 0.61060476f, 0.64826065f, 0.68435490f, 0.71880043f, 0.75151426f, 0.78241771f, 0.81143618f,
1727
    0.83849984f, 0.86354351f, 0.88650686f, 0.90733445f, 0.92597628f, 0.94238728f, 0.95652801f, 0.96836442f, 0.97786790f,
1728
    0.98501563f, 0.98979038f, 0.99218065f, 0.99218065f, 0.98979038f, 0.98501563f, 0.97786790f, 0.96836442f, 0.95652801f,
1729
    0.94238728f, 0.92597628f, 0.90733445f, 0.88650686f, 0.86354351f, 0.83849984f, 0.81143618f, 0.78241771f, 0.75151426f,
1730
    0.71880043f, 0.68435490f, 0.64826065f, 0.61060476f, 0.57147783f, 0.53097421f, 0.48919138f, 0.44623005f, 0.40219373f,
1731
    0.35718846f, 0.31132272f, 0.26470694f, 0.21745349f, 0.16967617f, 0.12149009f, 0.07301132f, 0.02435667f, 0.02417992f,
1732
    0.07248152f, 0.12060850f, 0.16844493f, 0.21587555f, 0.26278612f, 0.30906361f, 0.35459653f, 0.39927521f, 0.44299200f,
1733
    0.48564157f, 0.52712119f, 0.56733096f, 0.60617393f, 0.64355659f, 0.67938888f, 0.71358448f, 0.74606097f, 0.77674013f,
1734
    0.80554801f, 0.83241534f, 0.85727727f, 0.88007390f, 0.90075046f, 0.91925693f, 0.93554890f, 0.94958699f, 0.96133751f,
1735
    0.97077203f, 0.97786790f, 0.98260796f, 0.98498088f, 0.98498088f, 0.98260796f, 0.97786790f, 0.97077203f, 0.96133751f,
1736
    0.94958699f, 0.93554890f, 0.91925693f, 0.90075046f, 0.88007390f, 0.85727727f, 0.83241534f, 0.80554801f, 0.77674013f,
1737
    0.74606097f, 0.71358448f, 0.67938888f, 0.64355659f, 0.60617393f, 0.56733096f, 0.52712119f, 0.48564157f, 0.44299200f,
1738
    0.39927521f, 0.35459653f, 0.30906361f, 0.26278612f, 0.21587555f, 0.16844493f, 0.12060850f, 0.07248152f, 0.02417992f,
1739
    0.02394493f, 0.07177710f, 0.11943635f, 0.16680788f, 0.21377754f, 0.26023221f, 0.30605996f, 0.35115036f, 0.39539480f,
1740
    0.43868673f, 0.48092180f, 0.52199835f, 0.56181729f, 0.60028279f, 0.63730216f, 0.67278618f, 0.70664942f, 0.73881030f,
1741
    0.76919127f, 0.79771924f, 0.82432544f, 0.84894574f, 0.87152088f, 0.89199638f, 0.91032308f, 0.92645669f, 0.94035834f,
1742
    0.95199466f, 0.96133751f, 0.96836442f, 0.97305840f, 0.97540826f, 0.97540826f, 0.97305840f, 0.96836442f, 0.96133751f,
1743
    0.95199466f, 0.94035834f, 0.92645669f, 0.91032308f, 0.89199638f, 0.87152088f, 0.84894574f, 0.82432544f, 0.79771924f,
1744
    0.76919127f, 0.73881030f, 0.70664942f, 0.67278618f, 0.63730216f, 0.60028279f, 0.56181729f, 0.52199835f, 0.48092180f,
1745
    0.43868673f, 0.39539480f, 0.35115036f, 0.30605996f, 0.26023221f, 0.21377754f, 0.16680788f, 0.11943635f, 0.07177710f,
1746
    0.02394493f, 0.02365225f, 0.07089976f, 0.11797648f, 0.16476898f, 0.21116453f, 0.25705138f, 0.30231896f, 0.34685823f,
1747
    0.39056188f, 0.43332464f, 0.47504348f, 0.51561791f, 0.55495018f, 0.59294546f, 0.62951237f, 0.66456270f, 0.69801199f,
1748
    0.72977978f, 0.75978941f, 0.78796870f, 0.81424963f, 0.83856905f, 0.86086822f, 0.88109350f, 0.89919615f, 0.91513252f,
1749
    0.92886430f, 0.94035834f, 0.94958699f, 0.95652801f, 0.96116465f, 0.96348578f, 0.96348578f, 0.96116465f, 0.95652801f,
1750
    0.94958699f, 0.94035834f, 0.92886430f, 0.91513252f, 0.89919615f, 0.88109350f, 0.86086822f, 0.83856905f, 0.81424963f,
1751
    0.78796870f, 0.75978941f, 0.72977978f, 0.69801199f, 0.66456270f, 0.62951237f, 0.59294546f, 0.55495018f, 0.51561791f,
1752
    0.47504348f, 0.43332464f, 0.39056188f, 0.34685823f, 0.30231896f, 0.25705138f, 0.21116453f, 0.16476898f, 0.11797648f,
1753
    0.07089976f, 0.02365225f, 0.02330259f, 0.06985163f, 0.11623239f, 0.16233313f, 0.20804280f, 0.25325128f, 0.29784966f,
1754
    0.34173048f, 0.38478804f, 0.42691863f, 0.46802074f, 0.50799531f, 0.54674608f, 0.58417976f, 0.62020600f, 0.65473819f,
1755
    0.68769300f, 0.71899116f, 0.74855715f, 0.77631980f, 0.80221230f, 0.82617211f, 0.84814167f, 0.86806792f, 0.88590294f,
1756
    0.90160376f, 0.91513252f, 0.92645669f, 0.93554890f, 0.94238728f, 0.94695538f, 0.94924217f, 0.94924217f, 0.94695538f,
1757
    0.94238728f, 0.93554890f, 0.92645669f, 0.91513252f, 0.90160376f, 0.88590294f, 0.86806792f, 0.84814167f, 0.82617211f,
1758
    0.80221230f, 0.77631980f, 0.74855715f, 0.71899116f, 0.68769300f, 0.65473819f, 0.62020600f, 0.58417976f, 0.54674608f,
1759
    0.50799531f, 0.46802074f, 0.42691863f, 0.38478804f, 0.34173048f, 0.29784966f, 0.25325128f, 0.20804280f, 0.16233313f,
1760
    0.11623239f, 0.06985163f, 0.02330259f, 0.02289679f, 0.06863521f, 0.11420828f, 0.15950622f, 0.20441988f, 0.24884108f,
1761
    0.29266280f, 0.33577949f, 0.37808722f, 0.41948414f, 0.45987046f, 0.49914894f, 0.53722489f, 0.57400662f, 0.60940558f,
1762
    0.64333636f, 0.67571729f, 0.70647043f, 0.73552155f, 0.76280075f, 0.78824228f, 0.81178492f, 0.83337182f, 0.85295111f,
1763
    0.87047559f, 0.88590294f, 0.89919615f, 0.91032308f, 0.91925693f, 0.92597628f, 0.93046480f, 0.93271178f, 0.93271178f,
1764
    0.93046480f, 0.92597628f, 0.91925693f, 0.91032308f, 0.89919615f, 0.88590294f, 0.87047559f, 0.85295111f, 0.83337182f,
1765
    0.81178492f, 0.78824228f, 0.76280075f, 0.73552155f, 0.70647043f, 0.67571729f, 0.64333636f, 0.60940558f, 0.57400662f,
1766
    0.53722489f, 0.49914894f, 0.45987046f, 0.41948414f, 0.37808722f, 0.33577949f, 0.29266280f, 0.24884108f, 0.20441988f,
1767
    0.15950622f, 0.11420828f, 0.06863521f, 0.02289679f, 0.02243583f, 0.06725344f, 0.11190903f, 0.15629503f, 0.20030449f,
1768
    0.24383141f, 0.28677091f, 0.32901955f, 0.37047556f, 0.41103905f, 0.45061234f, 0.48910004f, 0.52640945f, 0.56245071f,
1769
    0.59713697f, 0.63038468f, 0.66211373f, 0.69224769f, 0.72071397f, 0.74744403f, 0.77237338f, 0.79544204f, 0.81659436f,
1770
    0.83577949f, 0.85295111f, 0.86806792f, 0.88109350f, 0.89199638f, 0.90075046f, 0.90733445f, 0.91173267f, 0.91393441f,
1771
    0.91393441f, 0.91173267f, 0.90733445f, 0.90075046f, 0.89199638f, 0.88109350f, 0.86806792f, 0.85295111f, 0.83577949f,
1772
    0.81659436f, 0.79544204f, 0.77237338f, 0.74744403f, 0.72071397f, 0.69224769f, 0.66211373f, 0.63038468f, 0.59713697f,
1773
    0.56245071f, 0.52640945f, 0.48910004f, 0.45061234f, 0.41103905f, 0.37047556f, 0.32901955f, 0.28677091f, 0.24383141f,
1774
    0.20030449f, 0.15629503f, 0.11190903f, 0.06725344f, 0.02243583f, 0.02192082f, 0.06570966f, 0.10934019f, 0.15270731f,
1775
    0.19570655f, 0.23823431f, 0.28018814f, 0.32146698f, 0.36197138f, 0.40160376f, 0.44026864f, 0.47787288f, 0.51432586f,
1776
    0.54953980f, 0.58342987f, 0.61591434f, 0.64691508f, 0.67635733f, 0.70417017f, 0.73028660f, 0.75464374f, 0.77718282f,
1777
    0.79784966f, 0.81659436f, 0.83337182f, 0.84814167f, 0.86086822f, 0.87152088f, 0.88007390f, 0.88650686f, 0.89080405f,
1778
    0.89295530f, 0.89295530f, 0.89080405f, 0.88650686f, 0.88007390f, 0.87152088f, 0.86086822f, 0.84814167f, 0.83337182f,
1779
    0.81659436f, 0.79784966f, 0.77718282f, 0.75464374f, 0.73028660f, 0.70417017f, 0.67635733f, 0.64691508f, 0.61591434f,
1780
    0.58342987f, 0.54953980f, 0.51432586f, 0.47787288f, 0.44026864f, 0.40160376f, 0.36197138f, 0.32146698f, 0.28018814f,
1781
    0.23823431f, 0.19570655f, 0.15270731f, 0.10934019f, 0.06570966f, 0.02192082f, 0.02135300f, 0.06400757f, 0.10650793f,
1782
    0.14875172f, 0.19063714f, 0.23206329f, 0.27293041f, 0.31313998f, 0.35259521f, 0.39120096f, 0.42886430f, 0.46549448f,
1783
    0.50100321f, 0.53530502f, 0.56831717f, 0.59996027f, 0.63015795f, 0.65883756f, 0.68592995f, 0.71136993f, 0.73509610f,
1784
    0.75705135f, 0.77718282f, 0.79544204f, 0.81178492f, 0.82617211f, 0.83856905f, 0.84894574f, 0.85727727f, 0.86354351f,
1785
    0.86772943f, 0.86982495f, 0.86982495f, 0.86772943f, 0.86354351f, 0.85727727f, 0.84894574f, 0.83856905f, 0.82617211f,
1786
    0.81178492f, 0.79544204f, 0.77718282f, 0.75705135f, 0.73509610f, 0.71136993f, 0.68592995f, 0.65883756f, 0.63015795f,
1787
    0.59996027f, 0.56831717f, 0.53530502f, 0.50100321f, 0.46549448f, 0.42886430f, 0.39120096f, 0.35259521f, 0.31313998f,
1788
    0.27293041f, 0.23206329f, 0.19063714f, 0.14875172f, 0.10650793f, 0.06400757f, 0.02135300f, 0.02073374f, 0.06215128f,
1789
    0.10341910f, 0.14443776f, 0.18510847f, 0.22533323f, 0.26501513f, 0.30405861f, 0.34236956f, 0.37985572f, 0.41642681f,
1790
    0.45199466f, 0.48647359f, 0.51978058f, 0.55183542f, 0.58256078f, 0.61188275f, 0.63973057f, 0.66603726f, 0.69073945f,
1791
    0.71377754f, 0.73509610f, 0.75464374f, 0.77237338f, 0.78824228f, 0.80221230f, 0.81424963f, 0.82432544f, 0.83241534f,
1792
    0.83849984f, 0.84256440f, 0.84459913f, 0.84459913f, 0.84256440f, 0.83849984f, 0.83241534f, 0.82432544f, 0.81424963f,
1793
    0.80221230f, 0.78824228f, 0.77237338f, 0.75464374f, 0.73509610f, 0.71377754f, 0.69073945f, 0.66603726f, 0.63973057f,
1794
    0.61188275f, 0.58256078f, 0.55183542f, 0.51978058f, 0.48647359f, 0.45199466f, 0.41642681f, 0.37985572f, 0.34236956f,
1795
    0.30405861f, 0.26501513f, 0.22533323f, 0.18510847f, 0.14443776f, 0.10341910f, 0.06215128f, 0.02073374f, 0.02006454f,
1796
    0.06014527f, 0.10008111f, 0.13977584f, 0.17913385f, 0.21806030f, 0.25646144f, 0.29424471f, 0.33131915f, 0.36759540f,
1797
    0.40298608f, 0.43740594f, 0.47077203f, 0.50300401f, 0.53402418f, 0.56375790f, 0.59213340f, 0.61908245f, 0.64454007f,
1798
    0.66844493f, 0.69073945f, 0.71136993f, 0.73028660f, 0.74744403f, 0.76280075f, 0.77631980f, 0.78796870f, 0.79771924f,
1799
    0.80554801f, 0.81143618f, 0.81536955f, 0.81733859f, 0.81733859f, 0.81536955f, 0.81143618f, 0.80554801f, 0.79771924f,
1800
    0.78796870f, 0.77631980f, 0.76280075f, 0.74744403f, 0.73028660f, 0.71136993f, 0.69073945f, 0.66844493f, 0.64454007f,
1801
    0.61908245f, 0.59213340f, 0.56375790f, 0.53402418f, 0.50300401f, 0.47077203f, 0.43740594f, 0.40298608f, 0.36759540f,
1802
    0.33131915f, 0.29424471f, 0.25646144f, 0.21806030f, 0.17913385f, 0.13977584f, 0.10008111f, 0.06014527f, 0.02006454f,
1803
    0.01934699f, 0.05799436f, 0.09650202f, 0.13477719f, 0.17272767f, 0.21026205f, 0.24728988f, 0.28372195f, 0.31947055f,
1804
    0.35444948f, 0.38857454f, 0.42176345f, 0.45393634f, 0.48501563f, 0.51492649f, 0.54359680f, 0.57095760f, 0.59694290f,
1805
    0.62149006f, 0.64454007f, 0.66603726f, 0.68592995f, 0.70417017f, 0.72071397f, 0.73552155f, 0.74855715f, 0.75978941f,
1806
    0.76919127f, 0.77674013f, 0.78241771f, 0.78621036f, 0.78810900f, 0.78810900f, 0.78621036f, 0.78241771f, 0.77674013f,
1807
    0.76919127f, 0.75978941f, 0.74855715f, 0.73552155f, 0.72071397f, 0.70417017f, 0.68592995f, 0.66603726f, 0.64454007f,
1808
    0.62149006f, 0.59694290f, 0.57095760f, 0.54359680f, 0.51492649f, 0.48501563f, 0.45393634f, 0.42176345f, 0.38857454f,
1809
    0.35444948f, 0.31947055f, 0.28372195f, 0.24728988f, 0.21026205f, 0.17272767f, 0.13477719f, 0.09650202f, 0.05799436f,
1810
    0.01934699f, 0.01858284f, 0.05570374f, 0.09269045f, 0.12945385f, 0.16590540f, 0.20195726f, 0.23752259f, 0.27251571f,
1811
    0.30685231f, 0.34044969f, 0.37322688f, 0.40510494f, 0.43600705f, 0.46585882f, 0.49458826f, 0.52212620f, 0.54840630f,
1812
    0.57336521f, 0.59694290f, 0.61908245f, 0.63973057f, 0.65883756f, 0.67635733f, 0.69224769f, 0.70647043f, 0.71899116f,
1813
    0.72977978f, 0.73881030f, 0.74606097f, 0.75151426f, 0.75515717f, 0.75698078f, 0.75698078f, 0.75515717f, 0.75151426f,
1814
    0.74606097f, 0.73881030f, 0.72977978f, 0.71899116f, 0.70647043f, 0.69224769f, 0.67635733f, 0.65883756f, 0.63973057f,
1815
    0.61908245f, 0.59694290f, 0.57336521f, 0.54840630f, 0.52212620f, 0.49458826f, 0.46585882f, 0.43600705f, 0.40510494f,
1816
    0.37322688f, 0.34044969f, 0.30685231f, 0.27251571f, 0.23752259f, 0.20195726f, 0.16590540f, 0.12945385f, 0.09269045f,
1817
    0.05570374f, 0.01858284f, 0.01777391f, 0.05327892f, 0.08865558f, 0.12381865f, 0.15868343f, 0.19316594f, 0.22718309f,
1818
    0.26065293f, 0.29349485f, 0.32562968f, 0.35698009f, 0.38747045f, 0.41702741f, 0.44557968f, 0.47305852f, 0.49939772f,
1819
    0.52453381f, 0.54840630f, 0.57095760f, 0.59213340f, 0.61188275f, 0.63015795f, 0.64691508f, 0.66211373f, 0.67571729f,
1820
    0.68769300f, 0.69801199f, 0.70664942f, 0.71358448f, 0.71880043f, 0.72228467f, 0.72402894f, 0.72402894f, 0.72228467f,
1821
    0.71880043f, 0.71358448f, 0.70664942f, 0.69801199f, 0.68769300f, 0.67571729f, 0.66211373f, 0.64691508f, 0.63015795f,
1822
    0.61188275f, 0.59213340f, 0.57095760f, 0.54840630f, 0.52453381f, 0.49939772f, 0.47305852f, 0.44557968f, 0.41702741f,
1823
    0.38747045f, 0.35698009f, 0.32562968f, 0.29349485f, 0.26065293f, 0.22718309f, 0.19316594f, 0.15868343f, 0.12381865f,
1824
    0.08865558f, 0.05327892f, 0.01777391f, 0.01692217f, 0.05072575f, 0.08440712f, 0.11788516f, 0.15107919f, 0.18390927f,
1825
    0.21629629f, 0.24816222f, 0.27943033f, 0.31002524f, 0.33987328f, 0.36890256f, 0.39704308f, 0.42422712f, 0.45038915f,
1826
    0.47546616f, 0.49939772f, 0.52212620f, 0.54359680f, 0.56375790f, 0.58256078f, 0.59996027f, 0.61591434f, 0.63038468f,
1827
    0.64333636f, 0.65473819f, 0.66456270f, 0.67278618f, 0.67938888f, 0.68435490f, 0.68767220f, 0.68933284f, 0.68933284f,
1828
    0.68767220f, 0.68435490f, 0.67938888f, 0.67278618f, 0.66456270f, 0.65473819f, 0.64333636f, 0.63038468f, 0.61591434f,
1829
    0.59996027f, 0.58256078f, 0.56375790f, 0.54359680f, 0.52212620f, 0.49939772f, 0.47546616f, 0.45038915f, 0.42422712f,
1830
    0.39704308f, 0.36890256f, 0.33987328f, 0.31002524f, 0.27943033f, 0.24816222f, 0.21629629f, 0.18390927f, 0.15107919f,
1831
    0.11788516f, 0.08440712f, 0.05072575f, 0.01692217f, 0.01602966f, 0.04805037f, 0.07995533f, 0.11166766f, 0.14311098f,
1832
    0.17420954f, 0.20488839f, 0.23507367f, 0.26469263f, 0.29367390f, 0.32194772f, 0.34944591f, 0.37610227f, 0.40185258f,
1833
    0.42663476f, 0.45038915f, 0.47305852f, 0.49458826f, 0.51492649f, 0.53402418f, 0.55183542f, 0.56831717f, 0.58342987f,
1834
    0.59713697f, 0.60940558f, 0.62020600f, 0.62951237f, 0.63730216f, 0.64355659f, 0.64826065f, 0.65140307f, 0.65297610f,
1835
    0.65297610f, 0.65140307f, 0.64826065f, 0.64355659f, 0.63730216f, 0.62951237f, 0.62020600f, 0.60940558f, 0.59713697f,
1836
    0.58342987f, 0.56831717f, 0.55183542f, 0.53402418f, 0.51492649f, 0.49458826f, 0.47305852f, 0.45038915f, 0.42663476f,
1837
    0.40185258f, 0.37610227f, 0.34944591f, 0.32194772f, 0.29367390f, 0.26469263f, 0.23507367f, 0.20488839f, 0.17420954f,
1838
    0.14311098f, 0.11166766f, 0.07995533f, 0.04805037f, 0.01602966f, 0.01509854f, 0.04525924f, 0.07531092f, 0.10518116f,
1839
    0.13479801f, 0.16409011f, 0.19298692f, 0.22141880f, 0.24931726f, 0.27661508f, 0.30324653f, 0.32914743f, 0.35425538f,
1840
    0.37850991f, 0.40185258f, 0.42422712f, 0.44557968f, 0.46585882f, 0.48501563f, 0.50300401f, 0.51978058f, 0.53530502f,
1841
    0.54953980f, 0.56245071f, 0.57400662f, 0.58417976f, 0.59294546f, 0.60028279f, 0.60617393f, 0.61060476f, 0.61356461f,
1842
    0.61504632f, 0.61504632f, 0.61356461f, 0.61060476f, 0.60617393f, 0.60028279f, 0.59294546f, 0.58417976f, 0.57400662f,
1843
    0.56245071f, 0.54953980f, 0.53530502f, 0.51978058f, 0.50300401f, 0.48501563f, 0.46585882f, 0.44557968f, 0.42422712f,
1844
    0.40185258f, 0.37850991f, 0.35425538f, 0.32914743f, 0.30324653f, 0.27661508f, 0.24931726f, 0.22141880f, 0.19298692f,
1845
    0.16409011f, 0.13479801f, 0.10518116f, 0.07531092f, 0.04525924f, 0.01509854f, 0.01413104f, 0.04235908f, 0.07048507f,
1846
    0.09844126f, 0.12616029f, 0.15357539f, 0.18062052f, 0.20723051f, 0.23334126f, 0.25888988f, 0.28381482f, 0.30805603f,
1847
    0.33155507f, 0.35425538f, 0.37610227f, 0.39704308f, 0.41702741f, 0.43600705f, 0.45393634f, 0.47077203f, 0.48647359f,
1848
    0.50100321f, 0.51432586f, 0.52640945f, 0.53722489f, 0.54674608f, 0.55495018f, 0.56181729f, 0.56733096f, 0.57147783f,
1849
    0.57424802f, 0.57563478f, 0.57563478f, 0.57424802f, 0.57147783f, 0.56733096f, 0.56181729f, 0.55495018f, 0.54674608f,
1850
    0.53722489f, 0.52640945f, 0.51432586f, 0.50100321f, 0.48647359f, 0.47077203f, 0.45393634f, 0.43600705f, 0.41702741f,
1851
    0.39704308f, 0.37610227f, 0.35425538f, 0.33155507f, 0.30805603f, 0.28381482f, 0.25888988f, 0.23334126f, 0.20723051f,
1852
    0.18062052f, 0.15357539f, 0.12616029f, 0.09844126f, 0.07048507f, 0.04235908f, 0.01413104f, 0.01312950f, 0.03935686f,
1853
    0.06548942f, 0.09146421f, 0.11721864f, 0.14269069f, 0.16781898f, 0.19254299f, 0.21680313f, 0.24054100f, 0.26369935f,
1854
    0.28622246f, 0.30805603f, 0.32914743f, 0.34944591f, 0.36890256f, 0.38747045f, 0.40510494f, 0.42176345f, 0.43740594f,
1855
    0.45199466f, 0.46549448f, 0.47787288f, 0.48910004f, 0.49914894f, 0.50799531f, 0.51561791f, 0.52199835f, 0.52712119f,
1856
    0.53097421f, 0.53354800f, 0.53483647f, 0.53483647f, 0.53354800f, 0.53097421f, 0.52712119f, 0.52199835f, 0.51561791f,
1857
    0.50799531f, 0.49914894f, 0.48910004f, 0.47787288f, 0.46549448f, 0.45199466f, 0.43740594f, 0.42176345f, 0.40510494f,
1858
    0.38747045f, 0.36890256f, 0.34944591f, 0.32914743f, 0.30805603f, 0.28622246f, 0.26369935f, 0.24054100f, 0.21680313f,
1859
    0.19254299f, 0.16781898f, 0.14269069f, 0.11721864f, 0.09146421f, 0.06548942f, 0.03935686f, 0.01312950f, 0.01209633f,
1860
    0.03625984f, 0.06033600f, 0.08426680f, 0.10799461f, 0.13146223f, 0.15461317f, 0.17739162f, 0.19974270f, 0.22161262f,
1861
    0.24294862f, 0.26369935f, 0.28381482f, 0.30324653f, 0.32194772f, 0.33987328f, 0.35698009f, 0.37322688f, 0.38857454f,
1862
    0.40298608f, 0.41642681f, 0.42886430f, 0.44026864f, 0.45061234f, 0.45987046f, 0.46802074f, 0.47504348f, 0.48092180f,
1863
    0.48564157f, 0.48919138f, 0.49156266f, 0.49274975f, 0.49274975f, 0.49156266f, 0.48919138f, 0.48564157f, 0.48092180f,
1864
    0.47504348f, 0.46802074f, 0.45987046f, 0.45061234f, 0.44026864f, 0.42886430f, 0.41642681f, 0.40298608f, 0.38857454f,
1865
    0.37322688f, 0.35698009f, 0.33987328f, 0.32194772f, 0.30324653f, 0.28381482f, 0.26369935f, 0.24294862f, 0.22161262f,
1866
    0.19974270f, 0.17739162f, 0.15461317f, 0.13146223f, 0.10799461f, 0.08426680f, 0.06033600f, 0.03625984f, 0.01209633f,
1867
    0.01103401f, 0.03307546f, 0.05503723f, 0.07686640f, 0.09851040f, 0.11991708f, 0.14103487f, 0.16181289f, 0.18220109f,
1868
    0.20215034f, 0.22161262f, 0.24054100f, 0.25888988f, 0.27661508f, 0.29367390f, 0.31002524f, 0.32562968f, 0.34044969f,
1869
    0.35444948f, 0.36759540f, 0.37985572f, 0.39120096f, 0.40160376f, 0.41103905f, 0.41948414f, 0.42691863f, 0.43332464f,
1870
    0.43868673f, 0.44299200f, 0.44623005f, 0.44839308f, 0.44947591f, 0.44947591f, 0.44839308f, 0.44623005f, 0.44299200f,
1871
    0.43868673f, 0.43332464f, 0.42691863f, 0.41948414f, 0.41103905f, 0.40160376f, 0.39120096f, 0.37985572f, 0.36759540f,
1872
    0.35444948f, 0.34044969f, 0.32562968f, 0.31002524f, 0.29367390f, 0.27661508f, 0.25888988f, 0.24054100f, 0.22161262f,
1873
    0.20215034f, 0.18220109f, 0.16181289f, 0.14103487f, 0.11991708f, 0.09851040f, 0.07686640f, 0.05503723f, 0.03307546f,
1874
    0.01103401f, 0.00994512f, 0.02981140f, 0.04960586f, 0.06928082f, 0.08878887f, 0.10808302f, 0.12711680f, 0.14584434f,
1875
    0.16422053f, 0.18220109f, 0.19974270f, 0.21680313f, 0.23334126f, 0.24931726f, 0.26469263f, 0.27943033f, 0.29349485f,
1876
    0.30685231f, 0.31947055f, 0.33131915f, 0.34236956f, 0.35259521f, 0.36197138f, 0.37047556f, 0.37808722f, 0.38478804f,
1877
    0.39056188f, 0.39539480f, 0.39927521f, 0.40219373f, 0.40414330f, 0.40511927f, 0.40511927f, 0.40414330f, 0.40219373f,
1878
    0.39927521f, 0.39539480f, 0.39056188f, 0.38478804f, 0.37808722f, 0.37047556f, 0.36197138f, 0.35259521f, 0.34236956f,
1879
    0.33131915f, 0.31947055f, 0.30685231f, 0.29349485f, 0.27943033f, 0.26469263f, 0.24931726f, 0.23334126f, 0.21680313f,
1880
    0.19974270f, 0.18220109f, 0.16422053f, 0.14584434f, 0.12711680f, 0.10808302f, 0.08878887f, 0.06928082f, 0.04960586f,
1881
    0.02981140f, 0.00994512f, 0.00883227f, 0.02647552f, 0.04405500f, 0.06152834f, 0.07885345f, 0.09598859f, 0.11289250f,
1882
    0.12952444f, 0.14584434f, 0.16181289f, 0.17739162f, 0.19254299f, 0.20723051f, 0.22141880f, 0.23507367f, 0.24816222f,
1883
    0.26065293f, 0.27251571f, 0.28372195f, 0.29424471f, 0.30405861f, 0.31313998f, 0.32146698f, 0.32901955f, 0.33577949f,
1884
    0.34173048f, 0.34685823f, 0.35115036f, 0.35459653f, 0.35718846f, 0.35891989f, 0.35978663f, 0.35978663f, 0.35891989f,
1885
    0.35718846f, 0.35459653f, 0.35115036f, 0.34685823f, 0.34173048f, 0.33577949f, 0.32901955f, 0.32146698f, 0.31313998f,
1886
    0.30405861f, 0.29424471f, 0.28372195f, 0.27251571f, 0.26065293f, 0.24816222f, 0.23507367f, 0.22141880f, 0.20723051f,
1887
    0.19254299f, 0.17739162f, 0.16181289f, 0.14584434f, 0.12952444f, 0.11289250f, 0.09598859f, 0.07885345f, 0.06152834f,
1888
    0.04405500f, 0.02647552f, 0.00883227f, 0.00769814f, 0.02307586f, 0.03839799f, 0.05362762f, 0.06872806f, 0.08366292f,
1889
    0.09839623f, 0.11289250f, 0.12711680f, 0.14103487f, 0.15461317f, 0.16781898f, 0.18062052f, 0.19298692f, 0.20488839f,
1890
    0.21629629f, 0.22718309f, 0.23752259f, 0.24728988f, 0.25646144f, 0.26501513f, 0.27293041f, 0.28018814f, 0.28677091f,
1891
    0.29266280f, 0.29784966f, 0.30231896f, 0.30605996f, 0.30906361f, 0.31132272f, 0.31283182f, 0.31358728f, 0.31358728f,
1892
    0.31283182f, 0.31132272f, 0.30906361f, 0.30605996f, 0.30231896f, 0.29784966f, 0.29266280f, 0.28677091f, 0.28018814f,
1893
    0.27293041f, 0.26501513f, 0.25646144f, 0.24728988f, 0.23752259f, 0.22718309f, 0.21629629f, 0.20488839f, 0.19298692f,
1894
    0.18062052f, 0.16781898f, 0.15461317f, 0.14103487f, 0.12711680f, 0.11289250f, 0.09839623f, 0.08366292f, 0.06872806f,
1895
    0.05362762f, 0.03839799f, 0.02307586f, 0.00769814f, 0.00654546f, 0.01962061f, 0.03264849f, 0.04559772f, 0.05843709f,
1896
    0.07113569f, 0.08366292f, 0.09598859f, 0.10808302f, 0.11991708f, 0.13146223f, 0.14269069f, 0.15357539f, 0.16409011f,
1897
    0.17420954f, 0.18390927f, 0.19316594f, 0.20195726f, 0.21026205f, 0.21806030f, 0.22533323f, 0.23206329f, 0.23823431f,
1898
    0.24383141f, 0.24884108f, 0.25325128f, 0.25705138f, 0.26023221f, 0.26278612f, 0.26470694f, 0.26599008f, 0.26663244f,
1899
    0.26663244f, 0.26599008f, 0.26470694f, 0.26278612f, 0.26023221f, 0.25705138f, 0.25325128f, 0.24884108f, 0.24383141f,
1900
    0.23823431f, 0.23206329f, 0.22533323f, 0.21806030f, 0.21026205f, 0.20195726f, 0.19316594f, 0.18390927f, 0.17420954f,
1901
    0.16409011f, 0.15357539f, 0.14269069f, 0.13146223f, 0.11991708f, 0.10808302f, 0.09598859f, 0.08366292f, 0.07113569f,
1902
    0.05843709f, 0.04559772f, 0.03264849f, 0.01962061f, 0.00654546f, 0.00537701f, 0.01611809f, 0.02682033f, 0.03745796f,
1903
    0.04800535f, 0.05843709f, 0.06872806f, 0.07885345f, 0.08878887f, 0.09851040f, 0.10799461f, 0.11721864f, 0.12616029f,
1904
    0.13479801f, 0.14311098f, 0.15107919f, 0.15868343f, 0.16590540f, 0.17272767f, 0.17913385f, 0.18510847f, 0.19063714f,
1905
    0.19570655f, 0.20030449f, 0.20441988f, 0.20804280f, 0.21116453f, 0.21377754f, 0.21587555f, 0.21745349f, 0.21850757f,
1906
    0.21903525f, 0.21903525f, 0.21850757f, 0.21745349f, 0.21587555f, 0.21377754f, 0.21116453f, 0.20804280f, 0.20441988f,
1907
    0.20030449f, 0.19570655f, 0.19063714f, 0.18510847f, 0.17913385f, 0.17272767f, 0.16590540f, 0.15868343f, 0.15107919f,
1908
    0.14311098f, 0.13479801f, 0.12616029f, 0.11721864f, 0.10799461f, 0.09851040f, 0.08878887f, 0.07885345f, 0.06872806f,
1909
    0.05843709f, 0.04800535f, 0.03745796f, 0.02682033f, 0.01611809f, 0.00537701f, 0.00419561f, 0.01257674f, 0.02092756f,
1910
    0.02922797f, 0.03745796f, 0.04559772f, 0.05362762f, 0.06152834f, 0.06928082f, 0.07686640f, 0.08426680f, 0.09146421f,
1911
    0.09844126f, 0.10518116f, 0.11166766f, 0.11788516f, 0.12381865f, 0.12945385f, 0.13477719f, 0.13977584f, 0.14443776f,
1912
    0.14875172f, 0.15270731f, 0.15629503f, 0.15950622f, 0.16233313f, 0.16476898f, 0.16680788f, 0.16844493f, 0.16967617f,
1913
    0.17049865f, 0.17091040f, 0.17091040f, 0.17049865f, 0.16967617f, 0.16844493f, 0.16680788f, 0.16476898f, 0.16233313f,
1914
    0.15950622f, 0.15629503f, 0.15270731f, 0.14875172f, 0.14443776f, 0.13977584f, 0.13477719f, 0.12945385f, 0.12381865f,
1915
    0.11788516f, 0.11166766f, 0.10518116f, 0.09844126f, 0.09146421f, 0.08426680f, 0.07686640f, 0.06928082f, 0.06152834f,
1916
    0.05362762f, 0.04559772f, 0.03745796f, 0.02922797f, 0.02092756f, 0.01257674f, 0.00419561f, 0.00300411f, 0.00900509f,
1917
    0.01498437f, 0.02092756f, 0.02682033f, 0.03264849f, 0.03839799f, 0.04405500f, 0.04960586f, 0.05503723f, 0.06033600f,
1918
    0.06548942f, 0.07048507f, 0.07531092f, 0.07995533f, 0.08440712f, 0.08865558f, 0.09269045f, 0.09650202f, 0.10008111f,
1919
    0.10341910f, 0.10650793f, 0.10934019f, 0.11190903f, 0.11420828f, 0.11623239f, 0.11797648f, 0.11943635f, 0.12060850f,
1920
    0.12149009f, 0.12207900f, 0.12237380f, 0.12237380f, 0.12207900f, 0.12149009f, 0.12060850f, 0.11943635f, 0.11797648f,
1921
    0.11623239f, 0.11420828f, 0.11190903f, 0.10934019f, 0.10650793f, 0.10341910f, 0.10008111f, 0.09650202f, 0.09269045f,
1922
    0.08865558f, 0.08440712f, 0.07995533f, 0.07531092f, 0.07048507f, 0.06548942f, 0.06033600f, 0.05503723f, 0.04960586f,
1923
    0.04405500f, 0.03839799f, 0.03264849f, 0.02682033f, 0.02092756f, 0.01498437f, 0.00900509f, 0.00300411f, 0.00180536f,
1924
    0.00541175f, 0.00900509f, 0.01257674f, 0.01611809f, 0.01962061f, 0.02307586f, 0.02647552f, 0.02981140f, 0.03307546f,
1925
    0.03625984f, 0.03935686f, 0.04235908f, 0.04525924f, 0.04805037f, 0.05072575f, 0.05327892f, 0.05570374f, 0.05799436f,
1926
    0.06014527f, 0.06215128f, 0.06400757f, 0.06570966f, 0.06725344f, 0.06863521f, 0.06985163f, 0.07089976f, 0.07177710f,
1927
    0.07248152f, 0.07301132f, 0.07336523f, 0.07354241f, 0.07354241f, 0.07336523f, 0.07301132f, 0.07248152f, 0.07177710f,
1928
    0.07089976f, 0.06985163f, 0.06863521f, 0.06725344f, 0.06570966f, 0.06400757f, 0.06215128f, 0.06014527f, 0.05799436f,
1929
    0.05570374f, 0.05327892f, 0.05072575f, 0.04805037f, 0.04525924f, 0.04235908f, 0.03935686f, 0.03625984f, 0.03307546f,
1930
    0.02981140f, 0.02647552f, 0.02307586f, 0.01962061f, 0.01611809f, 0.01257674f, 0.00900509f, 0.00541175f, 0.00180536f,
1931
    0.00060227f, 0.00180536f, 0.00300411f, 0.00419561f, 0.00537701f, 0.00654546f, 0.00769814f, 0.00883227f, 0.00994512f,
1932
    0.01103401f, 0.01209633f, 0.01312950f, 0.01413104f, 0.01509854f, 0.01602966f, 0.01692217f, 0.01777391f, 0.01858284f,
1933
    0.01934699f, 0.02006454f, 0.02073374f, 0.02135300f, 0.02192082f, 0.02243583f, 0.02289679f, 0.02330259f, 0.02365225f,
1934
    0.02394493f, 0.02417992f, 0.02435667f, 0.02447473f, 0.02453384f, 0.02453384f, 0.02447473f, 0.02435667f, 0.02417992f,
1935
    0.02394493f, 0.02365225f, 0.02330259f, 0.02289679f, 0.02243583f, 0.02192082f, 0.02135300f, 0.02073374f, 0.02006454f,
1936
    0.01934699f, 0.01858284f, 0.01777391f, 0.01692217f, 0.01602966f, 0.01509854f, 0.01413104f, 0.01312950f, 0.01209633f,
1937
    0.01103401f, 0.00994512f, 0.00883227f, 0.00769814f, 0.00654546f, 0.00537701f, 0.00419561f, 0.00300411f, 0.00180536f,
1938
    0.00060227f,
1939
};
1940
1941
static const float* get_half_cos_window(int32_t block_size) {
1942
    switch (block_size) {
1943
    case 2: {
1944
        return window_function_half_cos_window_2;
1945
    }
1946
    case 4: {
1947
        return window_function_half_cos_window_4;
1948
    }
1949
    case 8: {
1950
        return window_function_half_cos_window_8;
1951
    }
1952
    case 16: {
1953
        return window_function_half_cos_window_16;
1954
    }
1955
    case 32: {
1956
        return window_function_half_cos_window_32;
1957
    }
1958
    case 64: {
1959
        return window_function_half_cos_window_64;
1960
    }
1961
    }
1962
    assert(0);
1963
    return NULL;
1964
}
1965
1966
#define DITHER_AND_QUANTIZE(INT_TYPE, suffix)                                                                           \
1967
    static void dither_and_quantize_##suffix(float*    result,                                                          \
1968
                                             int32_t   result_stride,                                                   \
1969
                                             INT_TYPE* denoised,                                                        \
1970
                                             int32_t   w,                                                               \
1971
                                             int32_t   h,                                                               \
1972
                                             int32_t   stride,                                                          \
1973
                                             int32_t   chroma_sub_w,                                                    \
1974
                                             int32_t   chroma_sub_h,                                                    \
1975
                                             int32_t   block_size,                                                      \
1976
                                             float     block_normalization) {                                               \
1977
        for (int32_t y = 0; y < (h >> chroma_sub_h); ++y) {                                                             \
1978
            for (int32_t x = 0; x < (w >> chroma_sub_w); ++x) {                                                         \
1979
                const int32_t result_idx = (y + (block_size >> chroma_sub_h)) * result_stride + x +                     \
1980
                    (block_size >> chroma_sub_w);                                                                       \
1981
                INT_TYPE    new_val      = (INT_TYPE)AOMMIN(AOMMAX(result[result_idx] * block_normalization + 0.5f, 0), \
1982
                                                    block_normalization);                                       \
1983
                const float err          = -(((float)new_val) / block_normalization - result[result_idx]);              \
1984
                denoised[y * stride + x] = new_val;                                                                     \
1985
                if (x + 1 < (w >> chroma_sub_w)) {                                                                      \
1986
                    result[result_idx + 1] += err * 7.0f / 16.0f;                                                       \
1987
                }                                                                                                       \
1988
                if (y + 1 < (h >> chroma_sub_h)) {                                                                      \
1989
                    if (x > 0) {                                                                                        \
1990
                        result[result_idx + result_stride - 1] += err * 3.0f / 16.0f;                                   \
1991
                    }                                                                                                   \
1992
                    result[result_idx + result_stride] += err * 5.0f / 16.0f;                                           \
1993
                    if (x + 1 < (w >> chroma_sub_w)) {                                                                  \
1994
                        result[result_idx + result_stride + 1] += err * 1.0f / 16.0f;                                   \
1995
                    }                                                                                                   \
1996
                }                                                                                                       \
1997
            }                                                                                                           \
1998
        }                                                                                                               \
1999
    }
2000
2001
DITHER_AND_QUANTIZE(uint8_t, lowbd);
2002
DITHER_AND_QUANTIZE(uint16_t, highbd);
2003
2004
void svt_av1_apply_window_function_to_plane_c(int32_t y_size, int32_t x_size, float* result_ptr, uint32_t result_stride,
2005
0
                                              float* block, float* plane, const float* window_function) {
2006
0
    for (int32_t y = 0; y < y_size; ++y) {
2007
0
        for (int32_t x = 0; x < x_size; ++x) {
2008
0
            result_ptr[y * result_stride + x] += (block[y * x_size + x] + plane[y * x_size + x]) *
2009
0
                window_function[y * x_size + x];
2010
0
        }
2011
0
    }
2012
0
}
2013
2014
int32_t svt_aom_wiener_denoise_2d(const uint8_t* const data[3], uint8_t* denoised[3], int32_t w, int32_t h,
2015
                                  int32_t stride[3], int32_t chroma_sub[2], float noise_psd[3], int32_t block_size,
2016
0
                                  int32_t bit_depth, int32_t use_highbd) {
2017
0
    const float *window_full = NULL, *window_chroma = NULL;
2018
0
    float*       plane = NULL;
2019
0
    DECLARE_ALIGNED(32, float, *block);
2020
0
    block                          = NULL;
2021
0
    double *               block_d = NULL, *plane_d = NULL;
2022
0
    struct aom_noise_tx_t* tx_full       = NULL;
2023
0
    struct aom_noise_tx_t* tx_chroma     = NULL;
2024
0
    const int32_t          num_blocks_w  = (w + block_size - 1) / block_size;
2025
0
    const int32_t          num_blocks_h  = (h + block_size - 1) / block_size;
2026
0
    const int32_t          result_stride = (num_blocks_w + 2) * block_size;
2027
0
    const int32_t          result_height = (num_blocks_h + 2) * block_size;
2028
0
    float*                 result        = NULL;
2029
0
    int32_t                init_success  = 1;
2030
0
    AomFlatBlockFinder     block_finder_full;
2031
0
    AomFlatBlockFinder     block_finder_chroma;
2032
0
    const float            k_block_normalization = (float)((1 << bit_depth) - 1);
2033
0
    if (chroma_sub[0] != chroma_sub[1]) {
2034
0
        SVT_ERROR(
2035
0
            "svt_aom_wiener_denoise_2d doesn't handle different chroma "
2036
0
            "subsampling");
2037
0
        return 0;
2038
0
    }
2039
0
    init_success &= svt_aom_flat_block_finder_init(&block_finder_full, block_size, bit_depth, use_highbd);
2040
0
    result      = (float*)malloc((num_blocks_h + 2) * block_size * result_stride * sizeof(*result));
2041
0
    plane       = (float*)malloc(block_size * block_size * sizeof(*plane));
2042
0
    block       = (float*)svt_aom_memalign(32, 2 * block_size * block_size * sizeof(*block));
2043
0
    block_d     = (double*)malloc(block_size * block_size * sizeof(*block_d));
2044
0
    plane_d     = (double*)malloc(block_size * block_size * sizeof(*plane_d));
2045
0
    window_full = get_half_cos_window(block_size);
2046
0
    tx_full     = svt_aom_noise_tx_malloc(block_size);
2047
2048
0
    if (chroma_sub[0] != 0) {
2049
0
        init_success &= svt_aom_flat_block_finder_init(
2050
0
            &block_finder_chroma, block_size >> chroma_sub[0], bit_depth, use_highbd);
2051
0
        window_chroma = get_half_cos_window(block_size >> chroma_sub[0]);
2052
0
        tx_chroma     = svt_aom_noise_tx_malloc(block_size >> chroma_sub[0]);
2053
0
    } else {
2054
0
        window_chroma = window_full;
2055
0
        tx_chroma     = tx_full;
2056
0
    }
2057
2058
0
    init_success &= (int32_t)((tx_full != NULL) && (tx_chroma != NULL) && (plane != NULL) && (plane_d != NULL) &&
2059
0
                              (block != NULL) && (block_d != NULL) && (window_full != NULL) &&
2060
0
                              (window_chroma != NULL) && (result != NULL));
2061
0
    for (int32_t c = init_success ? 0 : 3; c < 3; ++c) {
2062
0
        const float*           window_function = c == 0 ? window_full : window_chroma;
2063
0
        AomFlatBlockFinder*    block_finder    = &block_finder_full;
2064
0
        const int32_t          chroma_sub_h    = c > 0 ? chroma_sub[1] : 0;
2065
0
        const int32_t          chroma_sub_w    = c > 0 ? chroma_sub[0] : 0;
2066
0
        struct aom_noise_tx_t* tx              = (c > 0 && chroma_sub[0] > 0) ? tx_chroma : tx_full;
2067
0
        if (!data[c] || !denoised[c]) {
2068
0
            continue;
2069
0
        }
2070
0
        if (c > 0 && chroma_sub[0] != 0) {
2071
0
            block_finder = &block_finder_chroma;
2072
0
        }
2073
0
        memset(result, 0, sizeof(*result) * result_stride * result_height);
2074
        // Do overlapped block processing (half overlapped). The block rows can
2075
        // easily be done in parallel
2076
0
        for (int32_t offsy = 0; offsy < (block_size >> chroma_sub_h); offsy += (block_size >> chroma_sub_h) / 2) {
2077
0
            for (int32_t offsx = 0; offsx < (block_size >> chroma_sub_w); offsx += (block_size >> chroma_sub_w) / 2) {
2078
                // Pad the boundary when processing each block-set.
2079
0
                for (int32_t by = -1; by < num_blocks_h; ++by) {
2080
0
                    for (int32_t bx = -1; bx < num_blocks_w; ++bx) {
2081
0
                        const int32_t pixels_per_block = (block_size >> chroma_sub_w) * (block_size >> chroma_sub_h);
2082
0
                        svt_aom_flat_block_finder_extract_block(block_finder,
2083
0
                                                                data[c],
2084
0
                                                                w >> chroma_sub_w,
2085
0
                                                                h >> chroma_sub_h,
2086
0
                                                                stride[c],
2087
0
                                                                bx * (block_size >> chroma_sub_w) + offsx,
2088
0
                                                                by * (block_size >> chroma_sub_h) + offsy,
2089
0
                                                                plane_d,
2090
0
                                                                block_d);
2091
0
                        svt_av1_pointwise_multiply(window_function, plane, block, plane_d, block_d, pixels_per_block);
2092
0
                        svt_aom_noise_tx_forward(tx, block);
2093
0
                        svt_aom_noise_tx_filter(tx->block_size, tx->tx_block, noise_psd[c]);
2094
0
                        svt_aom_noise_tx_inverse(tx, block);
2095
2096
                        // Apply window function to the plane approximation (we will apply
2097
                        // it to the sum of plane + block when composing the results).
2098
2099
0
                        const int y_size  = (block_size >> chroma_sub_h);
2100
0
                        const int x_size  = (block_size >> chroma_sub_w);
2101
0
                        float* result_ptr = result + ((by + 1) * y_size + offsy) * result_stride + (bx + 1) * x_size +
2102
0
                            offsx;
2103
0
                        svt_av1_apply_window_function_to_plane(
2104
0
                            y_size, x_size, result_ptr, result_stride, block, plane, window_function);
2105
0
                    }
2106
0
                }
2107
0
            }
2108
0
        }
2109
0
        if (use_highbd) {
2110
0
            dither_and_quantize_highbd(result,
2111
0
                                       result_stride,
2112
0
                                       (uint16_t*)denoised[c],
2113
0
                                       w,
2114
0
                                       h,
2115
0
                                       stride[c],
2116
0
                                       chroma_sub_w,
2117
0
                                       chroma_sub_h,
2118
0
                                       block_size,
2119
0
                                       k_block_normalization);
2120
0
        } else {
2121
0
            dither_and_quantize_lowbd(result,
2122
0
                                      result_stride,
2123
0
                                      denoised[c],
2124
0
                                      w,
2125
0
                                      h,
2126
0
                                      stride[c],
2127
0
                                      chroma_sub_w,
2128
0
                                      chroma_sub_h,
2129
0
                                      block_size,
2130
0
                                      k_block_normalization);
2131
0
        }
2132
0
    }
2133
0
    free(result);
2134
0
    free(plane);
2135
0
    svt_aom_free(block);
2136
0
    free(plane_d);
2137
0
    free(block_d);
2138
2139
0
    svt_aom_noise_tx_free(tx_full);
2140
2141
0
    svt_aom_flat_block_finder_free(&block_finder_full);
2142
0
    if (chroma_sub[0] != 0) {
2143
0
        svt_aom_flat_block_finder_free(&block_finder_chroma);
2144
0
        svt_aom_noise_tx_free(tx_chroma);
2145
0
    }
2146
0
    return init_success;
2147
0
}
2148
2149
0
static void denoise_and_model_dctor(EbPtr p) {
2150
0
    AomDenoiseAndModel* obj = (AomDenoiseAndModel*)p;
2151
2152
0
    free(obj->flat_blocks);
2153
0
    for (int32_t i = 0; i < 3; ++i) {
2154
0
        EB_FREE_ARRAY(obj->denoised[i]);
2155
0
        EB_FREE_ARRAY(obj->packed[i]);
2156
0
    }
2157
0
    svt_aom_noise_model_free(&obj->noise_model);
2158
0
    svt_aom_flat_block_finder_free(&obj->flat_block_finder);
2159
0
}
2160
2161
0
EbErrorType svt_aom_denoise_and_model_ctor(AomDenoiseAndModel* object_ptr, EbPtr object_init_data_ptr) {
2162
0
    DenoiseAndModelInitData* init_data_ptr = (DenoiseAndModelInitData*)object_init_data_ptr;
2163
0
    EbErrorType              return_error  = EB_ErrorNone;
2164
0
    uint32_t                 use_highbd    = init_data_ptr->encoder_bit_depth > EB_EIGHT_BIT ? 1 : 0;
2165
0
    ResolutionRange          input_resolution;
2166
2167
0
    int32_t chroma_sub_log2[2] = {1, 1}; //todo: send chroma subsampling
2168
0
    chroma_sub_log2[0]         = (init_data_ptr->encoder_color_format == EB_YUV444 ? 0 : 1);
2169
0
    chroma_sub_log2[1]         = (init_data_ptr->encoder_color_format >= EB_YUV422 ? 0 : 1);
2170
2171
0
    object_ptr->dctor = denoise_and_model_dctor;
2172
2173
0
    const uint32_t input_size = init_data_ptr->width * init_data_ptr->height;
2174
0
    svt_aom_derive_input_resolution(&input_resolution, input_size);
2175
2176
0
    int32_t denoise_block_size = 32;
2177
0
    if (init_data_ptr->adaptive_film_grain) {
2178
0
        if (input_resolution <= INPUT_SIZE_1080p_RANGE) {
2179
0
            denoise_block_size = 8;
2180
0
        } else if (input_resolution <= INPUT_SIZE_4K_RANGE) {
2181
0
            denoise_block_size = 16;
2182
0
        }
2183
0
    }
2184
2185
0
    object_ptr->block_size  = denoise_block_size;
2186
0
    object_ptr->noise_level = (float)(init_data_ptr->noise_level / 10.0);
2187
0
    object_ptr->bit_depth   = init_data_ptr->encoder_bit_depth > EB_EIGHT_BIT ? 10 : 8;
2188
2189
0
    object_ptr->width     = init_data_ptr->width;
2190
0
    object_ptr->height    = init_data_ptr->height;
2191
0
    object_ptr->y_stride  = init_data_ptr->y_stride;
2192
0
    object_ptr->uv_stride = init_data_ptr->u_stride;
2193
2194
    //todo: consider replacing with EbPictureBuffersDesc
2195
2196
0
    EB_CALLOC_ARRAY(object_ptr->denoised[0], (object_ptr->y_stride * object_ptr->height) << use_highbd);
2197
0
    EB_CALLOC_ARRAY(object_ptr->denoised[1],
2198
0
                    (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])) << use_highbd);
2199
0
    EB_CALLOC_ARRAY(object_ptr->denoised[2],
2200
0
                    (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])) << use_highbd);
2201
2202
0
    if (use_highbd) {
2203
0
        EB_CALLOC_ARRAY(object_ptr->packed[0], (object_ptr->y_stride * object_ptr->height));
2204
0
        EB_CALLOC_ARRAY(object_ptr->packed[1], (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])));
2205
0
        EB_CALLOC_ARRAY(object_ptr->packed[2], (object_ptr->uv_stride * (object_ptr->height >> chroma_sub_log2[0])));
2206
0
    }
2207
2208
0
    object_ptr->denoise_apply = init_data_ptr->denoise_apply;
2209
2210
0
    return return_error;
2211
0
}
2212
2213
static int32_t denoise_and_model_realloc_if_necessary(struct AomDenoiseAndModel* ctx, EbPictureBufferDesc* sd,
2214
                                                      int32_t use_highbd) {
2215
    const int32_t chroma_sub_log2[2] = {1, 1}; //todo: send chroma subsampling
2216
2217
    free(ctx->flat_blocks);
2218
    ctx->flat_blocks = NULL;
2219
2220
    ctx->num_blocks_w = (sd->width + ctx->block_size - 1) / ctx->block_size;
2221
    ctx->num_blocks_h = (sd->height + ctx->block_size - 1) / ctx->block_size;
2222
    ctx->flat_blocks  = malloc(ctx->num_blocks_w * ctx->num_blocks_h);
2223
2224
    svt_aom_flat_block_finder_free(&ctx->flat_block_finder);
2225
    if (!svt_aom_flat_block_finder_init(&ctx->flat_block_finder, ctx->block_size, ctx->bit_depth, use_highbd)) {
2226
        SVT_ERROR("Unable to init flat block finder\n");
2227
        return 0;
2228
    }
2229
2230
    const AomNoiseModelParams params = {AOM_NOISE_SHAPE_SQUARE, 3, ctx->bit_depth, use_highbd};
2231
    //  svt_aom_noise_model_free(&ctx->noise_model);
2232
    if (!svt_aom_noise_model_init(&ctx->noise_model, params)) {
2233
        SVT_ERROR("Unable to init noise model\n");
2234
        return 0;
2235
    }
2236
2237
    // Simply use a flat PSD (although we could use the flat blocks to estimate
2238
    // PSD) those to estimate an actual noise PSD)
2239
    const float y_noise_level  = svt_aom_noise_psd_get_default_value(ctx->block_size, ctx->noise_level);
2240
    const float uv_noise_level = svt_aom_noise_psd_get_default_value(ctx->block_size >> chroma_sub_log2[1],
2241
                                                                     ctx->noise_level);
2242
    ctx->noise_psd[0]          = y_noise_level;
2243
    ctx->noise_psd[1] = ctx->noise_psd[2] = uv_noise_level;
2244
    return 1;
2245
}
2246
2247
0
static void unpack_2d_pic(uint8_t* packed[3], EbPictureBufferDesc* outputPicturePtr) {
2248
0
    uint16_t luma_width    = (uint16_t)(outputPicturePtr->width);
2249
0
    uint16_t chroma_width  = luma_width >> 1;
2250
0
    uint16_t luma_height   = (uint16_t)(outputPicturePtr->height);
2251
0
    uint16_t chroma_height = luma_height >> 1;
2252
2253
0
    svt_unpack_and_2bcompress((uint16_t*)(packed[0]),
2254
0
                              outputPicturePtr->y_stride,
2255
0
                              outputPicturePtr->y_buffer,
2256
0
                              outputPicturePtr->y_stride,
2257
0
                              outputPicturePtr->y_buffer_bit_inc,
2258
0
                              outputPicturePtr->y_stride_bit_inc >> 2,
2259
0
                              luma_width,
2260
0
                              luma_height);
2261
2262
0
    svt_unpack_and_2bcompress((uint16_t*)(packed[1]),
2263
0
                              outputPicturePtr->u_stride,
2264
0
                              outputPicturePtr->u_buffer,
2265
0
                              outputPicturePtr->u_stride,
2266
0
                              outputPicturePtr->u_buffer_bit_inc,
2267
0
                              outputPicturePtr->u_stride_bit_inc >> 2,
2268
0
                              chroma_width,
2269
0
                              chroma_height);
2270
2271
0
    svt_unpack_and_2bcompress((uint16_t*)(packed[2]),
2272
0
                              outputPicturePtr->v_stride,
2273
0
                              outputPicturePtr->v_buffer,
2274
0
                              outputPicturePtr->v_stride,
2275
0
                              outputPicturePtr->v_buffer_bit_inc,
2276
0
                              outputPicturePtr->v_stride_bit_inc >> 2,
2277
0
                              chroma_width,
2278
0
                              chroma_height);
2279
0
}
2280
2281
int32_t svt_aom_denoise_and_model_run(struct AomDenoiseAndModel* ctx, EbPictureBufferDesc* sd, AomFilmGrain* film_grain,
2282
0
                                      int32_t use_highbd) {
2283
0
    const int32_t block_size = ctx->block_size;
2284
0
    uint8_t*      raw_data[3];
2285
0
    int32_t       chroma_sub_log2[2] = {1, 1}; //todo: send chroma subsampling
2286
0
    int32_t       strides[3]         = {sd->y_stride, sd->u_stride, sd->v_stride};
2287
2288
0
    if (!denoise_and_model_realloc_if_necessary(ctx, sd, use_highbd)) {
2289
0
        SVT_ERROR("Unable to realloc buffers\n");
2290
0
        return 0;
2291
0
    }
2292
2293
0
    if (!use_highbd) { // 8 bits input
2294
0
        raw_data[0] = sd->y_buffer;
2295
0
        raw_data[1] = sd->u_buffer;
2296
0
        raw_data[2] = sd->v_buffer;
2297
0
    } else { // 10 bits input
2298
0
        svt_aom_pack_2d_pic(sd, ctx->packed);
2299
2300
0
        raw_data[0] = (uint8_t*)(ctx->packed[0]);
2301
0
        raw_data[1] = (uint8_t*)(ctx->packed[1]);
2302
0
        raw_data[2] = (uint8_t*)(ctx->packed[2]);
2303
0
    }
2304
2305
0
    const uint8_t* const data[3] = {raw_data[0], raw_data[1], raw_data[2]};
2306
2307
0
    svt_aom_flat_block_finder_run(
2308
0
        &ctx->flat_block_finder, data[0], sd->width, sd->height, strides[0], ctx->flat_blocks);
2309
2310
0
    if (!svt_aom_wiener_denoise_2d(data,
2311
0
                                   ctx->denoised,
2312
0
                                   sd->width,
2313
0
                                   sd->height,
2314
0
                                   strides,
2315
0
                                   chroma_sub_log2,
2316
0
                                   ctx->noise_psd,
2317
0
                                   block_size,
2318
0
                                   ctx->bit_depth,
2319
0
                                   use_highbd)) {
2320
0
        SVT_ERROR("Unable to denoise image\n");
2321
0
        return 0;
2322
0
    }
2323
2324
0
    const AomNoiseStatus status = noise_model_update(&ctx->noise_model,
2325
0
                                                     data,
2326
0
                                                     (const uint8_t* const*)ctx->denoised,
2327
0
                                                     sd->width,
2328
0
                                                     sd->height,
2329
0
                                                     strides,
2330
0
                                                     chroma_sub_log2,
2331
0
                                                     ctx->flat_blocks,
2332
0
                                                     block_size);
2333
2334
0
    int32_t have_noise_estimate = 0;
2335
0
    if (status == AOM_NOISE_STATUS_OK || status == AOM_NOISE_STATUS_DIFFERENT_NOISE_TYPE) {
2336
0
        svt_aom_noise_model_save_latest(&ctx->noise_model);
2337
0
        have_noise_estimate = 1;
2338
0
    }
2339
2340
0
    film_grain->apply_grain = 0;
2341
0
    if (have_noise_estimate) {
2342
0
        if (!svt_aom_noise_model_get_grain_parameters(&ctx->noise_model, film_grain)) {
2343
0
            SVT_ERROR("Unable to get grain parameters.\n");
2344
0
            return 0;
2345
0
        }
2346
0
        film_grain->apply_grain = 1;
2347
2348
0
        if (ctx->denoise_apply) {
2349
0
            if (!use_highbd) {
2350
0
                SVT_MEMCPY(raw_data[0], ctx->denoised[0], (strides[0] * sd->height) << use_highbd);
2351
0
                SVT_MEMCPY(
2352
0
                    raw_data[1], ctx->denoised[1], (strides[1] * (sd->height >> chroma_sub_log2[0])) << use_highbd);
2353
0
                SVT_MEMCPY(
2354
0
                    raw_data[2], ctx->denoised[2], (strides[2] * (sd->height >> chroma_sub_log2[0])) << use_highbd);
2355
0
            } else {
2356
0
                unpack_2d_pic(ctx->denoised, sd);
2357
0
            }
2358
0
        }
2359
0
    }
2360
0
    svt_aom_flat_block_finder_free(&ctx->flat_block_finder);
2361
0
    svt_aom_noise_model_free(&ctx->noise_model);
2362
0
    free(ctx->flat_blocks);
2363
0
    ctx->flat_blocks = NULL;
2364
2365
0
    return 1;
2366
0
}
2367
#endif