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 This file is part of darktable,
3 Copyright (C) 2019 Aurélien PIERRE.
4 Copyright (C) 2019 luzpaz.
5 Copyright (C) 2019-2020 Pascal Obry.
6 Copyright (C) 2020 Diederik Ter Rahe.
7 Copyright (C) 2022 Martin Bařinka.
8 Copyright (C) 2022 Sakari Kapanen.
9
10 darktable is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 darktable is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with darktable. If not, see <http://www.gnu.org/licenses/>.
22*/
23#include <assert.h>
24#include <math.h>
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <time.h>
29
30#include "common/darktable.h"
32
33
34/* NOTE: this code complies with the optimizations in "common/extra_optimizations.h".
35 * Consider including that at the beginning of a *.c file where you use this
36 * header (provided the rest of the code complies).
37 **/
38
39
40#define MIN_FLOAT exp2f(-16.0f)
41
42
44{
45 DT_TONEEQ_MEAN = 0, // $DESCRIPTION: "RGB average"
46 DT_TONEEQ_LIGHTNESS, // $DESCRIPTION: "HSL lightness"
47 DT_TONEEQ_VALUE, // $DESCRIPTION: "HSV value / RGB max"
48 DT_TONEEQ_NORM_1, // $DESCRIPTION: "RGB sum"
49 DT_TONEEQ_NORM_2, // $DESCRIPTION: "RGB euclidean norm")
50 DT_TONEEQ_NORM_POWER, // $DESCRIPTION: "RGB power norm"
51 DT_TONEEQ_GEOMEAN, // $DESCRIPTION: "RGB geometric mean"
54
73#ifdef _OPENMP
74#pragma omp declare simd
75#endif
76static float linear_contrast(const float pixel, const float fulcrum, const float contrast)
77{
78 // Increase the slope of the value around a fulcrum value
79 return fmaxf((pixel - fulcrum) * contrast + fulcrum, MIN_FLOAT);
80}
81
82
83#ifdef _OPENMP
84#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
85#endif
86static void pixel_rgb_mean(const float *const restrict image,
87 float *const restrict luminance,
88 const size_t k, const size_t ch,
89 const float exposure_boost,
90 const float fulcrum, const float contrast_boost)
91{
92 // mean(RGB) is the intensity
93
94 float lum = 0.0f;
95
96#ifdef _OPENMP
97#pragma omp simd reduction(+:lum) aligned(image:64)
98#endif
99 for(int c = 0; c < 3; ++c)
100 lum += image[k + c];
101
102 luminance[k / ch] = linear_contrast(exposure_boost * lum / 3.0f, fulcrum, contrast_boost);
103}
104
105
106#ifdef _OPENMP
107#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
108#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
125static void pixel_rgb_lightness(const float *const restrict image,
126 float *const restrict luminance,
127 const size_t k, const size_t ch,
128 const float exposure_boost,
129 const float fulcrum, const float contrast_boost)
130{
131 // (max(RGB) + min(RGB)) / 2 is equivalent to HSL lightness
132
133 const float max_rgb = fmaxf(fmaxf(image[k], image[k + 1]), image[k + 2]);
134 const float min_rgb = fminf(fminf(image[k], image[k + 1]), image[k + 2]);
135 luminance[k / ch] = linear_contrast(exposure_boost * (max_rgb + min_rgb) / 2.0f, fulcrum, contrast_boost);
136}
137
138#ifdef _OPENMP
139#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
140#endif
141static void pixel_rgb_norm_1(const float *const restrict image,
142 float *const restrict luminance,
143 const size_t k, const size_t ch,
144 const float exposure_boost,
145 const float fulcrum, const float contrast_boost)
146{
147 // vector norm L1
148
149 float lum = 0.0f;
150
151 #ifdef _OPENMP
152 #pragma omp simd reduction(+:lum) aligned(image:64)
153 #endif
154 for(int c = 0; c < 3; ++c)
155 lum += fabsf(image[k + c]);
156
157 luminance[k / ch] = linear_contrast(exposure_boost * lum, fulcrum, contrast_boost);
158}
159
160
161#ifdef _OPENMP
162#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
163#endif
164static void pixel_rgb_norm_2(const float *const restrict image,
165 float *const restrict luminance,
166 const size_t k, const size_t ch,
167 const float exposure_boost,
168 const float fulcrum, const float contrast_boost)
169{
170 // vector norm L2 : euclidean norm
171
172 float result = 0.0f;
173
174#ifdef _OPENMP
175#pragma omp simd aligned(image:64) reduction(+: result)
176#endif
177 for(int c = 0; c < 3; ++c) result += image[k + c] * image[k + c];
178
179 luminance[k / ch] = linear_contrast(exposure_boost * sqrtf(result), fulcrum, contrast_boost);
180}
181
182
183#ifdef _OPENMP
184#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
185#endif
186static void pixel_rgb_norm_power(const float *const restrict image,
187 float *const restrict luminance,
188 const size_t k, const size_t ch,
189 const float exposure_boost,
190 const float fulcrum, const float contrast_boost)
191{
192 // weird norm sort of perceptual. This is black magic really, but it looks good.
193
194 float numerator = 0.0f;
195 float denominator = 0.0f;
196
197#ifdef _OPENMP
198#pragma omp simd aligned(image:64) reduction(+:numerator, denominator)
199#endif
200 for(int c = 0; c < 3; ++c)
201 {
202 const float value = fabsf(image[k + c]);
203 const float RGB_square = value * value;
204 const float RGB_cubic = RGB_square * value;
205 numerator += RGB_cubic;
206 denominator += RGB_square;
207 }
208
209 luminance[k / ch] = linear_contrast(exposure_boost * numerator / denominator, fulcrum, contrast_boost);
210}
211
212#ifdef _OPENMP
213#pragma omp declare simd aligned(image, luminance:64) uniform(image, luminance)
214#endif
215static void pixel_rgb_geomean(const float *const restrict image,
216 float *const restrict luminance,
217 const size_t k, const size_t ch,
218 const float exposure_boost,
219 const float fulcrum, const float contrast_boost)
220{
221 // geometric_mean(RGB). Kind of interesting for saturated colours (maps them to shadows)
222
223 float lum = 1.0f;
224
225#ifdef _OPENMP
226#pragma omp simd aligned(image:64) reduction(*:lum)
227#endif
228 for(int c = 0; c < 3; ++c)
229 {
230 lum *= fabsf(image[k + c]);
231 }
232
233 luminance[k / ch] = linear_contrast(exposure_boost * powf(lum, 1.0f / 3.0f), fulcrum, contrast_boost);
234}
235
236
237// Overkill trick to explicitely unswitch loops
238// GCC should to it automatically with "funswitch-loops" flag,
239// but not sure about Clang
240#ifdef _OPENMP
241 #define LOOP(fn) \
242 { \
243 _Pragma ("omp parallel for simd default(none) schedule(static) \
244 dt_omp_firstprivate(num_elem, ch, in, out, exposure_boost, fulcrum, contrast_boost)\
245 aligned(in, out:64)" ) \
246 for(size_t k = 0; k < num_elem; k += ch) \
247 { \
248 fn(in, out, k, ch, exposure_boost, fulcrum, contrast_boost); \
249 } \
250 break; \
251 }
252#else
253 #define LOOP(fn) \
254 { \
255 for(size_t k = 0; k < num_elem; k += ch) \
256 { \
257 fn(in, out, k, ch, exposure_boost, fulcrum, contrast_boost); \
258 } \
259 break; \
260 }
261#endif
262
263
265static inline void luminance_mask(const float *const restrict in, float *const restrict out,
266 const size_t width, const size_t height, const size_t ch,
268 const float exposure_boost,
269 const float fulcrum, const float contrast_boost)
270{
271 const size_t num_elem = width * height * ch;
272 switch(method)
273 {
274 case DT_TONEEQ_MEAN:
276
279
280 case DT_TONEEQ_VALUE:
282
283 case DT_TONEEQ_NORM_1:
285
286 case DT_TONEEQ_NORM_2:
288
291
294
295 default:
296 break;
297 }
298}
299
300
301// clang-format off
302// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
303// vim: shiftwidth=2 expandtab tabstop=2 cindent
304// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
305// clang-format on
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const float c
Definition colorspaces_inline_conversions.h:1365
static const dt_colormatrix_t dt_aligned_pixel_t out
Definition colorspaces_inline_conversions.h:184
#define __DT_CLONE_TARGETS__
Definition darktable.h:291
static const dt_aligned_pixel_simd_t value
Definition darktable.h:501
static 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:215
dt_iop_luminance_mask_method_t
Definition luminance_mask.h:44
@ DT_TONEEQ_NORM_2
Definition luminance_mask.h:49
@ DT_TONEEQ_MEAN
Definition luminance_mask.h:45
@ DT_TONEEQ_LIGHTNESS
Definition luminance_mask.h:46
@ DT_TONEEQ_LAST
Definition luminance_mask.h:52
@ DT_TONEEQ_VALUE
Definition luminance_mask.h:47
@ DT_TONEEQ_NORM_1
Definition luminance_mask.h:48
@ DT_TONEEQ_GEOMEAN
Definition luminance_mask.h:51
@ DT_TONEEQ_NORM_POWER
Definition luminance_mask.h:50
static 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:86
static 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:141
static 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:125
static float linear_contrast(const float pixel, const float fulcrum, const float contrast)
Definition luminance_mask.h:76
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:265
#define MIN_FLOAT
Definition luminance_mask.h:40
static 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
#define LOOP(fn)
Definition luminance_mask.h:253
static 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:164
static 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:186