Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
luminance_mask.h
Go to the documentation of this file.
1
2/*
3 This file is part of darktable,
4 Copyright (C) 2019-2020 darktable developers.
5
6 darktable 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 darktable 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#include <assert.h>
21#include <math.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <time.h>
26
27#include "common/darktable.h"
29
30
31/* NOTE: this code complies with the optimizations in "common/extra_optimizations.h".
32 * Consider including that at the beginning of a *.c file where you use this
33 * header (provided the rest of the code complies).
34 **/
35
36
37#define MIN_FLOAT exp2f(-16.0f)
38
39
41{
42 DT_TONEEQ_MEAN = 0, // $DESCRIPTION: "RGB average"
43 DT_TONEEQ_LIGHTNESS, // $DESCRIPTION: "HSL lightness"
44 DT_TONEEQ_VALUE, // $DESCRIPTION: "HSV value / RGB max"
45 DT_TONEEQ_NORM_1, // $DESCRIPTION: "RGB sum"
46 DT_TONEEQ_NORM_2, // $DESCRIPTION: "RGB euclidean norm")
47 DT_TONEEQ_NORM_POWER, // $DESCRIPTION: "RGB power norm"
48 DT_TONEEQ_GEOMEAN, // $DESCRIPTION: "RGB geometric mean"
51
70#ifdef _OPENMP
71#pragma omp declare simd
72#endif
74static float linear_contrast(const float pixel, const float fulcrum, const float contrast)
75{
76 // Increase the slope of the value around a fulcrum value
77 return fmaxf((pixel - fulcrum) * contrast + fulcrum, MIN_FLOAT);
78}
79
80
81#ifdef _OPENMP
82#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
83#endif
85static void pixel_rgb_mean(const float *const restrict image,
86 float *const restrict luminance,
87 const size_t k, const size_t ch,
88 const float exposure_boost,
89 const float fulcrum, const float contrast_boost)
90{
91 // mean(RGB) is the intensity
92
93 float lum = 0.0f;
94
95#ifdef _OPENMP
96#pragma omp simd reduction(+:lum) aligned(image:64)
97#endif
98 for(int c = 0; c < 3; ++c)
99 lum += image[k + c];
100
101 luminance[k / ch] = linear_contrast(exposure_boost * lum / 3.0f, fulcrum, contrast_boost);
102}
103
104
105#ifdef _OPENMP
106#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
107#endif
109static void pixel_rgb_value(const float *const restrict image,
110 float *const restrict luminance,
111 const size_t k, const size_t ch,
112 const float exposure_boost,
113 const float fulcrum, const float contrast_boost)
114{
115 // max(RGB) is equivalent to HSV value
116
117 const float lum = exposure_boost * fmaxf(fmaxf(image[k], image[k + 1]), image[k + 2]);
118 luminance[k / ch] = linear_contrast(lum, fulcrum, contrast_boost);
119}
120
121
122#ifdef _OPENMP
123#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
124#endif
126static void pixel_rgb_lightness(const float *const restrict image,
127 float *const restrict luminance,
128 const size_t k, const size_t ch,
129 const float exposure_boost,
130 const float fulcrum, const float contrast_boost)
131{
132 // (max(RGB) + min(RGB)) / 2 is equivalent to HSL lightness
133
134 const float max_rgb = fmaxf(fmaxf(image[k], image[k + 1]), image[k + 2]);
135 const float min_rgb = fminf(fminf(image[k], image[k + 1]), image[k + 2]);
136 luminance[k / ch] = linear_contrast(exposure_boost * (max_rgb + min_rgb) / 2.0f, fulcrum, contrast_boost);
137}
138
139#ifdef _OPENMP
140#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
141#endif
143static void pixel_rgb_norm_1(const float *const restrict image,
144 float *const restrict luminance,
145 const size_t k, const size_t ch,
146 const float exposure_boost,
147 const float fulcrum, const float contrast_boost)
148{
149 // vector norm L1
150
151 float lum = 0.0f;
152
153 #ifdef _OPENMP
154 #pragma omp simd reduction(+:lum) aligned(image:64)
155 #endif
156 for(int c = 0; c < 3; ++c)
157 lum += fabsf(image[k + c]);
158
159 luminance[k / ch] = linear_contrast(exposure_boost * lum, fulcrum, contrast_boost);
160}
161
162
163#ifdef _OPENMP
164#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
165#endif
167static void pixel_rgb_norm_2(const float *const restrict image,
168 float *const restrict luminance,
169 const size_t k, const size_t ch,
170 const float exposure_boost,
171 const float fulcrum, const float contrast_boost)
172{
173 // vector norm L2 : euclidean norm
174
175 float result = 0.0f;
176
177#ifdef _OPENMP
178#pragma omp simd aligned(image:64) reduction(+: result)
179#endif
180 for(int c = 0; c < 3; ++c) result += image[k + c] * image[k + c];
181
182 luminance[k / ch] = linear_contrast(exposure_boost * sqrtf(result), fulcrum, contrast_boost);
183}
184
185
186#ifdef _OPENMP
187#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
188#endif
190static void pixel_rgb_norm_power(const float *const restrict image,
191 float *const restrict luminance,
192 const size_t k, const size_t ch,
193 const float exposure_boost,
194 const float fulcrum, const float contrast_boost)
195{
196 // weird norm sort of perceptual. This is black magic really, but it looks good.
197
198 float numerator = 0.0f;
199 float denominator = 0.0f;
200
201#ifdef _OPENMP
202#pragma omp simd aligned(image:64) reduction(+:numerator, denominator)
203#endif
204 for(int c = 0; c < 3; ++c)
205 {
206 const float value = fabsf(image[k + c]);
207 const float RGB_square = value * value;
208 const float RGB_cubic = RGB_square * value;
209 numerator += RGB_cubic;
210 denominator += RGB_square;
211 }
212
213 luminance[k / ch] = linear_contrast(exposure_boost * numerator / denominator, fulcrum, contrast_boost);
214}
215
216#ifdef _OPENMP
217#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
218#endif
220static void pixel_rgb_geomean(const float *const restrict image,
221 float *const restrict luminance,
222 const size_t k, const size_t ch,
223 const float exposure_boost,
224 const float fulcrum, const float contrast_boost)
225{
226 // geometric_mean(RGB). Kind of interesting for saturated colours (maps them to shadows)
227
228 float lum = 1.0f;
229
230#ifdef _OPENMP
231#pragma omp simd aligned(image:64) reduction(*:lum)
232#endif
233 for(int c = 0; c < 3; ++c)
234 {
235 lum *= fabsf(image[k + c]);
236 }
237
238 luminance[k / ch] = linear_contrast(exposure_boost * powf(lum, 1.0f / 3.0f), fulcrum, contrast_boost);
239}
240
241
242// Overkill trick to explicitely unswitch loops
243// GCC should to it automatically with "funswitch-loops" flag,
244// but not sure about Clang
245#ifdef _OPENMP
246 #define LOOP(fn) \
247 { \
248 _Pragma ("omp parallel for simd default(none) schedule(static) \
249 dt_omp_firstprivate(num_elem, ch, in, out, exposure_boost, fulcrum, contrast_boost)\
250 aligned(in, out:64)" ) \
251 for(size_t k = 0; k < num_elem; k += ch) \
252 { \
253 fn(in, out, k, ch, exposure_boost, fulcrum, contrast_boost); \
254 } \
255 break; \
256 }
257#else
258 #define LOOP(fn) \
259 { \
260 for(size_t k = 0; k < num_elem; k += ch) \
261 { \
262 fn(in, out, k, ch, exposure_boost, fulcrum, contrast_boost); \
263 } \
264 break; \
265 }
266#endif
267
268
270static inline void luminance_mask(const float *const restrict in, float *const restrict out,
271 const size_t width, const size_t height, const size_t ch,
273 const float exposure_boost,
274 const float fulcrum, const float contrast_boost)
275{
276 const size_t num_elem = width * height * ch;
277 switch(method)
278 {
279 case DT_TONEEQ_MEAN:
281
284
285 case DT_TONEEQ_VALUE:
287
288 case DT_TONEEQ_NORM_1:
290
291 case DT_TONEEQ_NORM_2:
293
296
299
300 default:
301 break;
302 }
303}
304
305
306// clang-format off
307// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
308// vim: shiftwidth=2 expandtab tabstop=2 cindent
309// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
310// clang-format on
311
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
#define __DT_CLONE_TARGETS__
Definition darktable.h:249
static __DT_CLONE_TARGETS__ float linear_contrast(const float pixel, const float fulcrum, const float contrast)
Definition luminance_mask.h:74
dt_iop_luminance_mask_method_t
Definition luminance_mask.h:41
@ DT_TONEEQ_NORM_2
Definition luminance_mask.h:46
@ DT_TONEEQ_MEAN
Definition luminance_mask.h:42
@ DT_TONEEQ_LIGHTNESS
Definition luminance_mask.h:43
@ DT_TONEEQ_LAST
Definition luminance_mask.h:49
@ DT_TONEEQ_VALUE
Definition luminance_mask.h:44
@ DT_TONEEQ_NORM_1
Definition luminance_mask.h:45
@ DT_TONEEQ_GEOMEAN
Definition luminance_mask.h:48
@ DT_TONEEQ_NORM_POWER
Definition luminance_mask.h:47
static __DT_CLONE_TARGETS__ void pixel_rgb_geomean(const float *const restrict image, float *const restrict luminance, const size_t k, const size_t ch, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:220
static __DT_CLONE_TARGETS__ void pixel_rgb_lightness(const float *const restrict image, float *const restrict luminance, const size_t k, const size_t ch, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:126
static __DT_CLONE_TARGETS__ void pixel_rgb_norm_2(const float *const restrict image, float *const restrict luminance, const size_t k, const size_t ch, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:167
static __DT_CLONE_TARGETS__ void pixel_rgb_norm_1(const float *const restrict image, float *const restrict luminance, const size_t k, const size_t ch, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:143
static __DT_CLONE_TARGETS__ void luminance_mask(const float *const restrict in, float *const restrict out, const size_t width, const size_t height, const size_t ch, const dt_iop_luminance_mask_method_t method, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:270
#define MIN_FLOAT
Definition luminance_mask.h:37
static __DT_CLONE_TARGETS__ void pixel_rgb_mean(const float *const restrict image, float *const restrict luminance, const size_t k, const size_t ch, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:85
#define LOOP(fn)
Definition luminance_mask.h:258
static __DT_CLONE_TARGETS__ void pixel_rgb_norm_power(const float *const restrict image, float *const restrict luminance, const size_t k, const size_t ch, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:190
static __DT_CLONE_TARGETS__ void pixel_rgb_value(const float *const restrict image, float *const restrict luminance, const size_t k, const size_t ch, const float exposure_boost, const float fulcrum, const float contrast_boost)
Definition luminance_mask.h:109