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