Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
coefficient_field.h
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#pragma once
20
21// Coefficient-field colour-line transport + HF-refit stage (CPU + OpenCL).
22// Public API of this highlights harmonic-transposition module (a compiled TU). Include
23// this header to call into the module; internals are static in the .c. See common.h.
24
25#include "common/opencl.h"
27#include <stdint.h>
28
29// Single-plane convenience wrapper (isotropic callers and lone planes).
30void _cf_harmonic_fill(float *const restrict val, const uint8_t *const restrict hole, const int region_w,
31 const int region_h, const int base_ds, const float *const restrict steer,
32 const dt_dev_pixelpipe_t *pipe);
33
34// ===== coefficient-field reconstruction (see the DT_HL_COEFF_FIELD macro comment) =====
35// MATHS BRIDGE -- article "The algorithm" step 3, "The coefficient field". The windowed weighted
36// least squares (a,b,d)(x) = argmin_{a,b,d} Sum_y w(y) G_sigma(x-y) (v(y) - a u1(y) - b u2(y) - d)^2,
37// with v the clipped channel, u1/u2 its two guides, w the trust mask (all channels valid), and
38// G_sigma a Gaussian window at a single scale sigma = clip(r/6, 8, 64). The evaluation is
39// v_hat(x) = a(x) u1(x) + b(x) u2(x) + d(x). Rather than solve per pixel, this fits from TEN blurred
40// moment planes (1 trusted-mass count + 3 means + 6 second moments, gathered in three 4-channel
41// Gaussian blurs) through the 2x2 normal equations, then TRANSPORTS the coefficient planes into the
42// hole with _cf_harmonic_fill (E_transport) before evaluating against the measured guides.
43// This block owns the whole fit+transport+evaluation; the HF-refit, self-dome and core stages follow.
44void _cf_reconstruct(_hl_region_ctx_t *const ctx);
45
46#ifdef HAVE_OPENCL
47
48// Single-plane convenience wrapper (isotropic callers and lone planes).
49cl_int _cf_harmonic_fill_cl(const int devid, void *gd_void, cl_mem val, cl_mem hole, const int region_w,
50 const int region_h, const int base_ds, const int mask_is_hole, cl_mem steer);
51
52// ---- coefficient-field JOINT stage on the GPU (pattern-setter for the per-pixel port) ----
53// One "fit clipped channel c from the two guides g1/g2" pass: fit the colour-line coefficients
54// per pixel from the pre-blurred windowed moments (local means and channel-product averages),
55// harmonically diffuse the coefficient fields across the clipped zone, then evaluate the
56// prediction against the measured guides and write the result into est (also updating the
57// fit-quality score bsc).
58// est/vld/bsc are float4 buffers (rn * 4); moments go through image2d for the CL blur; the
59// diffused coefficients live in single-channel buffers feeding _cf_harmonic_fill_cl.
60// Mirrors the joint coefficient-field stage inside _region_guided_filter (CPU): any change here
61// must be mirrored there and re-validated with the HL_CFCL_TEST self-tests
62// (_cf_joint_stage_cl_selftest / _cf_stage_cl_selftest).
63//
64// MATHS BRIDGE -- article "The algorithm" step 3, one two-guide colour-line: fit (a,b,d) at every pixel
65// from the blurred moments through the 2x2 normal equations (hl_cf_fit_joint), transport the coefficient
66// planes with the E_transport fill (_cf_harmonic_fill_cl), then evaluate v_hat = a*u1 + b*u2 + d against
67// the measured guides (hl_cf_eval_joint). R^2 is diffused as a fourth plane on the broader anchor mask.
68cl_int _cf_joint_stage_cl(const int devid, void *gd_void, cl_mem estimate, cl_mem valid, cl_mem model_quality,
69 cl_mem mom0, cl_mem mom1, cl_mem mom2, cl_mem steer,
70 const float *const restrict channel_means, const int region_w, const int region_h,
71 const float cf_sigma, const float cf_fmin, const int c, const int guide1,
72 const int guide2);
73
74// The COMPLETE coefficient-field stage on the GPU: joint fits (predict each clipped channel
75// from the other two) with the deep channel deferred, pair fallbacks (single-guide fits),
76// then the deferred deep-channel evaluation with the depth-split blend. cdeep is the channel
77// with the most clipped pixels (host-side decision from region metadata); it is evaluated
78// last so its guides are already reconstructed.
79// Inputs: est (working red/green/blue/norm pixels), vld (validity mask), bsc (fit-quality
80// score), lsb (frozen brightness plane for the fit weights); all float4 device buffers.
81// Mirrors the coefficient-field stage of _region_guided_filter (CPU): any change here must be
82// mirrored there and re-validated with the HL_CFCL_TEST self-tests (_cf_stage_cl_selftest).
83//
84// MATHS BRIDGE -- article "The algorithm" step 3 end to end, the GPU driver of the coefficient field:
85// pack + Gaussian-blur the ten windowed moment planes ONCE (three 4-channel blurs via hl_cf_pack_joint),
86// run the two-guide joint fits (deep channel deferred), the single-guide pair fallbacks, then the
87// deferred deep-channel evaluation with the depth-split blend. sigma = clip(r/6, 8, 64), fit windows
88// weighted by w = [all valid] * soft occlusion weight (cf_binv); moments centred on channel_means to
89// avoid the E[u^2]-E[u]^2 float cancellation.
90cl_int _cf_stage_cl(const int devid, void *gd_void, cl_mem estimate, cl_mem valid, cl_mem model_quality,
91 cl_mem luminance, cl_mem steer, const float *const restrict channel_means,
92 dt_gaussian_cl_t *gaussian, const int region_w, const int region_h, const float cf_sigma,
93 const float cf_fmin, const float cf_binv, const int cdeep);
94
95// High-frequency (detail band) hybrid stage on the GPU: one lowpass blur of estimate (the detail
96// band is estimate minus this lowpass), windowed moments of the detail band, per-channel gains
97// shrunk by the fit quality (chan_a weak colour-line must not print the guides' fine texture),
98// gains diffused across the clipped zone, minimum-energy blend of guided resynthesis vs the
99// damped detail at strict targets, damped-only treatment at single-guide pixels.
100// Mirrors the DT_HL_HF_GUIDE block of _region_guided_filter (CPU): any change here must be
101// mirrored there and re-validated with the HL_HFCL_TEST self-test (_hf_stage_cl_selftest).
102//
103// MATHS BRIDGE -- Step 4 (HF refit), article §"Hybrid Laplacian-band guiding of the high frequencies"
104// / §"Rebuild the high frequencies": split estimate at sigma/4 into low band ubar (lowpass) and detail
105// u - ubar; fit the detail band's OWN colour-line with R^2-shrunk gains (hl_hf_fit: gain *= R^2, the
106// correct shrinkage on a zero-mean band), transport the gains with the E_transport fill, then blend the
107// guided resynthesis h_g = a(u_g1-ubar_g1)+b(u_g2-ubar_g2) against the R^2-damped transfer
108// h_d = R^2 (u_c - ubar_c) by quadratic min-energy odds w = e_d^2/(e_d^2 + e_g^2), e_{d,g} = blurred
109// |HF| (hl_hf_energy + hl_hf_eval) -- a guide misfire spikes e_g so the damped path self-selects.
110// Single-guide pixels keep only the damped detail (hl_hf_damp). The band split blurs at sigma/4 (floored
111// at 2 px) while the moments blur at the fit's cf_sigma -- the two scales are deliberately different.
112cl_int _hf_stage_cl(const int devid, void *gd_void, cl_mem estimate, cl_mem valid, cl_mem model_quality,
113 cl_mem luminance, cl_mem steer, dt_gaussian_cl_t *gaussian, const int region_w,
114 const int region_h, const float cf_sigma, const float cf_fmin, const float cf_binv);
115
116#endif // HAVE_OPENCL
void _cf_reconstruct(_hl_region_ctx_t *const ctx)
cl_int _cf_stage_cl(const int devid, void *gd_void, cl_mem estimate, cl_mem valid, cl_mem model_quality, cl_mem luminance, cl_mem steer, const float *const restrict channel_means, dt_gaussian_cl_t *gaussian, const int region_w, const int region_h, const float cf_sigma, const float cf_fmin, const float cf_binv, const int cdeep)
cl_int _cf_harmonic_fill_cl(const int devid, void *gd_void, cl_mem val, cl_mem hole, const int region_w, const int region_h, const int base_ds, const int mask_is_hole, cl_mem steer)
cl_int _cf_joint_stage_cl(const int devid, void *gd_void, cl_mem estimate, cl_mem valid, cl_mem model_quality, cl_mem mom0, cl_mem mom1, cl_mem mom2, cl_mem steer, const float *const restrict channel_means, const int region_w, const int region_h, const float cf_sigma, const float cf_fmin, const int c, const int guide1, const int guide2)
void _cf_harmonic_fill(float *const restrict val, const uint8_t *const restrict hole, const int region_w, const int region_h, const int base_ds, const float *const restrict steer, const dt_dev_pixelpipe_t *pipe)
cl_int _hf_stage_cl(const int devid, void *gd_void, cl_mem estimate, cl_mem valid, cl_mem model_quality, cl_mem luminance, cl_mem steer, dt_gaussian_cl_t *gaussian, const int region_w, const int region_h, const float cf_sigma, const float cf_fmin, const float cf_binv)
static float gaussian(float x, float std)
Definition filmic.c:397
float *const restrict luminance