Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
equalizer_eaw.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2011 johannes hanika.
4 Copyright (C) 2011 Henrik Andersson.
5 Copyright (C) 2012 Richard Wonka.
6 Copyright (C) 2014, 2016 Roman Lebedev.
7 Copyright (C) 2014, 2016 Tobias Ellinghaus.
8 Copyright (C) 2014 Ulrich Pegelow.
9 Copyright (C) 2019 Andreas Schneider.
10 Copyright (C) 2020 Hubert Kowalski.
11 Copyright (C) 2020-2021 Pascal Obry.
12 Copyright (C) 2021 Ralf Brown.
13 Copyright (C) 2022 Martin Bařinka.
14 Copyright (C) 2025-2026 Aurélien PIERRE.
15
16 darktable is free software: you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 darktable is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with darktable. If not, see <http://www.gnu.org/licenses/>.
28*/
29
30#ifndef DT_IOP_EQUALIZER_EAW_H
31#define DT_IOP_EQUALIZER_EAW_H
32
33// edge-avoiding wavelet:
34#define gweight(i, j, ii, jj) \
35 1.0 / (fabsf(weight_a[l][(size_t)wd * ((j) >> (l - 1)) + ((i) >> (l - 1))] \
36 - weight_a[l][(size_t)wd * ((jj) >> (l - 1)) + ((ii) >> (l - 1))]) + 1.e-5)
37// #define gweight(i, j, ii, jj) 1.0/(powf(fabsf(weight_a[l][wd*((j)>>(l-1)) + ((i)>>(l-1))] -
38// weight_a[l][wd*((jj)>>(l-1)) + ((ii)>>(l-1))]),0.8)+1.e-5)
39// std cdf(2,2) wavelet:
40// #define gweight(i, j, ii, jj) (wd ? 1.0 : 1.0) //1.0
41#define gbuf(BUF, A, B) ((BUF)[4 * ((size_t)width * ((B)) + ((A))) + ch])
42
43
44static int dt_iop_equalizer_wtf(float *const buf, float **weight_a, const int l, const int width, const int height)
45{
46 const int wd = (int)(1 + (width >> (l - 1))), ht = (int)(1 + (height >> (l - 1)));
47 int ch = 0;
48 // store weights for luma channel only, chroma uses same basis.
49 for(int j = 0; j < ht - 1; j++)
50 {
51 for(int i = 0; i < wd - 1; i++) weight_a[l][(size_t)j * wd + i] = gbuf(buf, i << (l - 1), j << (l - 1));
52 weight_a[l][j * wd + (wd - 1)] = 0.0f; // zero out right-most column
53 }
54 for(int i = 0; i < wd; i++) // zero out the bottom row
55 weight_a[l][(ht-1) * wd + i] = 0.0f;
56
57 const int step = 1 << l;
58 const int st = step / 2;
59
60 size_t scratch_size;
61 float *const restrict tmp_width_buf = dt_pixelpipe_cache_alloc_perthread_float(width, &scratch_size);
62 if(IS_NULL_PTR(tmp_width_buf)) return 1;
63 __OMP_PARALLEL_FOR__(private(ch) )
64 for(int j = 0; j < height; j++)
65 {
66 // rows
67 // precompute weights:
68 float *tmp = dt_get_perthread(tmp_width_buf, scratch_size);
69 for(int i = 0; i < width - st; i += st) tmp[i] = gweight(i, j, i + st, j);
70 // predict, get detail
71 int i = st;
72 for(; i < width - st; i += step)
73 for(ch = 0; ch < 3; ch++)
74 gbuf(buf, i, j) -= (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
75 / (tmp[i - st] + tmp[i]);
76 if(i < width)
77 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i - st, j);
78 // update coarse
79 for(ch = 0; ch < 3; ch++) gbuf(buf, 0, j) += gbuf(buf, st, j) * 0.5f;
80 for(i = step; i < width - st; i += step)
81 for(ch = 0; ch < 3; ch++)
82 gbuf(buf, i, j) += (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
83 / (2.0 * (tmp[i - st] + tmp[i]));
84 if(i < width)
85 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i - st, j) * .5f;
86 }
87
88 dt_pixelpipe_cache_free_align(tmp_width_buf);
89
90 float *const restrict tmp_height_buf = dt_pixelpipe_cache_alloc_perthread_float(height, &scratch_size);
91 if(IS_NULL_PTR(tmp_height_buf)) return 1;
92 __OMP_PARALLEL_FOR__(private(ch) )
93 for(int i = 0; i < width; i++)
94 {
95 // cols
96 // precompute weights:
97 float *const tmp = dt_get_perthread(tmp_height_buf, scratch_size);
98 for(int j = 0; j < height - st; j += st) tmp[j] = gweight(i, j, i, j + st);
99 int j = st;
100 // predict, get detail
101 for(; j < height - st; j += step)
102 for(ch = 0; ch < 3; ch++)
103 gbuf(buf, i, j) -= (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
104 / (tmp[j - st] + tmp[j]);
105 if(j < height)
106 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i, j - st);
107 // update
108 for(ch = 0; ch < 3; ch++) gbuf(buf, i, 0) += gbuf(buf, i, st) * 0.5;
109 for(j = step; j < height - st; j += step)
110 for(ch = 0; ch < 3; ch++)
111 gbuf(buf, i, j) += (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
112 / (2.0 * (tmp[j - st] + tmp[j]));
113 if(j < height)
114 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i, j - st) * .5f;
115 }
116
117 dt_pixelpipe_cache_free_align(tmp_height_buf);
118 return 0;
119}
120
121static int dt_iop_equalizer_iwtf(float *buf, float **weight_a, const int l, const int width, const int height)
122{
123 const int step = 1 << l;
124 const int st = step / 2;
125 const int wd = (int)(1 + (width >> (l - 1)));
126
127 size_t scratch_size;
128 float *const restrict tmp_height_buf = dt_pixelpipe_cache_alloc_perthread_float(height, &scratch_size);
129 if(IS_NULL_PTR(tmp_height_buf)) return 1;
131 for(int i = 0; i < width; i++)
132 {
133 // cols
134 float *const restrict tmp = dt_get_perthread(tmp_height_buf, scratch_size);
135 int j;
136 for(j = 0; j < height - st; j += st) tmp[j] = gweight(i, j, i, j + st);
137 // update coarse
138 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, 0) -= gbuf(buf, i, st) * 0.5f;
139 for(j = step; j < height - st; j += step)
140 for(int ch = 0; ch < 3; ch++)
141 gbuf(buf, i, j) -= (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
142 / (2.0 * (tmp[j - st] + tmp[j]));
143 if(j < height)
144 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i, j - st) * .5f;
145 // predict
146 for(j = st; j < height - st; j += step)
147 for(int ch = 0; ch < 3; ch++)
148 gbuf(buf, i, j) += (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
149 / (tmp[j - st] + tmp[j]);
150 if(j < height)
151 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i, j - st);
152 }
153
154 dt_pixelpipe_cache_free_align(tmp_height_buf);
155
156 float *const restrict tmp_width_buf = dt_pixelpipe_cache_alloc_perthread_float(width, &scratch_size);
157 if(IS_NULL_PTR(tmp_width_buf)) return 1;
159 for(int j = 0; j < height; j++)
160 {
161 // rows
162 float *const restrict tmp = dt_get_perthread(tmp_width_buf, scratch_size);
163 for(int i = 0; i < width - st; i += st) tmp[i] = gweight(i, j, i + st, j);
164 // update
165 for(int ch = 0; ch < 3; ch++) gbuf(buf, 0, j) -= gbuf(buf, st, j) * 0.5f;
166 int i;
167 for(i = step; i < width - st; i += step)
168 for(int ch = 0; ch < 3; ch++)
169 gbuf(buf, i, j) -= (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
170 / (2.0 * (tmp[i - st] + tmp[i]));
171 if(i < width)
172 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i - st, j) * 0.5f;
173 // predict
174 for(i = st; i < width - st; i += step)
175 for(int ch = 0; ch < 3; ch++)
176 gbuf(buf, i, j) += (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
177 / (tmp[i - st] + tmp[i]);
178 if(i < width)
179 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i - st, j);
180 }
181
182 dt_pixelpipe_cache_free_align(tmp_width_buf);
183 return 0;
184}
185
186#undef gbuf
187#undef gweight
188
189#endif // DT_IOP_EQUALIZER_EAW_H
190
191// clang-format off
192// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
193// vim: shiftwidth=2 expandtab tabstop=2 cindent
194// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
195// clang-format on
#define gweight(i, j, ii, jj)
static int dt_iop_equalizer_wtf(float *const buf, float **weight_a, const int l, const int width, const int height)
#define gbuf(BUF, A, B)
static int dt_iop_equalizer_iwtf(float *buf, float **weight_a, const int l, const int width, const int height)
float *const restrict const size_t const size_t ch
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
#define dt_pixelpipe_cache_free_align(mem)
#define dt_get_perthread(buf, padsize)
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)