@@ -216,18 +216,15 @@ static inline void illuminant_CCT_to_RGB(const float t, dt_aligned_pixel_t RGB)
216216 illuminant_xy_to_RGB (x , y , RGB );
217217}
218218
219- static inline gboolean find_temperature_from_wb_coeffs (const dt_image_t * img , const dt_aligned_pixel_t wb_coeffs ,
220- float * chroma_x , float * chroma_y );
221219
222220// Fetch image from pipeline and read EXIF for camera RAW WB coeffs
223- static inline gboolean find_temperature_from_as_shot_coeffs (const dt_image_t * img , const dt_aligned_pixel_t adaptation_ratios ,
221+ static inline gboolean find_temperature_from_raw_coeffs (const dt_image_t * img , const dt_aligned_pixel_t custom_wb ,
224222 float * chroma_x , float * chroma_y );
225223
226224
227225static inline int illuminant_to_xy (const dt_illuminant_t illuminant , // primary type of illuminant
228226 const dt_image_t * img , // image container
229- const dt_aligned_pixel_t wb_coeffs ,
230- const dt_aligned_pixel_t adaptation_ratios , // optional ratios to adapt camera WB
227+ const dt_aligned_pixel_t custom_wb , // optional user-set WB coeffs
231228 float * x_out , float * y_out , // chromaticity output
232229 const float t , // temperature in K, if needed
233230 const dt_illuminant_fluo_t fluo , // sub-type of fluorescent illuminant, if needed
@@ -304,11 +301,13 @@ static inline int illuminant_to_xy(const dt_illuminant_t illuminant, // primary
304301 {
305302 // Detect WB from RAW EXIF
306303 if (img )
307- if (find_temperature_from_as_shot_coeffs (img , adaptation_ratios , & x , & y )) break ;
304+ if (find_temperature_from_raw_coeffs (img , custom_wb , & x , & y )) break ;
308305 }
309- case DT_ILLUMINANT_FROM_WB : {
306+ case DT_ILLUMINANT_FROM_WB :
307+ { // FIXME copy-paste
308+ // Detect WB from RAW EXIF
310309 if (img )
311- if (find_temperature_from_wb_coeffs (img , wb_coeffs , & x , & y )) break ;
310+ if (find_temperature_from_raw_coeffs (img , custom_wb , & x , & y )) break ;
312311 }
313312 case DT_ILLUMINANT_CUSTOM : // leave x and y as-is
314313 case DT_ILLUMINANT_DETECT_EDGES :
@@ -337,8 +336,6 @@ static inline void WB_coeffs_to_illuminant_xy(const float CAM_to_XYZ[4][3], cons
337336 dt_aligned_pixel_t XYZ , LMS ;
338337 // Simulate white point, aka convert (1, 1, 1) in camera space to XYZ
339338 // warning : we multiply the transpose of CAM_to_XYZ since the pseudoinverse transposes it
340- // if we're not in 'caveat' workaround mode, we'll push (1, 1, 1) through the matrix to find the
341- // XYZ of the illuminant
342339 XYZ [0 ] = CAM_to_XYZ [0 ][0 ] / WB [0 ] + CAM_to_XYZ [1 ][0 ] / WB [1 ] + CAM_to_XYZ [2 ][0 ] / WB [2 ];
343340 XYZ [1 ] = CAM_to_XYZ [0 ][1 ] / WB [0 ] + CAM_to_XYZ [1 ][1 ] / WB [1 ] + CAM_to_XYZ [2 ][1 ] / WB [2 ];
344341 XYZ [2 ] = CAM_to_XYZ [0 ][2 ] / WB [0 ] + CAM_to_XYZ [1 ][2 ] / WB [1 ] + CAM_to_XYZ [2 ][2 ] / WB [2 ];
@@ -395,10 +392,31 @@ static inline void matrice_pseudoinverse(float (*in)[3], float (*out)[3], int si
395392 }
396393}
397394
398- // returns TRUE is OK, FALSE if failed
399- static gboolean get_CAM_to_XYZ (const dt_image_t * img , float (* CAM_to_XYZ )[3 ])
395+
396+ static gboolean find_temperature_from_raw_coeffs (const dt_image_t * img , const dt_aligned_pixel_t custom_wb ,
397+ float * chroma_x , float * chroma_y )
400398{
401- // Get the camera input profile (matrice of primaries) - embedded or raw library DB
399+ if (img == NULL ) return FALSE;
400+ if (!dt_image_is_matrix_correction_supported (img )) return FALSE;
401+
402+ gboolean has_valid_coeffs = TRUE;
403+ const int num_coeffs = (img -> flags & DT_IMAGE_4BAYER ) ? 4 : 3 ;
404+
405+ // Check coeffs
406+ for (int k = 0 ; has_valid_coeffs && k < num_coeffs ; k ++ )
407+ if (!dt_isnormal (img -> wb_coeffs [k ]) || img -> wb_coeffs [k ] == 0.0f ) has_valid_coeffs = FALSE;
408+
409+ if (!has_valid_coeffs ) return FALSE;
410+
411+ // Get white balance camera factors
412+ dt_aligned_pixel_t WB = { img -> wb_coeffs [0 ], img -> wb_coeffs [1 ], img -> wb_coeffs [2 ], img -> wb_coeffs [3 ] };
413+
414+ // Adapt the camera coeffs with custom white balance if provided
415+ // this can deal with WB coeffs that don't use the input matrix reference
416+ if (custom_wb )
417+ for (size_t k = 0 ; k < 4 ; k ++ ) WB [k ] *= custom_wb [k ];
418+
419+ // Get the camera input profile (matrice of primaries)
402420 float XYZ_to_CAM [4 ][3 ];
403421 dt_mark_colormatrix_invalid (& XYZ_to_CAM [0 ][0 ]);
404422
@@ -427,60 +445,21 @@ static gboolean get_CAM_to_XYZ(const dt_image_t * img, float(* CAM_to_XYZ)[3])
427445
428446 if (!dt_is_valid_colormatrix (XYZ_to_CAM [0 ][0 ])) return FALSE;
429447
448+ // Bloody input matrices define XYZ -> CAM transform, as if we often needed camera profiles to output
449+ // So we need to invert them. Here go your CPU cycles again.
450+ float CAM_to_XYZ [4 ][3 ];
430451 dt_mark_colormatrix_invalid (& CAM_to_XYZ [0 ][0 ]);
431452 matrice_pseudoinverse (XYZ_to_CAM , CAM_to_XYZ , 3 );
432- return dt_is_valid_colormatrix (CAM_to_XYZ [0 ][0 ]);
433- }
434-
435- // returns FALSE if failed; TRUE if successful
436- static gboolean find_temperature_from_wb_coeffs (const dt_image_t * img , const dt_aligned_pixel_t wb_coeffs ,
437- float * chroma_x , float * chroma_y )
438- {
439- if (img == NULL || wb_coeffs ) return FALSE;
440- if (!dt_image_is_matrix_correction_supported (img )) return FALSE;
441-
442- float CAM_to_XYZ [4 ][3 ];
443- if (!get_CAM_to_XYZ (img , CAM_to_XYZ )) {
444- return FALSE;
445- }
453+ if (!dt_is_valid_colormatrix (CAM_to_XYZ [0 ][0 ])) return FALSE;
446454
447455 float x , y ;
448- WB_coeffs_to_illuminant_xy (CAM_to_XYZ , wb_coeffs , & x , & y );
456+ WB_coeffs_to_illuminant_xy (CAM_to_XYZ , WB , & x , & y );
449457 * chroma_x = x ;
450458 * chroma_y = y ;
451459
452460 return TRUE;
453461}
454462
455- // returns FALSE if failed; TRUE if successful
456- static gboolean find_temperature_from_as_shot_coeffs (const dt_image_t * img , const dt_aligned_pixel_t adaptation_ratios ,
457- float * chroma_x , float * chroma_y )
458- {
459- if (img == NULL ) return FALSE;
460-
461- gboolean has_valid_coeffs = TRUE;
462- const int num_coeffs = (img -> flags & DT_IMAGE_4BAYER ) ? 4 : 3 ;
463-
464- // Check coeffs
465- for (int k = 0 ; has_valid_coeffs && k < num_coeffs ; k ++ )
466- if (!dt_isnormal (img -> wb_coeffs [k ]) || img -> wb_coeffs [k ] == 0.0f ) has_valid_coeffs = FALSE;
467-
468- if (!has_valid_coeffs ) return FALSE;
469-
470- // Get as-shot white balance camera factors (from raw)
471- // component wise raw-RGB * wb_coeffs should provide R=G=B for a neutral patch under
472- // the scene illuminant
473- dt_aligned_pixel_t WB = { img -> wb_coeffs [0 ], img -> wb_coeffs [1 ], img -> wb_coeffs [2 ], img -> wb_coeffs [3 ] };
474-
475- // Adapt the camera coeffs with custom D65 coefficients if provided ('caveats' workaround)
476- // this can deal with WB coeffs that don't use the input matrix reference
477- // adaptation_ratios[k] = chr->D65coeffs[k] / chr->wb_coeffs[k]
478- if (adaptation_ratios )
479- for (size_t k = 0 ; k < 4 ; k ++ ) WB [k ] *= adaptation_ratios [k ];
480- // for a neutral surface, raw RGB * img->wb_coeffs would produce neutral R=G=B
481-
482- return find_temperature_from_wb_coeffs (img , WB , chroma_x , chroma_y );
483- }
484463
485464DT_OMP_DECLARE_SIMD ()
486465static inline float planckian_normal (const float x , const float t )
0 commit comments