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#pragma once
31
32// edge-avoiding wavelet:
33#define gweight(i, j, ii, jj) \
34 1.0 / (fabsf(weight_a[l][(size_t)wd * ((j) >> (l - 1)) + ((i) >> (l - 1))] \
35 - weight_a[l][(size_t)wd * ((jj) >> (l - 1)) + ((ii) >> (l - 1))]) + 1.e-5)
36// #define gweight(i, j, ii, jj) 1.0/(powf(fabsf(weight_a[l][wd*((j)>>(l-1)) + ((i)>>(l-1))] -
37// weight_a[l][wd*((jj)>>(l-1)) + ((ii)>>(l-1))]),0.8)+1.e-5)
38// std cdf(2,2) wavelet:
39// #define gweight(i, j, ii, jj) (wd ? 1.0 : 1.0) //1.0
40#define gbuf(BUF, A, B) ((BUF)[4 * ((size_t)width * ((B)) + ((A))) + ch])
41
42
43static int dt_iop_equalizer_wtf(float *const buf, float **weight_a, const int l, const int width, const int height)
44{
45 const int wd = (int)(1 + (width >> (l - 1))), ht = (int)(1 + (height >> (l - 1)));
46 int ch = 0;
47 // store weights for luma channel only, chroma uses same basis.
48 for(int j = 0; j < ht - 1; j++)
49 {
50 for(int i = 0; i < wd - 1; i++) weight_a[l][(size_t)j * wd + i] = gbuf(buf, i << (l - 1), j << (l - 1));
51 weight_a[l][j * wd + (wd - 1)] = 0.0f; // zero out right-most column
52 }
53 for(int i = 0; i < wd; i++) // zero out the bottom row
54 weight_a[l][(ht-1) * wd + i] = 0.0f;
55
56 const int step = 1 << l;
57 const int st = step / 2;
58
59 size_t scratch_size;
60 float *const restrict tmp_width_buf = dt_pixelpipe_cache_alloc_perthread_float(width, &scratch_size);
61 if(tmp_width_buf == NULL) return 1;
62
63#ifdef _OPENMP
64#pragma omp parallel for default(none) \
65 dt_omp_firstprivate(height, l, st, step, tmp_width_buf, scratch_size, wd, width) \
66 dt_omp_sharedconst(buf) \
67 shared(weight_a) \
68 private(ch) \
69 schedule(static)
70#endif
71 for(int j = 0; j < height; j++)
72 {
73 // rows
74 // precompute weights:
75 float *tmp = dt_get_perthread(tmp_width_buf, scratch_size);
76 for(int i = 0; i < width - st; i += st) tmp[i] = gweight(i, j, i + st, j);
77 // predict, get detail
78 int i = st;
79 for(; i < width - st; i += step)
80 for(ch = 0; ch < 3; ch++)
81 gbuf(buf, i, j) -= (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
82 / (tmp[i - st] + tmp[i]);
83 if(i < width)
84 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i - st, j);
85 // update coarse
86 for(ch = 0; ch < 3; ch++) gbuf(buf, 0, j) += gbuf(buf, st, j) * 0.5f;
87 for(i = step; i < width - st; i += step)
88 for(ch = 0; ch < 3; ch++)
89 gbuf(buf, i, j) += (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
90 / (2.0 * (tmp[i - st] + tmp[i]));
91 if(i < width)
92 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i - st, j) * .5f;
93 }
94
95 dt_pixelpipe_cache_free_align(tmp_width_buf);
96
97 float *const restrict tmp_height_buf = dt_pixelpipe_cache_alloc_perthread_float(height, &scratch_size);
98 if(tmp_height_buf == NULL) return 1;
99
100#ifdef _OPENMP
101#pragma omp parallel for default(none) \
102 dt_omp_firstprivate(height, l, st, step, tmp_height_buf, scratch_size, wd, width) \
103 dt_omp_sharedconst(buf) \
104 shared(weight_a) \
105 private(ch) \
106 schedule(static)
107#endif
108 for(int i = 0; i < width; i++)
109 {
110 // cols
111 // precompute weights:
112 float *const tmp = dt_get_perthread(tmp_height_buf, scratch_size);
113 for(int j = 0; j < height - st; j += st) tmp[j] = gweight(i, j, i, j + st);
114 int j = st;
115 // predict, get detail
116 for(; j < height - st; j += step)
117 for(ch = 0; ch < 3; ch++)
118 gbuf(buf, i, j) -= (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
119 / (tmp[j - st] + tmp[j]);
120 if(j < height)
121 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i, j - st);
122 // update
123 for(ch = 0; ch < 3; ch++) gbuf(buf, i, 0) += gbuf(buf, i, st) * 0.5;
124 for(j = step; j < height - st; j += step)
125 for(ch = 0; ch < 3; ch++)
126 gbuf(buf, i, j) += (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
127 / (2.0 * (tmp[j - st] + tmp[j]));
128 if(j < height)
129 for(ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i, j - st) * .5f;
130 }
131
132 dt_pixelpipe_cache_free_align(tmp_height_buf);
133 return 0;
134}
135
136static int dt_iop_equalizer_iwtf(float *buf, float **weight_a, const int l, const int width, const int height)
137{
138 const int step = 1 << l;
139 const int st = step / 2;
140 const int wd = (int)(1 + (width >> (l - 1)));
141
142 size_t scratch_size;
143 float *const restrict tmp_height_buf = dt_pixelpipe_cache_alloc_perthread_float(height, &scratch_size);
144 if(tmp_height_buf == NULL) return 1;
145
146#ifdef _OPENMP
147#pragma omp parallel for default(none) \
148 dt_omp_firstprivate(height, l, st, step, tmp_height_buf, scratch_size, wd, width) \
149 shared(weight_a, buf) \
150 schedule(static)
151#endif
152 for(int i = 0; i < width; i++)
153 {
154 // cols
155 float *const restrict tmp = dt_get_perthread(tmp_height_buf, scratch_size);
156 int j;
157 for(j = 0; j < height - st; j += st) tmp[j] = gweight(i, j, i, j + st);
158 // update coarse
159 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, 0) -= gbuf(buf, i, st) * 0.5f;
160 for(j = step; j < height - st; j += step)
161 for(int ch = 0; ch < 3; ch++)
162 gbuf(buf, i, j) -= (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
163 / (2.0 * (tmp[j - st] + tmp[j]));
164 if(j < height)
165 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i, j - st) * .5f;
166 // predict
167 for(j = st; j < height - st; j += step)
168 for(int ch = 0; ch < 3; ch++)
169 gbuf(buf, i, j) += (tmp[j - st] * gbuf(buf, i, j - st) + tmp[j] * gbuf(buf, i, j + st))
170 / (tmp[j - st] + tmp[j]);
171 if(j < height)
172 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i, j - st);
173 }
174
175 dt_pixelpipe_cache_free_align(tmp_height_buf);
176
177 float *const restrict tmp_width_buf = dt_pixelpipe_cache_alloc_perthread_float(width, &scratch_size);
178 if(tmp_width_buf == NULL) return 1;
179
180#ifdef _OPENMP
181#pragma omp parallel for default(none) \
182 dt_omp_firstprivate(height, l, st, step, tmp_width_buf, scratch_size, wd, width) \
183 shared(weight_a, buf) \
184 schedule(static)
185#endif
186 for(int j = 0; j < height; j++)
187 {
188 // rows
189 float *const restrict tmp = dt_get_perthread(tmp_width_buf, scratch_size);
190 for(int i = 0; i < width - st; i += st) tmp[i] = gweight(i, j, i + st, j);
191 // update
192 for(int ch = 0; ch < 3; ch++) gbuf(buf, 0, j) -= gbuf(buf, st, j) * 0.5f;
193 int i;
194 for(i = step; i < width - st; i += step)
195 for(int ch = 0; ch < 3; ch++)
196 gbuf(buf, i, j) -= (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
197 / (2.0 * (tmp[i - st] + tmp[i]));
198 if(i < width)
199 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) -= gbuf(buf, i - st, j) * 0.5f;
200 // predict
201 for(i = st; i < width - st; i += step)
202 for(int ch = 0; ch < 3; ch++)
203 gbuf(buf, i, j) += (tmp[i - st] * gbuf(buf, i - st, j) + tmp[i] * gbuf(buf, i + st, j))
204 / (tmp[i - st] + tmp[i]);
205 if(i < width)
206 for(int ch = 0; ch < 3; ch++) gbuf(buf, i, j) += gbuf(buf, i - st, j);
207 }
208
209 dt_pixelpipe_cache_free_align(tmp_width_buf);
210 return 0;
211}
212
213#undef gbuf
214#undef gweight
215// clang-format off
216// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
217// vim: shiftwidth=2 expandtab tabstop=2 cindent
218// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
219// clang-format on
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const float i
Definition colorspaces_inline_conversions.h:669
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:377
#define dt_get_perthread(buf, padsize)
Definition darktable.h:967
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
Definition darktable.h:962
#define gweight(i, j, ii, jj)
Definition equalizer_eaw.h:33
static int dt_iop_equalizer_wtf(float *const buf, float **weight_a, const int l, const int width, const int height)
Definition equalizer_eaw.h:43
#define gbuf(BUF, A, B)
Definition equalizer_eaw.h:40
static int dt_iop_equalizer_iwtf(float *buf, float **weight_a, const int l, const int width, const int height)
Definition equalizer_eaw.h:136