Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
common/histogram.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2014-2016 Roman Lebedev.
4 Copyright (C) 2014, 2016 Tobias Ellinghaus.
5 Copyright (C) 2018-2019 Edgardo Hoszowski.
6 Copyright (C) 2019 Andreas Schneider.
7 Copyright (C) 2020 Pascal Obry.
8 Copyright (C) 2021 Ralf Brown.
9 Copyright (C) 2022 Martin Baƙinka.
10 Copyright (C) 2022 Philipp Lutz.
11
12 darktable is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 darktable is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with darktable. If not, see <http://www.gnu.org/licenses/>.
24*/
25#include <math.h>
26#include <stddef.h>
27#include <stdint.h>
28#include <assert.h>
29#include <stdlib.h>
30
32#include "common/darktable.h"
33#include "common/histogram.h"
34#include "develop/imageop.h"
35
36#define S(V, params) ((params->mul) * ((float)V))
37#define P(V, params) (CLAMP((V), 0, (params->bins_count - 1)))
38#define PU(V, params) (MIN((V), (params->bins_count - 1)))
39#define PS(V, params) (P(S(V, params), params))
40
41//------------------------------------------------------------------------------
42
44 const dt_dev_histogram_collection_params_t *const histogram_params, const float *pixel, uint32_t *histogram)
45{
46 const uint32_t i = PS(*pixel, histogram_params);
47 histogram[4 * i]++;
48}
49
50inline static void histogram_helper_cs_RAW(const dt_dev_histogram_collection_params_t *const histogram_params,
51 const void *pixel, uint32_t *histogram, int j,
52 const dt_iop_order_iccprofile_info_t *const profile_info)
53{
54 const dt_histogram_roi_t *roi = histogram_params->roi;
55 const float *input = (float *)pixel + roi->width * j + roi->crop_x;
56 for(int i = 0; i < roi->width - roi->crop_width - roi->crop_x; i++, input++)
57 {
58 histogram_helper_cs_RAW_helper_process_pixel_float(histogram_params, input, histogram);
59 }
60}
61
62//------------------------------------------------------------------------------
63
64// WARNING: you must ensure that bins_count is big enough
66 const dt_dev_histogram_collection_params_t *const histogram_params, const uint16_t *pixel, uint32_t *histogram)
67{
68 const uint16_t i = PU(*pixel, histogram_params);
69 histogram[4 * i]++;
70}
71
73 const void *pixel, uint32_t *histogram, int j,
74 const dt_iop_order_iccprofile_info_t *const profile_info)
75{
76 const dt_histogram_roi_t *roi = histogram_params->roi;
77 uint16_t *in = (uint16_t *)pixel + roi->width * j + roi->crop_x;
78
79 // process pixels
80 for(int i = 0; i < roi->width - roi->crop_width - roi->crop_x; i++, in++)
81 histogram_helper_cs_RAW_helper_process_pixel_uint16(histogram_params, in, histogram);
82}
83
84//------------------------------------------------------------------------------
85
86inline static void __attribute__((__unused__)) histogram_helper_cs_rgb_helper_process_pixel_float(
87 const dt_dev_histogram_collection_params_t *const histogram_params, const float *pixel, uint32_t *histogram)
88{
89 const uint32_t R = PS(pixel[0], histogram_params);
90 const uint32_t G = PS(pixel[1], histogram_params);
91 const uint32_t B = PS(pixel[2], histogram_params);
92 histogram[4 * R]++;
93 histogram[4 * G + 1]++;
94 histogram[4 * B + 2]++;
95}
96
97inline static void __attribute__((__unused__)) histogram_helper_cs_rgb_helper_process_pixel_float_compensated(
98 const dt_dev_histogram_collection_params_t *const histogram_params, const float *pixel, uint32_t *histogram,
99 const dt_iop_order_iccprofile_info_t *const profile_info)
100{
101 const dt_aligned_pixel_t rgb = { dt_ioppr_compensate_middle_grey(pixel[0], profile_info),
102 dt_ioppr_compensate_middle_grey(pixel[1], profile_info),
103 dt_ioppr_compensate_middle_grey(pixel[2], profile_info) };
104 const uint32_t R = PS(rgb[0], histogram_params);
105 const uint32_t G = PS(rgb[1], histogram_params);
106 const uint32_t B = PS(rgb[2], histogram_params);
107 histogram[4 * R]++;
108 histogram[4 * G + 1]++;
109 histogram[4 * B + 2]++;
110}
111
112inline static void histogram_helper_cs_rgb(const dt_dev_histogram_collection_params_t *const histogram_params,
113 const void *pixel, uint32_t *histogram, int j,
114 const dt_iop_order_iccprofile_info_t *const profile_info)
115{
116 const dt_histogram_roi_t *roi = histogram_params->roi;
117 float *in = (float *)pixel + 4 * (roi->width * j + roi->crop_x);
118
119 // process aligned pixels with SSE
120 for(int i = 0; i < roi->width - roi->crop_width - roi->crop_x; i++, in += 4)
121 {
122 histogram_helper_cs_rgb_helper_process_pixel_float(histogram_params, in, histogram);
123 }
124}
125
126inline static void histogram_helper_cs_rgb_compensated(const dt_dev_histogram_collection_params_t *const histogram_params,
127 const void *pixel, uint32_t *histogram, int j,
128 const dt_iop_order_iccprofile_info_t *const profile_info)
129{
130 const dt_histogram_roi_t *roi = histogram_params->roi;
131 float *in = (float *)pixel + 4 * (roi->width * j + roi->crop_x);
132
133 // process aligned pixels with SSE
134 for(int i = 0; i < roi->width - roi->crop_width - roi->crop_x; i++, in += 4)
135 {
136 histogram_helper_cs_rgb_helper_process_pixel_float_compensated(histogram_params, in, histogram, profile_info);
137 }
138}
139
140//------------------------------------------------------------------------------
141
142inline static void __attribute__((__unused__)) histogram_helper_cs_Lab_helper_process_pixel_float(
143 const dt_dev_histogram_collection_params_t *const histogram_params, const float *pixel, uint32_t *histogram)
144{
145 const float Lv = pixel[0];
146 const float av = pixel[1];
147 const float bv = pixel[2];
148 const float max = histogram_params->bins_count - 1;
149 const uint32_t L = CLAMP(histogram_params->mul / 100.0f * (Lv), 0, max);
150 const uint32_t a = CLAMP(histogram_params->mul / 256.0f * (av + 128.0f), 0, max);
151 const uint32_t b = CLAMP(histogram_params->mul / 256.0f * (bv + 128.0f), 0, max);
152 histogram[4 * L]++;
153 histogram[4 * a + 1]++;
154 histogram[4 * b + 2]++;
155}
156
157inline static void histogram_helper_cs_Lab(const dt_dev_histogram_collection_params_t *const histogram_params,
158 const void *pixel, uint32_t *histogram, int j,
159 const dt_iop_order_iccprofile_info_t *const profile_info)
160{
161 const dt_histogram_roi_t *roi = histogram_params->roi;
162 float *in = (float *)pixel + 4 * (roi->width * j + roi->crop_x);
163
164 // process aligned pixels with SSE
165 for(int i = 0; i < roi->width - roi->crop_width - roi->crop_x; i++, in += 4)
166 {
167 histogram_helper_cs_Lab_helper_process_pixel_float(histogram_params, in, histogram);
168 }
169}
170
171inline static void __attribute__((__unused__)) histogram_helper_cs_Lab_LCh_helper_process_pixel_float(
172 const dt_dev_histogram_collection_params_t *const histogram_params, const float *pixel, uint32_t *histogram)
173{
175 dt_Lab_2_LCH(pixel, LCh);
176 const uint32_t L = PS((LCh[0] / 100.f), histogram_params);
177 const uint32_t C = PS((LCh[1] / (128.0f * sqrtf(2.0f))), histogram_params);
178 const uint32_t h = PS(LCh[2], histogram_params);
179 histogram[4 * L]++;
180 histogram[4 * C + 1]++;
181 histogram[4 * h + 2]++;
182}
183
184inline static void histogram_helper_cs_Lab_LCh(const dt_dev_histogram_collection_params_t *const histogram_params,
185 const void *pixel, uint32_t *histogram, int j,
186 const dt_iop_order_iccprofile_info_t *const profile_info)
187{
188 const dt_histogram_roi_t *roi = histogram_params->roi;
189 float *in = (float *)pixel + 4 * (roi->width * j + roi->crop_x);
190
191 for(int i = 0; i < roi->width - roi->crop_width - roi->crop_x; i++, in += 4)
192 {
193 histogram_helper_cs_Lab_LCh_helper_process_pixel_float(histogram_params, in, histogram);
194 }
195}
196
197inline static void histogram_helper_cs_LCh(const dt_dev_histogram_collection_params_t *const histogram_params,
198 const void *pixel, uint32_t *histogram, int j,
199 const dt_iop_order_iccprofile_info_t *const profile_info)
200{
201 const dt_histogram_roi_t *roi = histogram_params->roi;
202 float *in = (float *)pixel + 4 * (roi->width * j + roi->crop_x);
203
204 for(int i = 0; i < roi->width - roi->crop_width - roi->crop_x; i++, in += 4)
205 {
206 const uint32_t L = PS((in[0] / 100.f), histogram_params);
207 const uint32_t C = PS((in[1] / (128.0f * sqrtf(2.0f))), histogram_params);
208 const uint32_t h = PS(in[2], histogram_params);
209 histogram[4 * L]++;
210 histogram[4 * C + 1]++;
211 histogram[4 * h + 2]++;
212 }
213}
214
215//==============================================================================
216
218 dt_dev_histogram_stats_t *histogram_stats, const void *const pixel,
219 uint32_t **histogram, const dt_worker Worker,
220 const dt_iop_order_iccprofile_info_t *const profile_info)
221{
222 const int nthreads = omp_get_max_threads();
223
224 const size_t bins_total = (size_t)4 * histogram_params->bins_count;
225 const size_t buf_size = bins_total * sizeof(uint32_t);
226 void *partial_hists = calloc(nthreads, buf_size);
227
228 if(histogram_params->mul == 0) histogram_params->mul = (double)(histogram_params->bins_count - 1);
229
230 const dt_histogram_roi_t *const roi = histogram_params->roi;
231 __OMP_PARALLEL_FOR__(shared(partial_hists) )
232 for(int j = roi->crop_y; j < roi->height - roi->crop_height; j++)
233 {
234 uint32_t *thread_hist = (uint32_t *)partial_hists + bins_total * omp_get_thread_num();
235 Worker(histogram_params, pixel, thread_hist, j, profile_info);
236 }
237
238#ifdef _OPENMP
239 *histogram = realloc(*histogram, buf_size);
240 memset(*histogram, 0, buf_size);
241 uint32_t *hist = *histogram;
242
243#pragma omp parallel for default(firstprivate) \
244 shared(hist, partial_hists)
245 for(size_t k = 0; k < bins_total; k++)
246 {
247 for(size_t n = 0; n < nthreads; n++)
248 {
249 const uint32_t *thread_hist = (uint32_t *)partial_hists + bins_total * n;
250 hist[k] += thread_hist[k];
251 }
252 }
253#else
254 *histogram = realloc(*histogram, buf_size);
255 memmove(*histogram, partial_hists, buf_size);
256#endif
257 dt_free(partial_hists);
258
259 histogram_stats->bins_count = histogram_params->bins_count;
260 histogram_stats->pixels = (roi->width - roi->crop_width - roi->crop_x)
261 * (roi->height - roi->crop_height - roi->crop_y);
262}
263
264//------------------------------------------------------------------------------
265
267 dt_dev_histogram_stats_t *histogram_stats, const dt_iop_colorspace_type_t cst,
268 const dt_iop_colorspace_type_t cst_to, const void *pixel, uint32_t **histogram,
269 const int compensate_middle_grey, const dt_iop_order_iccprofile_info_t *const profile_info)
270{
271 float *converted = NULL;
272 if(cst == IOP_CS_LAB && cst_to == IOP_CS_LCH)
273 {
274 const dt_histogram_roi_t *roi = histogram_params->roi;
275 const size_t pixels = (size_t)roi->width * roi->height;
276 converted = dt_pixelpipe_cache_alloc_align_float_cache(4 * pixels, 0);
277
278 if(!IS_NULL_PTR(converted))
279 {
281 for(size_t k = 0; k < pixels; k++)
282 {
283 const size_t offset = 4 * k;
284 dt_Lab_2_LCH((const float *)pixel + offset, converted + offset);
285 converted[offset + 3] = ((const float *)pixel)[offset + 3];
286 }
287 }
288 }
289
290 switch(cst)
291 {
292 case IOP_CS_RAW:
293 dt_histogram_worker(histogram_params, histogram_stats, pixel, histogram, histogram_helper_cs_RAW, profile_info);
294 histogram_stats->ch = 1u;
295 break;
296
297 case IOP_CS_RGB:
299 if(compensate_middle_grey && profile_info)
300 dt_histogram_worker(histogram_params, histogram_stats, pixel, histogram, histogram_helper_cs_rgb_compensated, profile_info);
301 else
302 dt_histogram_worker(histogram_params, histogram_stats, pixel, histogram, histogram_helper_cs_rgb, profile_info);
303 histogram_stats->ch = 3u;
304 break;
305
306 case IOP_CS_LAB:
307 default:
308 if(cst_to != IOP_CS_LCH)
309 dt_histogram_worker(histogram_params, histogram_stats, pixel, histogram, histogram_helper_cs_Lab, profile_info);
310 else if(!IS_NULL_PTR(converted))
311 dt_histogram_worker(histogram_params, histogram_stats, converted, histogram, histogram_helper_cs_LCh, profile_info);
312 else
313 dt_histogram_worker(histogram_params, histogram_stats, pixel, histogram, histogram_helper_cs_Lab_LCh, profile_info);
314 histogram_stats->ch = 3u;
315 break;
316 }
317
319}
320
321void dt_histogram_max_helper(const dt_dev_histogram_stats_t *const histogram_stats,
323 uint32_t **histogram, uint32_t *histogram_max)
324{
325 if(IS_NULL_PTR(*histogram)) return;
326 histogram_max[0] = histogram_max[1] = histogram_max[2] = histogram_max[3] = 0;
327 uint32_t *hist = *histogram;
328 switch(cst)
329 {
330 case IOP_CS_RAW:
331 for(int k = 0; k < 4 * histogram_stats->bins_count; k += 4)
332 histogram_max[0] = histogram_max[0] > hist[k] ? histogram_max[0] : hist[k];
333 break;
334
335 case IOP_CS_RGB:
337 // don't count <= 0 pixels
338 for(int k = 4; k < 4 * histogram_stats->bins_count; k += 4)
339 histogram_max[0] = histogram_max[0] > hist[k] ? histogram_max[0] : hist[k];
340 for(int k = 5; k < 4 * histogram_stats->bins_count; k += 4)
341 histogram_max[1] = histogram_max[1] > hist[k] ? histogram_max[1] : hist[k];
342 for(int k = 6; k < 4 * histogram_stats->bins_count; k += 4)
343 histogram_max[2] = histogram_max[2] > hist[k] ? histogram_max[2] : hist[k];
344 for(int k = 7; k < 4 * histogram_stats->bins_count; k += 4)
345 histogram_max[3] = histogram_max[3] > hist[k] ? histogram_max[3] : hist[k];
346 break;
347
348 case IOP_CS_LAB:
349 default:
350 if(cst_to == IOP_CS_LCH)
351 {
352 // don't count <= 0 pixels
353 for(int k = 4; k < 4 * histogram_stats->bins_count; k += 4)
354 histogram_max[0] = histogram_max[0] > hist[k] ? histogram_max[0] : hist[k];
355 for(int k = 5; k < 4 * histogram_stats->bins_count; k += 4)
356 histogram_max[1] = histogram_max[1] > hist[k] ? histogram_max[1] : hist[k];
357 for(int k = 6; k < 4 * histogram_stats->bins_count; k += 4)
358 histogram_max[2] = histogram_max[2] > hist[k] ? histogram_max[2] : hist[k];
359 for(int k = 7; k < 4 * histogram_stats->bins_count; k += 4)
360 histogram_max[3] = histogram_max[3] > hist[k] ? histogram_max[3] : hist[k];
361 }
362 else
363 {
364 // don't count <= 0 pixels in L
365 for(int k = 4; k < 4 * histogram_stats->bins_count; k += 4)
366 histogram_max[0] = histogram_max[0] > hist[k] ? histogram_max[0] : hist[k];
367
368 // don't count <= -128 and >= +128 pixels in a and b
369 for(int k = 5; k < 4 * (histogram_stats->bins_count - 1); k += 4)
370 histogram_max[1] = histogram_max[1] > hist[k] ? histogram_max[1] : hist[k];
371 for(int k = 6; k < 4 * (histogram_stats->bins_count - 1); k += 4)
372 histogram_max[2] = histogram_max[2] > hist[k] ? histogram_max[2] : hist[k];
373 }
374 break;
375 }
376}
377
378// clang-format off
379// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
380// vim: shiftwidth=2 expandtab tabstop=2 cindent
381// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
382// clang-format on
dt_iop_colorspace_type_t
@ IOP_CS_RAW
@ IOP_CS_LCH
@ IOP_CS_RGB
@ IOP_CS_LAB
#define B(y, x)
static dt_aligned_pixel_t rgb
const float max
static const float const float C
static void histogram_helper_cs_Lab_LCh(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
static void histogram_helper_cs_RAW_helper_process_pixel_float(const dt_dev_histogram_collection_params_t *const histogram_params, const float *pixel, uint32_t *histogram)
static void histogram_helper_cs_rgb(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
static void histogram_helper_cs_RAW_helper_process_pixel_uint16(const dt_dev_histogram_collection_params_t *const histogram_params, const uint16_t *pixel, uint32_t *histogram)
static void histogram_helper_cs_RAW(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
#define PS(V, params)
void dt_histogram_max_helper(const dt_dev_histogram_stats_t *const histogram_stats, const dt_iop_colorspace_type_t cst, const dt_iop_colorspace_type_t cst_to, uint32_t **histogram, uint32_t *histogram_max)
void dt_histogram_worker(dt_dev_histogram_collection_params_t *const histogram_params, dt_dev_histogram_stats_t *histogram_stats, const void *const pixel, uint32_t **histogram, const dt_worker Worker, const dt_iop_order_iccprofile_info_t *const profile_info)
void dt_histogram_helper(dt_dev_histogram_collection_params_t *histogram_params, dt_dev_histogram_stats_t *histogram_stats, const dt_iop_colorspace_type_t cst, const dt_iop_colorspace_type_t cst_to, const void *pixel, uint32_t **histogram, const int compensate_middle_grey, const dt_iop_order_iccprofile_info_t *const profile_info)
static void histogram_helper_cs_LCh(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
static void histogram_helper_cs_rgb_compensated(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
#define PU(V, params)
void dt_histogram_helper_cs_RAW_uint16(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
static void histogram_helper_cs_Lab(const dt_dev_histogram_collection_params_t *const histogram_params, const void *pixel, uint32_t *histogram, int j, const dt_iop_order_iccprofile_info_t *const profile_info)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
Definition darktable.h:447
#define omp_get_max_threads()
Definition darktable.h:254
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
Definition darktable.h:524
#define dt_free(ptr)
Definition darktable.h:456
#define omp_get_thread_num()
Definition darktable.h:255
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:258
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
@ IOP_CS_RGB_DISPLAY
Definition imageop.h:210
float *const restrict const size_t k
#define R
float dt_aligned_pixel_t[4]
const struct dt_histogram_roi_t * roi
Definition pixelpipe.h:56
typedef double((*spd)(unsigned long int wavelength, double TempK))