Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
illuminants.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020-2021 Aurélien PIERRE.
4 Copyright (C) 2020 EdgarLux.
5 Copyright (C) 2020-2021 parafin.
6 Copyright (C) 2021 Dan Torop.
7 Copyright (C) 2021 Olivier Samyn 🎻.
8 Copyright (C) 2021 Ralf Brown.
9 Copyright (C) 2022 Martin Bařinka.
10 Copyright (C) 2022 Pascal Obry.
11 Copyright (C) 2023 Luca Zulberti.
12
13 darktable is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 darktable is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with darktable. If not, see <http://www.gnu.org/licenses/>.
25*/
26
27#pragma once
28
30#include "common/image.h"
31
32
33/* Standard CIE illuminants */
34typedef enum dt_illuminant_t
35{
36 DT_ILLUMINANT_PIPE = 0, // $DESCRIPTION: "same as pipeline (D50)"
37 DT_ILLUMINANT_A = 1, // $DESCRIPTION: "A (incandescent)"
38 DT_ILLUMINANT_D = 2, // $DESCRIPTION: "D (daylight)"
39 DT_ILLUMINANT_E = 3, // $DESCRIPTION: "E (equi-energy)" (x = y)
40 DT_ILLUMINANT_F = 4, // $DESCRIPTION: "F (fluorescent)"
41 DT_ILLUMINANT_LED = 5, // $DESCRIPTION: "LED (LED light)"
42 DT_ILLUMINANT_BB = 6, // $DESCRIPTION: "Planckian (black body)" general black body radiator - not CIE standard
43 DT_ILLUMINANT_CUSTOM = 7, // $DESCRIPTION: "custom" input x and y directly - bypass search
44 DT_ILLUMINANT_DETECT_SURFACES = 8, // $DESCRIPTION: "(AI) detect from image surfaces..." auto-detection in image from grey world model
45 DT_ILLUMINANT_DETECT_EDGES = 9, // $DESCRIPTION: "(AI) detect from image edges..."auto-detection in image from grey edges model
46 DT_ILLUMINANT_CAMERA = 10,// $DESCRIPTION: "as shot in camera" read RAW EXIF for WB
49
50// CIE fluorescent standards : https://en.wikipedia.org/wiki/Standard_illuminant
52{
53 DT_ILLUMINANT_FLUO_F1 = 0, // $DESCRIPTION: "F1 (Daylight 6430 K) - medium CRI"
54 DT_ILLUMINANT_FLUO_F2 = 1, // $DESCRIPTION: "F2 (Cool White 4230 K) - medium CRI"
55 DT_ILLUMINANT_FLUO_F3 = 2, // $DESCRIPTION: "F3 (White 3450 K) - medium CRI"
56 DT_ILLUMINANT_FLUO_F4 = 3, // $DESCRIPTION: "F4 (Warm White 2940 K) - medium CRI"
57 DT_ILLUMINANT_FLUO_F5 = 4, // $DESCRIPTION: "F5 (Daylight 6350 K) - medium CRI"
58 DT_ILLUMINANT_FLUO_F6 = 5, // $DESCRIPTION: "F6 (Lite White 4150 K) - medium CRI"
59 DT_ILLUMINANT_FLUO_F7 = 6, // $DESCRIPTION: "F7 (D65 simulator 6500 K) - high CRI"
60 DT_ILLUMINANT_FLUO_F8 = 7, // $DESCRIPTION: "F8 (D50 simulator 5000 K) - high CRI"
61 DT_ILLUMINANT_FLUO_F9 = 8, // $DESCRIPTION: "F9 (Cool White Deluxe 4150 K) - high CRI"
62 DT_ILLUMINANT_FLUO_F10 = 9, // $DESCRIPTION: "F10 (Tuned RGB 5000 K) - low CRI" Philips TL85, Ultralume 50
63 DT_ILLUMINANT_FLUO_F11 = 10, // $DESCRIPTION: "F11 (Tuned RGB 4000 K) - low CRI" Philips TL84, Ultralume 40
64 DT_ILLUMINANT_FLUO_F12 = 11, // $DESCRIPTION: "F12 (Tuned RGB 3000 K) - low CRI" Philips TL83, Ultralume 30
67
68// CIE LED standards : https://en.wikipedia.org/wiki/Standard_illuminant
70{
71 DT_ILLUMINANT_LED_B1 = 0, // $DESCRIPTION: "B1 (Blue 2733 K)" phosphor-converted blue
72 DT_ILLUMINANT_LED_B2 = 1, // $DESCRIPTION: "B2 (Blue 2998 K)" phosphor-converted blue
73 DT_ILLUMINANT_LED_B3 = 2, // $DESCRIPTION: "B3 (Blue 4103 K)" phosphor-converted blue
74 DT_ILLUMINANT_LED_B4 = 3, // $DESCRIPTION: "B4 (Blue 5109 K)" phosphor-converted blue
75 DT_ILLUMINANT_LED_B5 = 4, // $DESCRIPTION: "B5 (Blue 6598 K)" phosphor-converted blue
76 DT_ILLUMINANT_LED_BH1 = 5, // $DESCRIPTION: "BH1 (Blue-Red hybrid 2851 K)" mix of phosphor-converted blue red
77 DT_ILLUMINANT_LED_RGB1= 6, // $DESCRIPTION: "RGB1 (RGB 2840 K)" mixing of red, green, and blue LEDs
78 DT_ILLUMINANT_LED_V1 = 7, // $DESCRIPTION: "V1 (Violet 2724 K)" phosphor-converted violet
79 DT_ILLUMINANT_LED_V2 = 8, // $DESCRIPTION: "V2 (Violet 4070 K)" phosphor-converted violet
82
83
93 // x_2 // y_2
94 static float fluorescent[DT_ILLUMINANT_FLUO_LAST][2] = { { 0.31310f, 0.33727f }, // DT_ILLUMINANT_FLUO_F1
95 { 0.37208f, 0.37529f }, // DT_ILLUMINANT_FLUO_F2
96 { 0.40910f, 0.39430f }, // DT_ILLUMINANT_FLUO_F3
97 { 0.44018f, 0.40329f }, // DT_ILLUMINANT_FLUO_F4
98 { 0.31379f, 0.34531f }, // DT_ILLUMINANT_FLUO_F5
99 { 0.37790f, 0.38835f }, // DT_ILLUMINANT_FLUO_F6
100 { 0.31292f, 0.32933f }, // DT_ILLUMINANT_FLUO_F7
101 { 0.34588f, 0.35875f }, // DT_ILLUMINANT_FLUO_F8
102 { 0.37417f, 0.37281f }, // DT_ILLUMINANT_FLUO_F9
103 { 0.34609f, 0.35986f }, // DT_ILLUMINANT_FLUO_F10
104 { 0.38052f, 0.37713f }, // DT_ILLUMINANT_FLUO_F11
105 { 0.43695f, 0.40441f } }; // DT_ILLUMINANT_FLUO_F12
115 // x_2 // y_2
116static float led[DT_ILLUMINANT_LED_LAST][2] = { { 0.4560f, 0.4078f }, // DT_ILLUMINANT_LED_B1
117 { 0.4357f, 0.4012f }, // DT_ILLUMINANT_LED_B2
118 { 0.3756f, 0.3723f }, // DT_ILLUMINANT_LED_B3
119 { 0.3422f, 0.3502f }, // DT_ILLUMINANT_LED_B4
120 { 0.3118f, 0.3236f }, // DT_ILLUMINANT_LED_B5
121 { 0.4474f, 0.4066f }, // DT_ILLUMINANT_LED_BH1
122 { 0.4557f, 0.4211f }, // DT_ILLUMINANT_LED_RGB1
123 { 0.4560f, 0.4548f }, // DT_ILLUMINANT_LED_V1
124 { 0.3781f, 0.3775f }}; // DT_ILLUMINANT_LED_V2
125
126#ifdef _OPENMP
127#pragma omp declare simd
128#endif
129static inline float xy_to_CCT(const float x, const float y)
130{
131 // Try to find correlated color temperature from chromaticity
132 // Valid for 3000 K to 50000 K
133 // Reference : https://www.usna.edu/Users/oceano/raylee/papers/RLee_AO_CCTpaper.pdf
134 // Warning : we throw a number ever if it's grossly off. You need to check the error later.
135 const float n = (x - 0.3366f)/(y - 0.1735f);
136 return -949.86315f + 6253.80338f * expf(-n / 0.92159f) + 28.70599f * expf(-n / 0.20039f) + 0.00004f * expf(-n / 0.07125f);
137}
138
139
140#ifdef _OPENMP
141#pragma omp declare simd
142#endif
143static inline void CCT_to_xy_daylight(const float t, float *x, float *y)
144{
145 // Take correlated color temperature in K and find the closest daylight illuminant in 4000 K - 250000 K
146 float x_temp = 0.f;
147 float y_temp = 0.f;
148
149 if(t >= 4000.f && t <= 7000.0f)
150 x_temp = ((-4.6070e9f / t + 2.9678e6f) / t + 0.09911e3f) / t + 0.244063f;
151 else if(t > 7000.f && t <= 25000.f)
152 x_temp = ((-2.0064e9f / t + 1.9018e6f) / t + 0.24748e3f) / t + 0.237040f;
153
154 y_temp = (-3.f * x_temp + 2.87f) * x_temp - 0.275f;
155
156 *x = x_temp;
157 *y = y_temp;
158}
159
160
161#ifdef _OPENMP
162#pragma omp declare simd
163#endif
164static inline void CCT_to_xy_blackbody(const float t, float *x, float *y)
165{
166 // Take correlated color temperature in K and find the closest blackbody illuminant in 1667 K - 250000 K
167 float x_temp = 0.f;
168 float y_temp = 0.f;
169
170 if(t >= 1667.f && t <= 4000.f)
171 x_temp = ((-0.2661239e9f / t - 0.2343589e6f) / t + 0.8776956e3f) / t + 0.179910f;
172 else if(t > 4000.f && t <= 25000.f)
173 x_temp = ((-3.0258469e9f / t + 2.1070379e6f) / t + 0.2226347e3f) / t + 0.240390f;
174
175 if(t >= 1667.f && t <= 2222.f)
176 y_temp = ((-1.1063814f * x_temp - 1.34811020f) * x_temp + 2.18555832f) * x_temp - 0.20219683f;
177 else if(t > 2222.f && t <= 4000.f)
178 y_temp = ((-0.9549476f * x_temp - 1.37418593f) * x_temp + 2.09137015f) * x_temp - 0.16748867f;
179 else if(t > 4000.f && t <= 25000.f)
180 y_temp = (( 3.0817580f * x_temp - 5.87338670f) * x_temp + 3.75112997f) * x_temp - 0.37001483f;
181
182 *x = x_temp;
183 *y = y_temp;
184}
185
186
187#ifdef _OPENMP
188#pragma omp declare simd
189#endif
190static inline void illuminant_xy_to_XYZ(const float x, const float y, dt_aligned_pixel_t XYZ)
191{
192 XYZ[0] = x / y; // X
193 XYZ[1] = 1.f; // Y is always 1 by definition, for an illuminant
194 XYZ[2] = (1.f - x - y) / y; // Z
195}
196
197
198#ifdef _OPENMP
199#pragma omp declare simd
200#endif
201static inline void illuminant_xy_to_RGB(const float x, const float y, dt_aligned_pixel_t RGB)
202{
203 // Get an sRGB preview of current illuminant
204 dt_aligned_pixel_t XYZ;
206
207 // Fixme : convert to RGB display space instead of sRGB but first the display profile should be global in dt,
208 // not confined to colorout where it gets created/destroyed all the time.
210
211 // Handle gamut clipping
212 const float max_RGB = fmaxf(fmaxf(RGB[0], RGB[1]), RGB[2]);
213 for(int c = 0; c < 3; c++) RGB[c] = fmaxf(RGB[c] / max_RGB, 0.f);
214}
215
216
217#ifdef _OPENMP
218#pragma omp declare simd
219#endif
220static inline void illuminant_CCT_to_RGB(const float t, dt_aligned_pixel_t RGB)
221{
222 float x, y;
223 if(t > 4000.f)
224 CCT_to_xy_daylight(t, &x, &y);
225 else
226 CCT_to_xy_blackbody(t, &x, &y);
227
229}
230
231
232// Fetch image from pipeline and read EXIF for camera RAW WB coeffs
233static inline int find_temperature_from_raw_coeffs(const dt_image_t *img, const dt_aligned_pixel_t custom_wb,
234 float *chroma_x, float *chroma_y);
235
236
237static inline int illuminant_to_xy(const dt_illuminant_t illuminant, // primary type of illuminant
238 const dt_image_t *img, // image container
239 const dt_aligned_pixel_t custom_wb, // optional user-set WB coeffs
240 float *x_out, float *y_out, // chromaticity output
241 const float t, // temperature in K, if needed
242 const dt_illuminant_fluo_t fluo, // sub-type of fluorescent illuminant, if needed
243 const dt_illuminant_led_t iled) // sub-type of led illuminant, if needed
244{
253 float x = 0.f;
254 float y = 0.f;
255
256 switch(illuminant)
257 {
259 {
260 // darktable default pipeline D50
261 x = 0.34567f;
262 y = 0.35850f;
263 break;
264 }
265 case DT_ILLUMINANT_E:
266 {
267 // Equi-energy - easy-peasy
268 x = y = 1.f / 3.f;
269 break;
270 }
271 case DT_ILLUMINANT_A:
272 {
273 // Special case of Planckian locus for incandescent tungsten bulbs
274 x = 0.44757f;
275 y = 0.40745f;
276 break;
277 }
278 case DT_ILLUMINANT_F:
279 {
280 // Fluorescent lighting - look up
281 if(fluo >= DT_ILLUMINANT_FLUO_LAST) break;
282
283 x = fluorescent[fluo][0];
284 y = fluorescent[fluo][1];
285 break;
286 }
288 {
289 // LED lighting - look up
290 if(iled >= DT_ILLUMINANT_LED_LAST) break;
291
292 x = led[iled][0];
293 y = led[iled][1];
294 break;
295 }
296 case DT_ILLUMINANT_D:
297 {
298 // Adjusted Planckian locus for daylight interpolated by cubic splines
299 // Model valid for T in [4000 ; 25000] K
300 CCT_to_xy_daylight(t, &x, &y);
301 if(y != 0.f && x != 0.f) break;
302 // else t is out of bounds -> use black body model (next case)
303 }
304 case DT_ILLUMINANT_BB:
305 {
306 // General Planckian locus for black body radiator interpolated by cubic splines
307 // Model valid for T in [1667 ; 25000] K
308 CCT_to_xy_blackbody(t, &x, &y);
309 if(y != 0.f && x != 0.f) break;
310 // else t is out of bounds -> use custom/original values (next case)
311 }
313 {
314 // Detect WB from RAW EXIF
315 if(img)
316 if(find_temperature_from_raw_coeffs(img, custom_wb, &x, &y)) break;
317 }
318 case DT_ILLUMINANT_CUSTOM: // leave x and y as-is
322 {
323 return FALSE;
324 }
325 }
326
327 if(x != 0.f && y != 0.f)
328 {
329 *x_out = x;
330 *y_out = y;
331 return TRUE;
332 }
333 else
334 return FALSE;
335}
336
337
338static inline void WB_coeffs_to_illuminant_xy(const float CAM_to_XYZ[4][3], const dt_aligned_pixel_t WB,
339 float *x, float *y)
340{
341 // Find the illuminant chromaticity x y from RAW WB coeffs and camera input matrice
342 dt_aligned_pixel_t XYZ, LMS;
343 // Simulate white point, aka convert (1, 1, 1) in camera space to XYZ
344 // warning : we multiply the transpose of CAM_to_XYZ since the pseudoinverse transposes it
345 XYZ[0] = CAM_to_XYZ[0][0] / WB[0] + CAM_to_XYZ[1][0] / WB[1] + CAM_to_XYZ[2][0] / WB[2];
346 XYZ[1] = CAM_to_XYZ[0][1] / WB[0] + CAM_to_XYZ[1][1] / WB[1] + CAM_to_XYZ[2][1] / WB[2];
347 XYZ[2] = CAM_to_XYZ[0][2] / WB[0] + CAM_to_XYZ[1][2] / WB[1] + CAM_to_XYZ[2][2] / WB[2];
348
349 // Matrices white point is D65. We need to convert it for darktable's pipe (D50)
350 static const dt_aligned_pixel_t D65 = { 0.941238f, 1.040633f, 1.088932f, 0.f };
351 const float p = powf(1.088932f / 0.818155f, 0.0834f);
352
356
357 // Get white point chromaticity
358 XYZ[0] /= XYZ[1];
359 XYZ[2] /= XYZ[1];
360 XYZ[1] /= XYZ[1];
361
362 *x = XYZ[0] / (XYZ[0] + XYZ[1] + XYZ[2]);
363 *y = XYZ[1] / (XYZ[0] + XYZ[1] + XYZ[2]);
364}
365
366
367static inline void matrice_pseudoinverse(float (*in)[3], float (*out)[3], int size)
368{
369 float DT_ALIGNED_ARRAY work[3][6];
370
371 for(int i = 0; i < 3; i++)
372 {
373 for(int j = 0; j < 6; j++)
374 work[i][j] = j == i+3;
375 for(int j = 0; j < 3; j++)
376 for(int k = 0; k < size; k++)
377 work[i][j] += in[k][i] * in[k][j];
378 }
379 for(int i = 0; i < 3; i++)
380 {
381 float num = work[i][i];
382 for(int j = 0; j < 6; j++)
383 work[i][j] /= num;
384 for(int k = 0; k < 3; k++)
385 {
386 if(k==i) continue;
387 num = work[k][i];
388 for(int j = 0; j < 6; j++)
389 work[k][j] -= work[i][j] * num;
390 }
391 }
392 for(int i = 0; i < size; i++)
393 for(int j = 0; j < 3; j++)
394 {
395 out[i][j] = 0.0f;
396 for(int k = 0; k < 3; k++)
397 out[i][j] += work[j][k+3] * in[i][k];
398 }
399}
400
401
402static int find_temperature_from_raw_coeffs(const dt_image_t *img, const dt_aligned_pixel_t custom_wb,
403 float *chroma_x, float *chroma_y)
404{
405 if(img == NULL) return FALSE;
407
408 int has_valid_coeffs = TRUE;
409 const int num_coeffs = (img->flags & DT_IMAGE_4BAYER) ? 4 : 3;
410
411 // Check coeffs
412 for(int k = 0; has_valid_coeffs && k < num_coeffs; k++)
413 if(!isnormal(img->wb_coeffs[k]) || img->wb_coeffs[k] == 0.0f) has_valid_coeffs = FALSE;
414
415 if(!has_valid_coeffs) return FALSE;
416
417 // Get white balance camera factors
418 dt_aligned_pixel_t WB = { img->wb_coeffs[0], img->wb_coeffs[1], img->wb_coeffs[2], img->wb_coeffs[3] };
419
420 // Adapt the camera coeffs with custom white balance if provided
421 // this can deal with WB coeffs that don't use the input matrix reference
422 if(custom_wb)
423 for(size_t k = 0; k < 4; k++) WB[k] *= custom_wb[k];
424
425 // Get the camera input profile (matrice of primaries)
426 float XYZ_to_CAM[4][3];
427 XYZ_to_CAM[0][0] = NAN;
428
429 if(!isnan(img->d65_color_matrix[0]))
430 {
431 // keep in sync with reload_defaults from colorin.c
432 // embedded matrix is used with higher priority than standard one
433 XYZ_to_CAM[0][0] = img->d65_color_matrix[0];
434 XYZ_to_CAM[0][1] = img->d65_color_matrix[1];
435 XYZ_to_CAM[0][2] = img->d65_color_matrix[2];
436
437 XYZ_to_CAM[1][0] = img->d65_color_matrix[3];
438 XYZ_to_CAM[1][1] = img->d65_color_matrix[4];
439 XYZ_to_CAM[1][2] = img->d65_color_matrix[5];
440
441 XYZ_to_CAM[2][0] = img->d65_color_matrix[6];
442 XYZ_to_CAM[2][1] = img->d65_color_matrix[7];
443 XYZ_to_CAM[2][2] = img->d65_color_matrix[8];
444 }
445 else
446 {
447 for(int k=0; k<4; k++)
448 for(int i=0; i<3; i++)
449 XYZ_to_CAM[k][i] = img->adobe_XYZ_to_CAM[k][i];
450 }
451
452 if(isnan(XYZ_to_CAM[0][0])) return FALSE;
453
454 // Bloody input matrices define XYZ -> CAM transform, as if we often needed camera profiles to output
455 // So we need to invert them. Here go your CPU cycles again.
456 float CAM_to_XYZ[4][3];
457 CAM_to_XYZ[0][0] = NAN;
458 matrice_pseudoinverse(XYZ_to_CAM, CAM_to_XYZ, 3);
459 if(isnan(CAM_to_XYZ[0][0])) return FALSE;
460
461 float x, y;
462 WB_coeffs_to_illuminant_xy(CAM_to_XYZ, WB, &x, &y);
463 *chroma_x = x;
464 *chroma_y = y;
465
466 return TRUE;
467}
468
469
470#ifdef _OPENMP
471#pragma omp declare simd
472#endif
473static inline float planckian_normal(const float x, const float t)
474{
475 float n = 0.f;
476
477 // Get the direction of the normal vector to the planckian locus at current temperature
478 // This is derivated from CCT_to_xy_blackbody equations
479 if(t >= 1667.f && t <= 2222.f)
480 n = (-3.3191442f * x - 2.69622040f) * x + 2.18555832f;
481 else if(t > 2222.f && t <= 4000.f)
482 n = (-2.8648428f * x - 2.74837186f) * x + 2.09137015f;
483 else if(t > 4000.f && t < 25000.f)
484 n = (9.2452740f * x - 11.7467734f) * x + 3.75112997f;
485 return n;
486}
487
488
489#ifdef _OPENMP
490#pragma omp declare simd
491#endif
492static inline void blackbody_xy_to_tinted_xy(const float x, const float y, const float t, const float tint,
493 float *x_out, float *y_out)
494{
495 // Move further away from planckian locus in the orthogonal direction, by an amount of "tint"
496 const float n = planckian_normal(x, t);
497 const float norm = sqrtf(1.f + n * n);
498 *x_out = x + tint * n / norm;
499 *y_out = y - tint / norm;
500}
501
502
503#ifdef _OPENMP
504#pragma omp declare simd
505#endif
506static inline float get_tint_from_tinted_xy(const float x, const float y, const float t)
507{
508 // Find the distance between planckian locus and arbitrary x y chromaticity in the orthogonal direction
509 const float n = planckian_normal(x, t);
510 const float norm = sqrtf(1.f + n * n);
511 float x_bb, y_bb;
512 CCT_to_xy_blackbody(t, &x_bb, &y_bb);
513 const float tint = -(y - y_bb) * norm;
514 return tint;
515}
516
517
518#ifdef _OPENMP
519#pragma omp declare simd
520#endif
521static inline void xy_to_uv(const float xy[2], float uv[2])
522{
523 // Convert to CIE1960 Yuv color space, usefull to compute CCT
524 // https://en.wikipedia.org/wiki/CIE_1960_color_space
525 const float denom = 12.f * xy[1] - 1.882f * xy[0] + 2.9088f;
526 uv[0] = 5.5932f * xy[0] + 1.9116 * xy[1];
527 uv[1] = 7.8972f * xy[1];
528 uv[0] /= denom;
529 uv[1] /= denom;
530}
531
532
533/*
534 * The following defines a custom OpenMP reduction so the reverse-lookup can be fully parallelized without sharing.
535 *
536 * Reference : https://stackoverflow.com/questions/61821090/parallelization-of-a-reverse-lookup-with-openmp
537 *
538 * The principle is that each thread has its own private radius and temperature, and find its own local minium radius.
539 * Then, at the end of the parallel loops, we fetch all the local minima from each thread, compare them and return
540 * the global minimum.
541 *
542 * This avoids sharing temperature and radius between threads and waiting for thread locks.
543 */
544typedef struct pair
545{
546 float radius;
549
550struct pair pair_min(struct pair r, struct pair n)
551{
552 // r is the current min value, n in the value to compare against it
553 if(n.radius < r.radius) return n;
554 else return r;
555}
556
557// Define a new reduction operation
558#ifdef _OPENMP
559#pragma omp declare reduction(pairmin:struct pair:omp_out=pair_min(omp_out,omp_in)) \
560 initializer(omp_priv = { FLT_MAX, 0.0f })
561#endif
562
563static inline float CCT_reverse_lookup(const float x, const float y)
564{
565 // Find out the closest correlated color temperature (closest point over the planckian locus)
566 // for any arbitrary x, y chromaticity, by brute-force reverse-lookup.
567 // Note that the LUT computation could be defered somewhere else, and computed once
568
569 static const float T_min = 1667.f;
570 static const float T_max = 25000.f;
571 static const float T_range = T_max - T_min;
572 static const size_t LUT_samples = 1<<16;
573
574 struct pair min_radius = { FLT_MAX, 0.0f };
575
576#if !(defined(__apple_build_version__) && __apple_build_version__ < 11030000) //makes Xcode 11.3.1 compiler crash
577#ifdef _OPENMP
578#pragma omp parallel for default(none) \
579 dt_omp_firstprivate(x, y, T_min, T_range, LUT_samples) reduction(pairmin:min_radius)\
580 schedule(simd:static)
581#endif
582#endif
583 for(size_t i = 0; i < LUT_samples; i++)
584 {
585 // we need more values for the low temperatures, so we scale the step with a power
586 const float step = powf((float)i / (float)(LUT_samples - 1), 4.0f);
587
588 // Current temperature in the lookup range
589 const float T = T_min + step * T_range;
590
591 // Current x, y chromaticity
592 float x_bb, y_bb;
593
594 if(T >= 4000.f)
595 CCT_to_xy_daylight(T, &x_bb, &y_bb);
596 else
597 CCT_to_xy_blackbody(T, &x_bb, &y_bb);
598
599 // Compute distance between current planckian chromaticity and input
600 const pair radius_tmp = { dt_fast_hypotf((x_bb - x), (y_bb - y)), T };
601
602 // If we found a smaller radius, save it
603 min_radius = pair_min(min_radius, radius_tmp);
604 }
605
606 return min_radius.temperature;
607}
608// clang-format off
609// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
610// vim: shiftwidth=2 expandtab tabstop=2 cindent
611// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
612// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
Definition chromatic_adaptation.h:315
static const dt_aligned_pixel_simd_t illuminant
Definition chromatic_adaptation.h:313
static float4 convert_XYZ_to_bradford_LMS(const float4 XYZ)
Definition colorspace.h:657
static void bradford_adapt_D50(float4 *lms_in, const float4 origin_illuminant, const float p, const int full)
Definition colorspace.h:697
static float4 convert_bradford_LMS_to_XYZ(const float4 LMS)
Definition colorspace.h:667
dt_aligned_pixel_t LMS
Definition colorspaces_inline_conversions.h:952
const float i
Definition colorspaces_inline_conversions.h:669
dt_XYZ_to_Rec709_D50(XYZ, rgb)
const float c
Definition colorspaces_inline_conversions.h:1365
const float denom
Definition colorspaces_inline_conversions.h:1334
const float r
Definition colorspaces_inline_conversions.h:1324
static const dt_colormatrix_t dt_aligned_pixel_t out
Definition colorspaces_inline_conversions.h:184
const float n
Definition colorspaces_inline_conversions.h:929
static dt_aligned_pixel_t XYZ
Definition colorspaces_inline_conversions.h:252
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
static dt_aligned_pixel_t RGB
Definition colorspaces_inline_conversions.h:509
return dt_load_simd_aligned(JCH)
gboolean dt_image_is_matrix_correction_supported(const dt_image_t *img)
Definition common/image.c:268
@ DT_IMAGE_4BAYER
Definition common/image.h:127
#define DT_ALIGNED_ARRAY
Definition darktable.h:312
static int illuminant_to_xy(const dt_illuminant_t illuminant, const dt_image_t *img, const dt_aligned_pixel_t custom_wb, float *x_out, float *y_out, const float t, const dt_illuminant_fluo_t fluo, const dt_illuminant_led_t iled)
Definition illuminants.h:237
dt_illuminant_t
Definition illuminants.h:35
@ DT_ILLUMINANT_A
Definition illuminants.h:37
@ DT_ILLUMINANT_PIPE
Definition illuminants.h:36
@ DT_ILLUMINANT_CAMERA
Definition illuminants.h:46
@ DT_ILLUMINANT_BB
Definition illuminants.h:42
@ DT_ILLUMINANT_F
Definition illuminants.h:40
@ DT_ILLUMINANT_CUSTOM
Definition illuminants.h:43
@ DT_ILLUMINANT_LED
Definition illuminants.h:41
@ DT_ILLUMINANT_DETECT_EDGES
Definition illuminants.h:45
@ DT_ILLUMINANT_E
Definition illuminants.h:39
@ DT_ILLUMINANT_LAST
Definition illuminants.h:47
@ DT_ILLUMINANT_DETECT_SURFACES
Definition illuminants.h:44
@ DT_ILLUMINANT_D
Definition illuminants.h:38
static void WB_coeffs_to_illuminant_xy(const float CAM_to_XYZ[4][3], const dt_aligned_pixel_t WB, float *x, float *y)
Definition illuminants.h:338
static void illuminant_CCT_to_RGB(const float t, dt_aligned_pixel_t RGB)
Definition illuminants.h:220
static void illuminant_xy_to_RGB(const float x, const float y, dt_aligned_pixel_t RGB)
Definition illuminants.h:201
static void illuminant_xy_to_XYZ(const float x, const float y, dt_aligned_pixel_t XYZ)
Definition illuminants.h:190
static float xy_to_CCT(const float x, const float y)
Definition illuminants.h:129
static void CCT_to_xy_daylight(const float t, float *x, float *y)
Definition illuminants.h:143
dt_illuminant_led_t
Definition illuminants.h:70
@ DT_ILLUMINANT_LED_BH1
Definition illuminants.h:76
@ DT_ILLUMINANT_LED_B5
Definition illuminants.h:75
@ DT_ILLUMINANT_LED_B2
Definition illuminants.h:72
@ DT_ILLUMINANT_LED_B1
Definition illuminants.h:71
@ DT_ILLUMINANT_LED_LAST
Definition illuminants.h:80
@ DT_ILLUMINANT_LED_V1
Definition illuminants.h:78
@ DT_ILLUMINANT_LED_B3
Definition illuminants.h:73
@ DT_ILLUMINANT_LED_B4
Definition illuminants.h:74
@ DT_ILLUMINANT_LED_V2
Definition illuminants.h:79
@ DT_ILLUMINANT_LED_RGB1
Definition illuminants.h:77
static float CCT_reverse_lookup(const float x, const float y)
Definition illuminants.h:563
static float get_tint_from_tinted_xy(const float x, const float y, const float t)
Definition illuminants.h:506
static float planckian_normal(const float x, const float t)
Definition illuminants.h:473
static int find_temperature_from_raw_coeffs(const dt_image_t *img, const dt_aligned_pixel_t custom_wb, float *chroma_x, float *chroma_y)
Definition illuminants.h:402
static void CCT_to_xy_blackbody(const float t, float *x, float *y)
Definition illuminants.h:164
static float fluorescent[DT_ILLUMINANT_FLUO_LAST][2]
Definition illuminants.h:94
static void matrice_pseudoinverse(float(*in)[3], float(*out)[3], int size)
Definition illuminants.h:367
dt_illuminant_fluo_t
Definition illuminants.h:52
@ DT_ILLUMINANT_FLUO_F6
Definition illuminants.h:58
@ DT_ILLUMINANT_FLUO_F4
Definition illuminants.h:56
@ DT_ILLUMINANT_FLUO_F1
Definition illuminants.h:53
@ DT_ILLUMINANT_FLUO_F5
Definition illuminants.h:57
@ DT_ILLUMINANT_FLUO_F2
Definition illuminants.h:54
@ DT_ILLUMINANT_FLUO_F3
Definition illuminants.h:55
@ DT_ILLUMINANT_FLUO_F12
Definition illuminants.h:64
@ DT_ILLUMINANT_FLUO_F8
Definition illuminants.h:60
@ DT_ILLUMINANT_FLUO_F9
Definition illuminants.h:61
@ DT_ILLUMINANT_FLUO_LAST
Definition illuminants.h:65
@ DT_ILLUMINANT_FLUO_F11
Definition illuminants.h:63
@ DT_ILLUMINANT_FLUO_F7
Definition illuminants.h:59
@ DT_ILLUMINANT_FLUO_F10
Definition illuminants.h:62
static void blackbody_xy_to_tinted_xy(const float x, const float y, const float t, const float tint, float *x_out, float *y_out)
Definition illuminants.h:492
static void xy_to_uv(const float xy[2], float uv[2])
Definition illuminants.h:521
static float led[DT_ILLUMINANT_LED_LAST][2]
Definition illuminants.h:116
struct pair pair_min(struct pair r, struct pair n)
Definition illuminants.h:550
static const float x
Definition iop_profile.h:239
const int t
Definition iop_profile.h:227
static float dt_fast_hypotf(const float x, const float y)
Definition math.h:280
size_t size
Definition mipmap_cache.c:3
Definition common/image.h:247
int32_t flags
Definition common/image.h:285
float d65_color_matrix[9]
Definition common/image.h:299
float adobe_XYZ_to_CAM[4][3]
Definition common/image.h:322
dt_aligned_pixel_t wb_coeffs
Definition common/image.h:319
Definition illuminants.h:545
float temperature
Definition illuminants.h:547
float radius
Definition illuminants.h:546