Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
knee.h
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4 Copyright (C) 2026 Guillaume Stutin.
5
6 Ansel is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Ansel is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with darktable. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef DT_IOP_HIGHLIGHTS_KNEE_H
21#define DT_IOP_HIGHLIGHTS_KNEE_H
22
23// R9 sensor-rolloff (knee) estimation and inversion (CPU + OpenCL).
24// Public API of this highlights harmonic-transposition module (a compiled TU). Include
25// this header to call into the module; internals are static in the .c. See common.h.
26
27#include "pixel/gaussian.h"
28#include "iop/highlights/blur.h"
30#include <string.h>
31
32static inline void _knee_blur(const float *const restrict in, float *const restrict out, const int width,
33 const int height, const float sigma)
34{
35 dt_gaussian_t *const gaussian = _hl_gauss_get(width, height, 1, sigma); // cached handle, do not free
36
37 if(!gaussian)
38 {
39 memcpy(out, in, (size_t)width * height * sizeof(float));
40 return;
41 }
42
44}
45
46// Step 2 (article "The algorithm", Sensor rolloff (knee) inversion): build the per-channel inverse
47// k^-1(v) = v + median{ v_hat_i - v_i | v_i in bin(v) }
48// from the image itself. v_i are the measured band pixels; v_hat_i is what a windowed colour-line
49// regression predicts each SHOULD read from its still-trusted neighbouring channels; the per-bin
50// median of the votes v_hat_i - v_i is the accepted lift.
51// Works on the RAW CFA `input`, NOT the bilinear-demosaiced buffer: the demosaic samples each
52// channel through a different spatial filter per Bayer phase, and that alternating error is the same
53// size as the knee signal -- it decorrelates the colour-lines and kills the estimate. A 2x2 quad
54// binning of the CFA instead gives co-located R / mean-G / B per cell with no inter-site
55// interpolation (the "quad-binned copy of the raw mosaic" of the article). `clipval_raw` is the
56// clip level per channel in raw units (= clips / DET). Writes 3 curves (engaged = 0 means
57// identity). Any shortage of data or memory returns 0 with identity. Returns 1 when `pipe` abandoned
58// the run: the curves are then not to be used.
59int _hl_knee_estimate(const float *const restrict input, const size_t width, const size_t height,
60 const uint32_t filters, const dt_iop_roi_t *const roi_in, const uint8_t (*const xtrans)[6],
61 const dt_aligned_pixel_t clipval_raw, _hl_knee_curve_t curves[3],
63
64// Step 2 application on the demosaiced [R,G,B,norm] buffer: for each engaged channel whose value
65// lies in the band, replace v by k^-1(v) = v + L(v). Keeps the norm channel consistent with the
66// corrected raw RGB (the "correction applied to the reconstruction anchors" of the article).
67void _hl_knee_apply_interpolated(float *const restrict interpolated, const size_t npix,
68 const dt_aligned_pixel_t clipvaln, const dt_aligned_pixel_t wb4,
69 const _hl_knee_curve_t curves[3]);
70
71// Apply the engaged curves to a CFA copy (raw units) so the final composition hands the corrected
72// band values to the output; unclipped/clipped values pass through untouched.
73void _hl_knee_apply_cfa(const float *const restrict input, float *const restrict input_corr, const size_t width,
74 const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in,
75 const uint8_t (*const xtrans)[6], const dt_aligned_pixel_t clipval_raw,
76 const _hl_knee_curve_t curves[3]);
77
78#ifdef HAVE_OPENCL
79// Step 2 (article "The algorithm", knee inversion) on the GPU: build the per-channel inverse
80// k^-1(v) = v + median{ v_hat_i - v_i | v_i in bin(v) },
81// v_hat from a windowed colour-line regression v_hat = a*u1 + b*u2 + d (joint) or a*u + d (single).
82// GPU knee estimation (sensor saturation-rolloff curve, see the DT_HL_KNEE macro comment):
83// the device runs Phase A (colour-filter-array binning, the 5-sigma windowed moment blurs --
84// packed 4 planes per gaussian pass -- and the colour-line regressions producing v_hat/R^2); the
85// host keeps Phase B (vote medians + significance gate + monotone curve fit) on the downloaded
86// BINNED planes (<= 1.5 Mpx grid, x/pred/r2s/done only). The full-res raw mosaic never crosses the
87// bus. Mirrors _hl_knee_estimate on the CPU: any change here must be mirrored there and
88// re-validated with the HL_KNEECL_TEST self-test (_knee_cl_selftest).
89cl_int _hl_knee_estimate_cl(const int devid, void *gd_void, cl_mem dev_in, const size_t width, const size_t height,
90 const uint32_t filters, const dt_iop_roi_t *const roi_in, cl_mem dev_xtrans,
91 const int is_xtrans, const dt_aligned_pixel_t clipval_raw, _hl_knee_curve_t curves[3],
93
94// Step 2 application on the device: replace each engaged-channel band pixel v of the raw mosaic by
95// k^-1(v) = v + L(v) (the hl_knee_apply kernel does the per-pixel curve lookup). The per-channel
96// lift[] knot arrays are flattened and uploaded; engaged flags gate which channels are corrected.
97// Mirrors _hl_knee_apply_cfa on the CPU: any change here must be mirrored there and
98// re-validated with the HL_KNEECL_TEST self-test (_knee_cl_selftest).
99cl_int _hl_knee_apply_cfa_cl(const int devid, void *gd_void, cl_mem dev_in, cl_mem dev_out, const size_t width,
100 const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in,
101 cl_mem dev_xtrans, const int is_xtrans, const dt_aligned_pixel_t clipval_raw,
102 const _hl_knee_curve_t curves[3]);
103#endif
104#endif // DT_IOP_HIGHLIGHTS_KNEE_H
dt_gaussian_t * _hl_gauss_get(const int width, const int height, const int channels, const float sigma)
Definition blur.c:28
const dt_colormatrix_t dt_aligned_pixel_t out
static float gaussian(float x, float std)
Definition filmic.c:404
__DT_CLONE_TARGETS__ void dt_gaussian_blur(dt_gaussian_t *g, const float *const in, float *const out)
Definition gaussian.c:176
void _hl_knee_apply_cfa(const float *const restrict input, float *const restrict input_corr, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6], const dt_aligned_pixel_t clipval_raw, const _hl_knee_curve_t curves[3])
Definition knee.c:565
static void _knee_blur(const float *const restrict in, float *const restrict out, const int width, const int height, const float sigma)
Definition knee.h:32
int _hl_knee_estimate(const float *const restrict input, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, const uint8_t(*const xtrans)[6], const dt_aligned_pixel_t clipval_raw, _hl_knee_curve_t curves[3], const dt_dev_pixelpipe_t *pipe)
Definition knee.c:108
void _hl_knee_apply_interpolated(float *const restrict interpolated, const size_t npix, const dt_aligned_pixel_t clipvaln, const dt_aligned_pixel_t wb4, const _hl_knee_curve_t curves[3])
Definition knee.c:527
cl_int _hl_knee_estimate_cl(const int devid, void *gd_void, cl_mem dev_in, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, cl_mem dev_xtrans, const int is_xtrans, const dt_aligned_pixel_t clipval_raw, _hl_knee_curve_t curves[3], const dt_dev_pixelpipe_t *pipe)
Definition knee.c:596
cl_int _hl_knee_apply_cfa_cl(const int devid, void *gd_void, cl_mem dev_in, cl_mem dev_out, const size_t width, const size_t height, const uint32_t filters, const dt_iop_roi_t *const roi_in, cl_mem dev_xtrans, const int is_xtrans, const dt_aligned_pixel_t clipval_raw, const _hl_knee_curve_t curves[3])
Definition knee.c:929
static const dt_dev_pixelpipe_t * pipe
Definition layers.h:49
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
const float sigma
Region of interest passed through the pixelpipe.
Definition format.h:49