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
127static inline float xy_to_CCT(const float x, const float y)
128{
129 // Try to find correlated color temperature from chromaticity
130 // Valid for 3000 K to 50000 K
131 // Reference : https://www.usna.edu/Users/oceano/raylee/papers/RLee_AO_CCTpaper.pdf
132 // Warning : we throw a number ever if it's grossly off. You need to check the error later.
133 const float n = (x - 0.3366f)/(y - 0.1735f);
134 return -949.86315f + 6253.80338f * expf(-n / 0.92159f) + 28.70599f * expf(-n / 0.20039f) + 0.00004f * expf(-n / 0.07125f);
135}
136
137
139static inline void CCT_to_xy_daylight(const float t, float *x, float *y)
140{
141 // Take correlated color temperature in K and find the closest daylight illuminant in 4000 K - 250000 K
142 float x_temp = 0.f;
143 float y_temp = 0.f;
144
145 if(t >= 4000.f && t <= 7000.0f)
146 x_temp = ((-4.6070e9f / t + 2.9678e6f) / t + 0.09911e3f) / t + 0.244063f;
147 else if(t > 7000.f && t <= 25000.f)
148 x_temp = ((-2.0064e9f / t + 1.9018e6f) / t + 0.24748e3f) / t + 0.237040f;
149
150 y_temp = (-3.f * x_temp + 2.87f) * x_temp - 0.275f;
151
152 *x = x_temp;
153 *y = y_temp;
154}
155
156
158static inline void CCT_to_xy_blackbody(const float t, float *x, float *y)
159{
160 // Take correlated color temperature in K and find the closest blackbody illuminant in 1667 K - 250000 K
161 float x_temp = 0.f;
162 float y_temp = 0.f;
163
164 if(t >= 1667.f && t <= 4000.f)
165 x_temp = ((-0.2661239e9f / t - 0.2343589e6f) / t + 0.8776956e3f) / t + 0.179910f;
166 else if(t > 4000.f && t <= 25000.f)
167 x_temp = ((-3.0258469e9f / t + 2.1070379e6f) / t + 0.2226347e3f) / t + 0.240390f;
168
169 if(t >= 1667.f && t <= 2222.f)
170 y_temp = ((-1.1063814f * x_temp - 1.34811020f) * x_temp + 2.18555832f) * x_temp - 0.20219683f;
171 else if(t > 2222.f && t <= 4000.f)
172 y_temp = ((-0.9549476f * x_temp - 1.37418593f) * x_temp + 2.09137015f) * x_temp - 0.16748867f;
173 else if(t > 4000.f && t <= 25000.f)
174 y_temp = (( 3.0817580f * x_temp - 5.87338670f) * x_temp + 3.75112997f) * x_temp - 0.37001483f;
175
176 *x = x_temp;
177 *y = y_temp;
178}
179
180
182static inline void illuminant_xy_to_XYZ(const float x, const float y, dt_aligned_pixel_t XYZ)
183{
184 XYZ[0] = x / y; // X
185 XYZ[1] = 1.f; // Y is always 1 by definition, for an illuminant
186 XYZ[2] = (1.f - x - y) / y; // Z
187}
188
189
191static inline void illuminant_xy_to_RGB(const float x, const float y, dt_aligned_pixel_t RGB)
192{
193 // Get an sRGB preview of current illuminant
196
197 // Fixme : convert to RGB display space instead of sRGB but first the display profile should be global in dt,
198 // not confined to colorout where it gets created/destroyed all the time.
200
201 // Handle gamut clipping
202 const float max_RGB = fmaxf(fmaxf(RGB[0], RGB[1]), RGB[2]);
203 for(int c = 0; c < 3; c++) RGB[c] = fmaxf(RGB[c] / max_RGB, 0.f);
204}
205
206
208static inline void illuminant_CCT_to_RGB(const float t, dt_aligned_pixel_t RGB)
209{
210 float x, y;
211 if(t > 4000.f)
212 CCT_to_xy_daylight(t, &x, &y);
213 else
214 CCT_to_xy_blackbody(t, &x, &y);
215
217}
218
219
220// Fetch image from pipeline and read EXIF for camera RAW WB coeffs
221static inline int find_temperature_from_raw_coeffs(const dt_image_t *img, const dt_aligned_pixel_t custom_wb,
222 float *chroma_x, float *chroma_y);
223
224
225static inline int illuminant_to_xy(const dt_illuminant_t illuminant, // primary type of illuminant
226 const dt_image_t *img, // image container
227 const dt_aligned_pixel_t custom_wb, // optional user-set WB coeffs
228 float *x_out, float *y_out, // chromaticity output
229 const float t, // temperature in K, if needed
230 const dt_illuminant_fluo_t fluo, // sub-type of fluorescent illuminant, if needed
231 const dt_illuminant_led_t iled) // sub-type of led illuminant, if needed
232{
241 float x = 0.f;
242 float y = 0.f;
243
244 switch(illuminant)
245 {
247 {
248 // darktable default pipeline D50
249 x = 0.34567f;
250 y = 0.35850f;
251 break;
252 }
253 case DT_ILLUMINANT_E:
254 {
255 // Equi-energy - easy-peasy
256 x = y = 1.f / 3.f;
257 break;
258 }
259 case DT_ILLUMINANT_A:
260 {
261 // Special case of Planckian locus for incandescent tungsten bulbs
262 x = 0.44757f;
263 y = 0.40745f;
264 break;
265 }
266 case DT_ILLUMINANT_F:
267 {
268 // Fluorescent lighting - look up
269 if(fluo >= DT_ILLUMINANT_FLUO_LAST) break;
270
271 x = fluorescent[fluo][0];
272 y = fluorescent[fluo][1];
273 break;
274 }
276 {
277 // LED lighting - look up
278 if(iled >= DT_ILLUMINANT_LED_LAST) break;
279
280 x = led[iled][0];
281 y = led[iled][1];
282 break;
283 }
284 case DT_ILLUMINANT_D:
285 {
286 // Adjusted Planckian locus for daylight interpolated by cubic splines
287 // Model valid for T in [4000 ; 25000] K
288 CCT_to_xy_daylight(t, &x, &y);
289 if(y != 0.f && x != 0.f) break;
290 // else t is out of bounds -> use black body model (next case)
291 }
292 case DT_ILLUMINANT_BB:
293 {
294 // General Planckian locus for black body radiator interpolated by cubic splines
295 // Model valid for T in [1667 ; 25000] K
296 CCT_to_xy_blackbody(t, &x, &y);
297 if(y != 0.f && x != 0.f) break;
298 // else t is out of bounds -> use custom/original values (next case)
299 }
301 {
302 // Detect WB from RAW EXIF
303 if(img)
304 if(find_temperature_from_raw_coeffs(img, custom_wb, &x, &y)) break;
305 }
306 case DT_ILLUMINANT_CUSTOM: // leave x and y as-is
310 {
311 return FALSE;
312 }
313 }
314
315 if(x != 0.f && y != 0.f)
316 {
317 *x_out = x;
318 *y_out = y;
319 return TRUE;
320 }
321 else
322 return FALSE;
323}
324
325
326static inline void WB_coeffs_to_illuminant_xy(const float CAM_to_XYZ[4][3], const dt_aligned_pixel_t WB,
327 float *x, float *y)
328{
329 // Find the illuminant chromaticity x y from RAW WB coeffs and camera input matrice
331 // Simulate white point, aka convert (1, 1, 1) in camera space to XYZ
332 // warning : we multiply the transpose of CAM_to_XYZ since the pseudoinverse transposes it
333 XYZ[0] = CAM_to_XYZ[0][0] / WB[0] + CAM_to_XYZ[1][0] / WB[1] + CAM_to_XYZ[2][0] / WB[2];
334 XYZ[1] = CAM_to_XYZ[0][1] / WB[0] + CAM_to_XYZ[1][1] / WB[1] + CAM_to_XYZ[2][1] / WB[2];
335 XYZ[2] = CAM_to_XYZ[0][2] / WB[0] + CAM_to_XYZ[1][2] / WB[1] + CAM_to_XYZ[2][2] / WB[2];
336
337 // Matrices white point is D65. We need to convert it for darktable's pipe (D50)
338 static const dt_aligned_pixel_t D65 = { 0.941238f, 1.040633f, 1.088932f, 0.f };
339 const float p = powf(1.088932f / 0.818155f, 0.0834f);
340
342 dt_store_simd_aligned(LMS, bradford_adapt_D50(dt_load_simd_aligned(LMS), dt_load_simd_aligned(D65), p, FALSE));
344
345 // Get white point chromaticity
346 XYZ[0] /= XYZ[1];
347 XYZ[2] /= XYZ[1];
348 XYZ[1] /= XYZ[1];
349
350 *x = XYZ[0] / (XYZ[0] + XYZ[1] + XYZ[2]);
351 *y = XYZ[1] / (XYZ[0] + XYZ[1] + XYZ[2]);
352}
353
354
355static inline void matrice_pseudoinverse(float (*in)[3], float (*out)[3], int size)
356{
357 float DT_ALIGNED_ARRAY work[3][6];
358
359 for(int i = 0; i < 3; i++)
360 {
361 for(int j = 0; j < 6; j++)
362 work[i][j] = j == i+3;
363 for(int j = 0; j < 3; j++)
364 for(int k = 0; k < size; k++)
365 work[i][j] += in[k][i] * in[k][j];
366 }
367 for(int i = 0; i < 3; i++)
368 {
369 float num = work[i][i];
370 for(int j = 0; j < 6; j++)
371 work[i][j] /= num;
372 for(int k = 0; k < 3; k++)
373 {
374 if(k==i) continue;
375 num = work[k][i];
376 for(int j = 0; j < 6; j++)
377 work[k][j] -= work[i][j] * num;
378 }
379 }
380 for(int i = 0; i < size; i++)
381 for(int j = 0; j < 3; j++)
382 {
383 out[i][j] = 0.0f;
384 for(int k = 0; k < 3; k++)
385 out[i][j] += work[j][k+3] * in[i][k];
386 }
387}
388
389
391 float *chroma_x, float *chroma_y)
392{
393 if(IS_NULL_PTR(img)) return FALSE;
395
396 int has_valid_coeffs = TRUE;
397 const int num_coeffs = (img->flags & DT_IMAGE_4BAYER) ? 4 : 3;
398
399 // Check coeffs
400 for(int k = 0; has_valid_coeffs && k < num_coeffs; k++)
401 if(!isnormal(img->wb_coeffs[k]) || img->wb_coeffs[k] == 0.0f) has_valid_coeffs = FALSE;
402
403 if(!has_valid_coeffs) return FALSE;
404
405 // Get white balance camera factors
406 dt_aligned_pixel_t WB = { img->wb_coeffs[0], img->wb_coeffs[1], img->wb_coeffs[2], img->wb_coeffs[3] };
407
408 // Adapt the camera coeffs with custom white balance if provided
409 // this can deal with WB coeffs that don't use the input matrix reference
410 if(custom_wb)
411 for(size_t k = 0; k < 4; k++) WB[k] *= custom_wb[k];
412
413 // Get the camera input profile (matrice of primaries)
414 float XYZ_to_CAM[4][3];
415 XYZ_to_CAM[0][0] = NAN;
416
417 if(!isnan(img->d65_color_matrix[0]))
418 {
419 // keep in sync with reload_defaults from colorin.c
420 // embedded matrix is used with higher priority than standard one
421 XYZ_to_CAM[0][0] = img->d65_color_matrix[0];
422 XYZ_to_CAM[0][1] = img->d65_color_matrix[1];
423 XYZ_to_CAM[0][2] = img->d65_color_matrix[2];
424
425 XYZ_to_CAM[1][0] = img->d65_color_matrix[3];
426 XYZ_to_CAM[1][1] = img->d65_color_matrix[4];
427 XYZ_to_CAM[1][2] = img->d65_color_matrix[5];
428
429 XYZ_to_CAM[2][0] = img->d65_color_matrix[6];
430 XYZ_to_CAM[2][1] = img->d65_color_matrix[7];
431 XYZ_to_CAM[2][2] = img->d65_color_matrix[8];
432 }
433 else
434 {
435 for(int k=0; k<4; k++)
436 for(int i=0; i<3; i++)
437 XYZ_to_CAM[k][i] = img->adobe_XYZ_to_CAM[k][i];
438 }
439
440 if(isnan(XYZ_to_CAM[0][0])) return FALSE;
441
442 // Bloody input matrices define XYZ -> CAM transform, as if we often needed camera profiles to output
443 // So we need to invert them. Here go your CPU cycles again.
444 float CAM_to_XYZ[4][3];
445 CAM_to_XYZ[0][0] = NAN;
446 matrice_pseudoinverse(XYZ_to_CAM, CAM_to_XYZ, 3);
447 if(isnan(CAM_to_XYZ[0][0])) return FALSE;
448
449 float x, y;
450 WB_coeffs_to_illuminant_xy(CAM_to_XYZ, WB, &x, &y);
451 *chroma_x = x;
452 *chroma_y = y;
453
454 return TRUE;
455}
456
457
459static inline float planckian_normal(const float x, const float t)
460{
461 float n = 0.f;
462
463 // Get the direction of the normal vector to the planckian locus at current temperature
464 // This is derivated from CCT_to_xy_blackbody equations
465 if(t >= 1667.f && t <= 2222.f)
466 n = (-3.3191442f * x - 2.69622040f) * x + 2.18555832f;
467 else if(t > 2222.f && t <= 4000.f)
468 n = (-2.8648428f * x - 2.74837186f) * x + 2.09137015f;
469 else if(t > 4000.f && t < 25000.f)
470 n = (9.2452740f * x - 11.7467734f) * x + 3.75112997f;
471 return n;
472}
473
474
476static inline void blackbody_xy_to_tinted_xy(const float x, const float y, const float t, const float tint,
477 float *x_out, float *y_out)
478{
479 // Move further away from planckian locus in the orthogonal direction, by an amount of "tint"
480 const float n = planckian_normal(x, t);
481 const float norm = sqrtf(1.f + n * n);
482 *x_out = x + tint * n / norm;
483 *y_out = y - tint / norm;
484}
485
486
488static inline float get_tint_from_tinted_xy(const float x, const float y, const float t)
489{
490 // Find the distance between planckian locus and arbitrary x y chromaticity in the orthogonal direction
491 const float n = planckian_normal(x, t);
492 const float norm = sqrtf(1.f + n * n);
493 float x_bb, y_bb;
494 CCT_to_xy_blackbody(t, &x_bb, &y_bb);
495 const float tint = -(y - y_bb) * norm;
496 return tint;
497}
498
499
501static inline void xy_to_uv(const float xy[2], float uv[2])
502{
503 // Convert to CIE1960 Yuv color space, usefull to compute CCT
504 // https://en.wikipedia.org/wiki/CIE_1960_color_space
505 const float denom = 12.f * xy[1] - 1.882f * xy[0] + 2.9088f;
506 uv[0] = 5.5932f * xy[0] + 1.9116 * xy[1];
507 uv[1] = 7.8972f * xy[1];
508 uv[0] /= denom;
509 uv[1] /= denom;
510}
511
512
513/*
514 * The following defines a custom OpenMP reduction so the reverse-lookup can be fully parallelized without sharing.
515 *
516 * Reference : https://stackoverflow.com/questions/61821090/parallelization-of-a-reverse-lookup-with-openmp
517 *
518 * The principle is that each thread has its own private radius and temperature, and find its own local minium radius.
519 * Then, at the end of the parallel loops, we fetch all the local minima from each thread, compare them and return
520 * the global minimum.
521 *
522 * This avoids sharing temperature and radius between threads and waiting for thread locks.
523 */
524typedef struct pair
525{
526 float radius;
529
530struct pair pair_min(struct pair r, struct pair n)
531{
532 // r is the current min value, n in the value to compare against it
533 if(n.radius < r.radius) return n;
534 else return r;
535}
536
537// Define a new reduction operation
538#ifdef _OPENMP
539#pragma omp declare reduction(pairmin:struct pair:omp_out=pair_min(omp_out,omp_in)) \
540 initializer(omp_priv = { FLT_MAX, 0.0f })
541#endif
542
543static inline float CCT_reverse_lookup(const float x, const float y)
544{
545 // Find out the closest correlated color temperature (closest point over the planckian locus)
546 // for any arbitrary x, y chromaticity, by brute-force reverse-lookup.
547 // Note that the LUT computation could be defered somewhere else, and computed once
548
549 static const float T_min = 1667.f;
550 static const float T_max = 25000.f;
551 static const float T_range = T_max - T_min;
552 static const size_t LUT_samples = 1<<16;
553
554 struct pair min_radius = { FLT_MAX, 0.0f };
555
556#if !(defined(__apple_build_version__) && __apple_build_version__ < 11030000) //makes Xcode 11.3.1 compiler crash
557__OMP_PARALLEL_FOR__(reduction(pairmin:min_radius))
558#endif
559 for(size_t i = 0; i < LUT_samples; i++)
560 {
561 // we need more values for the low temperatures, so we scale the step with a power
562 const float step = powf((float)i / (float)(LUT_samples - 1), 4.0f);
563
564 // Current temperature in the lookup range
565 const float T = T_min + step * T_range;
566
567 // Current x, y chromaticity
568 float x_bb, y_bb;
569
570 if(T >= 4000.f)
571 CCT_to_xy_daylight(T, &x_bb, &y_bb);
572 else
573 CCT_to_xy_blackbody(T, &x_bb, &y_bb);
574
575 // Compute distance between current planckian chromaticity and input
576 const pair radius_tmp = { dt_fast_hypotf((x_bb - x), (y_bb - y)), T };
577
578 // If we found a smaller radius, save it
579 min_radius = pair_min(min_radius, radius_tmp);
580 }
581
582 return min_radius.temperature;
583}
584// clang-format off
585// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
586// vim: shiftwidth=2 expandtab tabstop=2 cindent
587// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
588// 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:309
static const dt_aligned_pixel_simd_t illuminant
Definition chromatic_adaptation.h:307
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:701
const float i
Definition colorspaces_inline_conversions.h:440
dt_XYZ_to_Rec709_D50(XYZ, rgb)
static dt_aligned_pixel_t XYZ
Definition colorspaces_inline_conversions.h:98
const dt_colormatrix_t dt_aligned_pixel_t out
Definition colorspaces_inline_conversions.h:42
const float n
Definition colorspaces_inline_conversions.h:678
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:327
gboolean dt_image_is_matrix_correction_supported(const dt_image_t *img)
Definition common/image.c:265
#define DT_ALIGNED_ARRAY
Definition darktable.h:388
#define __OMP_DECLARE_SIMD__(...)
Definition darktable.h:263
#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
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:225
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:326
static void illuminant_CCT_to_RGB(const float t, dt_aligned_pixel_t RGB)
Definition illuminants.h:208
static void illuminant_xy_to_RGB(const float x, const float y, dt_aligned_pixel_t RGB)
Definition illuminants.h:191
static void illuminant_xy_to_XYZ(const float x, const float y, dt_aligned_pixel_t XYZ)
Definition illuminants.h:182
static float xy_to_CCT(const float x, const float y)
Definition illuminants.h:127
static void CCT_to_xy_daylight(const float t, float *x, float *y)
Definition illuminants.h:139
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:543
static float get_tint_from_tinted_xy(const float x, const float y, const float t)
Definition illuminants.h:488
static float planckian_normal(const float x, const float t)
Definition illuminants.h:459
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:390
static void CCT_to_xy_blackbody(const float t, float *x, float *y)
Definition illuminants.h:158
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:355
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:476
static void xy_to_uv(const float xy[2], float uv[2])
Definition illuminants.h:501
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:530
@ DT_IMAGE_4BAYER
Definition image.h:127
static const float x
Definition iop_profile.h:235
const int t
Definition iop_profile.h:225
float *const restrict const size_t k
Definition luminance_mask.h:78
size_t size
Definition mipmap_cache.c:3
float dt_aligned_pixel_t[4]
Definition noiseprofile.c:28
const float r
Definition src/develop/noise_generator.h:101
Definition image.h:247
int32_t flags
Definition image.h:285
float d65_color_matrix[9]
Definition image.h:305
float adobe_XYZ_to_CAM[4][3]
Definition image.h:328
dt_aligned_pixel_t wb_coeffs
Definition image.h:325
Definition illuminants.h:525
float temperature
Definition illuminants.h:527
float radius
Definition illuminants.h:526