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#define MIN_FLOAT exp2f(-16.0f)
35
36
38{
39 DT_TONEEQ_MEAN = 0, // $DESCRIPTION: "RGB average"
40 DT_TONEEQ_LIGHTNESS, // $DESCRIPTION: "HSL lightness"
41 DT_TONEEQ_VALUE, // $DESCRIPTION: "HSV value / RGB max"
42 DT_TONEEQ_NORM_1, // $DESCRIPTION: "RGB sum"
43 DT_TONEEQ_NORM_2, // $DESCRIPTION: "RGB euclidean norm")
44 DT_TONEEQ_NORM_POWER, // $DESCRIPTION: "RGB power norm"
45 DT_TONEEQ_GEOMEAN, // $DESCRIPTION: "RGB geometric mean"
48
68static float linear_contrast(const float pixel, const float fulcrum, const float contrast)
69{
70 // Increase the slope of the value around a fulcrum value
71 return fmaxf((pixel - fulcrum) * contrast + fulcrum, MIN_FLOAT);
72}
73
74
75__OMP_DECLARE_SIMD__(aligned(image, luminance:64) uniform(image, luminance))
76static void pixel_rgb_mean(const float *const restrict image,
77 float *const restrict luminance,
78 const size_t k, const size_t ch,
79 const float exposure_boost,
80 const float fulcrum, const float contrast_boost)
81{
82 // mean(RGB) is the intensity
83
84 float lum = 0.0f;
85 __OMP_SIMD__(reduction(+:lum) aligned(image:64))
86 for(int c = 0; c < 3; ++c)
87 lum += image[k + c];
88
90}
91
92
93__OMP_DECLARE_SIMD__(aligned(image, luminance:64) uniform(image, luminance))
94static void pixel_rgb_value(const float *const restrict image,
95 float *const restrict luminance,
96 const size_t k, const size_t ch,
97 const float exposure_boost,
98 const float fulcrum, const float contrast_boost)
99{
100 // max(RGB) is equivalent to HSV value
101
102 const float lum = exposure_boost * fmaxf(fmaxf(image[k], image[k + 1]), image[k + 2]);
104}
105
106
107__OMP_DECLARE_SIMD__(aligned(image, luminance:64) uniform(image, luminance))
108static void pixel_rgb_lightness(const float *const restrict image,
109 float *const restrict luminance,
110 const size_t k, const size_t ch,
111 const float exposure_boost,
112 const float fulcrum, const float contrast_boost)
113{
114 // (max(RGB) + min(RGB)) / 2 is equivalent to HSL lightness
115
116 const float max_rgb = fmaxf(fmaxf(image[k], image[k + 1]), image[k + 2]);
117 const float min_rgb = fminf(fminf(image[k], image[k + 1]), image[k + 2]);
118 luminance[k / ch] = linear_contrast(exposure_boost * (max_rgb + min_rgb) / 2.0f, fulcrum, contrast_boost);
119}
120
121__OMP_DECLARE_SIMD__(aligned(image, luminance:64) uniform(image, luminance))
122static void pixel_rgb_norm_1(const float *const restrict image,
123 float *const restrict luminance,
124 const size_t k, const size_t ch,
125 const float exposure_boost,
126 const float fulcrum, const float contrast_boost)
127{
128 // vector norm L1
129
130 float lum = 0.0f;
131 __OMP_SIMD__(reduction(+:lum) aligned(image:64))
132 for(int c = 0; c < 3; ++c)
133 lum += fabsf(image[k + c]);
134
136}
137
138
139__OMP_DECLARE_SIMD__(aligned(image, luminance:64) uniform(image, luminance))
140static void pixel_rgb_norm_2(const float *const restrict image,
141 float *const restrict luminance,
142 const size_t k, const size_t ch,
143 const float exposure_boost,
144 const float fulcrum, const float contrast_boost)
145{
146 // vector norm L2 : euclidean norm
147
148 float result = 0.0f;
149 __OMP_SIMD__(aligned(image:64) reduction(+: result))
150 for(int c = 0; c < 3; ++c) result += image[k + c] * image[k + c];
151
153}
154
155
156__OMP_DECLARE_SIMD__(aligned(image, luminance:64) uniform(image, luminance))
157static void pixel_rgb_norm_power(const float *const restrict image,
158 float *const restrict luminance,
159 const size_t k, const size_t ch,
160 const float exposure_boost,
161 const float fulcrum, const float contrast_boost)
162{
163 // weird norm sort of perceptual. This is black magic really, but it looks good.
164
165 float numerator = 0.0f;
166 float denominator = 0.0f;
167 __OMP_SIMD__(aligned(image:64) reduction(+:numerator, denominator))
168 for(int c = 0; c < 3; ++c)
169 {
170 const float value = fabsf(image[k + c]);
171 const float RGB_square = value * value;
172 const float RGB_cubic = RGB_square * value;
173 numerator += RGB_cubic;
174 denominator += RGB_square;
175 }
176
177 luminance[k / ch] = linear_contrast(exposure_boost * numerator / denominator, fulcrum, contrast_boost);
178}
179
180__OMP_DECLARE_SIMD__(aligned(image, luminance:64) uniform(image, luminance))
181static void pixel_rgb_geomean(const float *const restrict image,
182 float *const restrict luminance,
183 const size_t k, const size_t ch,
184 const float exposure_boost,
185 const float fulcrum, const float contrast_boost)
186{
187 // geometric_mean(RGB). Kind of interesting for saturated colours (maps them to shadows)
188
189 float lum = 1.0f;
190 __OMP_SIMD__(aligned(image:64) reduction(*:lum))
191 for(int c = 0; c < 3; ++c)
192 {
193 lum *= fabsf(image[k + c]);
194 }
195
196 luminance[k / ch] = linear_contrast(exposure_boost * powf(lum, 1.0f / 3.0f), fulcrum, contrast_boost);
197}
198
199
200// Overkill trick to explicitely unswitch loops
201// GCC should to it automatically with "funswitch-loops" flag,
202// but not sure about Clang
203#ifdef _OPENMP
204 #define LOOP(fn) \
205 { \
206 _Pragma ("omp parallel for simd default(firstprivate) \
207 aligned(in, out:64)" ) \
208 for(size_t k = 0; k < num_elem; k += ch) \
209 { \
210 fn(in, out, k, ch, exposure_boost, fulcrum, contrast_boost); \
211 } \
212 break; \
213 }
214#else
215 #define LOOP(fn) \
216 { \
217 for(size_t k = 0; k < num_elem; k += ch) \
218 { \
219 fn(in, out, k, ch, exposure_boost, fulcrum, contrast_boost); \
220 } \
221 break; \
222 }
223#endif
224
225
227static inline void luminance_mask(const float *const restrict in, float *const restrict out,
228 const size_t width, const size_t height, const size_t ch,
230 const float exposure_boost,
231 const float fulcrum, const float contrast_boost)
232{
233 const size_t num_elem = width * height * ch;
234 switch(method)
235 {
236 case DT_TONEEQ_MEAN:
237 LOOP(pixel_rgb_mean);
238
240 LOOP(pixel_rgb_lightness);
241
242 case DT_TONEEQ_VALUE:
243 LOOP(pixel_rgb_value);
244
245 case DT_TONEEQ_NORM_1:
246 LOOP(pixel_rgb_norm_1);
247
248 case DT_TONEEQ_NORM_2:
249 LOOP(pixel_rgb_norm_2);
250
252 LOOP(pixel_rgb_norm_power);
253
255 LOOP(pixel_rgb_geomean);
256
257 default:
258 break;
259 }
260}
261
262
263// clang-format off
264// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
265// vim: shiftwidth=2 expandtab tabstop=2 cindent
266// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
267// clang-format on
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const dt_colormatrix_t dt_aligned_pixel_t out
Definition colorspaces_inline_conversions.h:42
for(size_t c=0;c< 3;c++) sRGB[c]
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define __OMP_SIMD__(...)
Definition darktable.h:262
#define __OMP_DECLARE_SIMD__(...)
Definition darktable.h:263
#define __DT_CLONE_TARGETS__
Definition darktable.h:367
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
float *const restrict const size_t const size_t const float const float fulcrum
Definition luminance_mask.h:80
float *const restrict const size_t const size_t const float exposure_boost
Definition luminance_mask.h:79
dt_iop_luminance_mask_method_t
Definition luminance_mask.h:38
@ DT_TONEEQ_NORM_2
Definition luminance_mask.h:43
@ DT_TONEEQ_MEAN
Definition luminance_mask.h:39
@ DT_TONEEQ_LIGHTNESS
Definition luminance_mask.h:40
@ DT_TONEEQ_LAST
Definition luminance_mask.h:46
@ DT_TONEEQ_VALUE
Definition luminance_mask.h:41
@ DT_TONEEQ_NORM_1
Definition luminance_mask.h:42
@ DT_TONEEQ_GEOMEAN
Definition luminance_mask.h:45
@ DT_TONEEQ_NORM_POWER
Definition luminance_mask.h:44
float *const restrict luminance
Definition luminance_mask.h:77
static float linear_contrast(const float pixel, const float fulcrum, const float contrast)
Definition luminance_mask.h:68
#define MIN_FLOAT
Definition luminance_mask.h:34
float *const restrict const size_t const size_t const float const float const float contrast_boost
Definition luminance_mask.h:81
float *const restrict const size_t k
Definition luminance_mask.h:78
#define LOOP(fn)
float *const restrict const size_t const size_t ch
Definition luminance_mask.h:78
c
Definition derive_filmic_v6_gamut_mapping.py:35