Skip to content

Commit 6d612e0

Browse files
committed
wb: added DT_ILLUMINANT_FROM_WB, separated find_temperature_from_raw_coeffs into find_temperature_from_wb_coeffs, find_temperature_from_as_shot_coeffs; added handling to channelmixerrgb.c + altered logic for 'late correction' check
1 parent fd60099 commit 6d612e0

4 files changed

Lines changed: 273 additions & 118 deletions

File tree

src/common/illuminants.h

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ typedef enum dt_illuminant_t
3434
DT_ILLUMINANT_BB = 6, // $DESCRIPTION: "Planckian (black body)" general black body radiator - not CIE standard
3535
DT_ILLUMINANT_CUSTOM = 7, // $DESCRIPTION: "custom" input x and y directly - bypass search
3636
DT_ILLUMINANT_CAMERA = 10,// $DESCRIPTION: "as shot in camera" read RAW EXIF for WB
37+
DT_ILLUMINANT_FROM_WB = 11,// $DESCRIPTION: "as set in white balance module" read coefficients from the white balance module
3738
DT_ILLUMINANT_LAST,
3839
DT_ILLUMINANT_DETECT_SURFACES = 8,
3940
DT_ILLUMINANT_DETECT_EDGES = 9,
@@ -215,19 +216,22 @@ static inline void illuminant_CCT_to_RGB(const float t, dt_aligned_pixel_t RGB)
215216
illuminant_xy_to_RGB(x, y, RGB);
216217
}
217218

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);
218221

219222
// Fetch image from pipeline and read EXIF for camera RAW WB coeffs
220-
static inline gboolean find_temperature_from_raw_coeffs(const dt_image_t *img, const dt_aligned_pixel_t custom_wb,
223+
static inline gboolean find_temperature_from_as_shot_coeffs(const dt_image_t *img, const dt_aligned_pixel_t correction_ratios,
221224
float *chroma_x, float *chroma_y);
222225

223226

224-
static inline int illuminant_to_xy(const dt_illuminant_t illuminant, // primary type of illuminant
225-
const dt_image_t *img, // image container
226-
const dt_aligned_pixel_t custom_wb, // optional user-set WB coeffs
227-
float *x_out, float *y_out, // chromaticity output
228-
const float t, // temperature in K, if needed
229-
const dt_illuminant_fluo_t fluo, // sub-type of fluorescent illuminant, if needed
230-
const dt_illuminant_led_t iled) // sub-type of led illuminant, if needed
227+
static inline int illuminant_to_xy(const dt_illuminant_t illuminant, // primary type of illuminant
228+
const dt_image_t *img, // image container
229+
const dt_aligned_pixel_t correction_ratios, // optional D65 correction ratios derived from user-set coefficients
230+
const dt_aligned_pixel_t wb_coeffs, // optional user-set WB coeffs (absolute)
231+
float *x_out, float *y_out, // chromaticity output
232+
const float t, // temperature in K, if needed
233+
const dt_illuminant_fluo_t fluo, // sub-type of fluorescent illuminant, if needed
234+
const dt_illuminant_led_t iled) // sub-type of led illuminant, if needed
231235
{
232236
/**
233237
* Compute the x and y chromaticity coordinates in Yxy spaces for standard illuminants
@@ -298,9 +302,15 @@ static inline int illuminant_to_xy(const dt_illuminant_t illuminant, // primary
298302
}
299303
case DT_ILLUMINANT_CAMERA:
300304
{
301-
// Detect WB from RAW EXIF
305+
// Detect WB from RAW EXIF, correcting with D65/wb_coeff ratios
302306
if(img)
303-
if(find_temperature_from_raw_coeffs(img, custom_wb, &x, &y)) break;
307+
if(find_temperature_from_as_shot_coeffs(img, correction_ratios, &x, &y)) break;
308+
}
309+
case DT_ILLUMINANT_FROM_WB:
310+
{
311+
// Detect WB from user-provided coefficients
312+
if(img)
313+
if(find_temperature_from_wb_coeffs(img, wb_coeffs, &x, &y)) break;
304314
}
305315
case DT_ILLUMINANT_CUSTOM: // leave x and y as-is
306316
case DT_ILLUMINANT_DETECT_EDGES:
@@ -385,31 +395,11 @@ static inline void matrice_pseudoinverse(float (*in)[3], float (*out)[3], int si
385395
}
386396
}
387397

388-
389-
static gboolean find_temperature_from_raw_coeffs(const dt_image_t *img, const dt_aligned_pixel_t custom_wb,
390-
float *chroma_x, float *chroma_y)
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])
391400
{
392-
if(img == NULL) return FALSE;
393-
if(!dt_image_is_matrix_correction_supported(img)) return FALSE;
394-
395-
gboolean has_valid_coeffs = TRUE;
396-
const int num_coeffs = (img->flags & DT_IMAGE_4BAYER) ? 4 : 3;
397-
398-
// Check coeffs
399-
for(int k = 0; has_valid_coeffs && k < num_coeffs; k++)
400-
if(!dt_isnormal(img->wb_coeffs[k]) || img->wb_coeffs[k] == 0.0f) has_valid_coeffs = FALSE;
401-
402-
if(!has_valid_coeffs) return FALSE;
403-
404-
// Get white balance camera factors
405-
dt_aligned_pixel_t WB = { img->wb_coeffs[0], img->wb_coeffs[1], img->wb_coeffs[2], img->wb_coeffs[3] };
406-
407-
// Adapt the camera coeffs with custom white balance if provided
408-
// this can deal with WB coeffs that don't use the input matrix reference
409-
if(custom_wb)
410-
for(size_t k = 0; k < 4; k++) WB[k] *= custom_wb[k];
411-
412-
// Get the camera input profile (matrice of primaries)
401+
if(img == NULL || CAM_to_XYZ == NULL) return FALSE;
402+
// Get the camera input profile (matrice of primaries) - embedded or raw library DB
413403
float XYZ_to_CAM[4][3];
414404
dt_mark_colormatrix_invalid(&XYZ_to_CAM[0][0]);
415405

@@ -438,21 +428,61 @@ static gboolean find_temperature_from_raw_coeffs(const dt_image_t *img, const dt
438428

439429
if(!dt_is_valid_colormatrix(XYZ_to_CAM[0][0])) return FALSE;
440430

441-
// Bloody input matrices define XYZ -> CAM transform, as if we often needed camera profiles to output
442-
// So we need to invert them. Here go your CPU cycles again.
443-
float CAM_to_XYZ[4][3];
444431
dt_mark_colormatrix_invalid(&CAM_to_XYZ[0][0]);
445432
matrice_pseudoinverse(XYZ_to_CAM, CAM_to_XYZ, 3);
446-
if(!dt_is_valid_colormatrix(CAM_to_XYZ[0][0])) return FALSE;
433+
return dt_is_valid_colormatrix(CAM_to_XYZ[0][0]);
434+
}
435+
436+
// returns FALSE if failed; TRUE if successful
437+
static gboolean find_temperature_from_wb_coeffs(const dt_image_t *img, const dt_aligned_pixel_t wb_coeffs,
438+
float *chroma_x, float *chroma_y)
439+
{
440+
if(img == NULL || wb_coeffs == NULL) return FALSE;
441+
if(!dt_image_is_matrix_correction_supported(img)) return FALSE;
442+
443+
float CAM_to_XYZ[4][3];
444+
if(!get_CAM_to_XYZ(img, CAM_to_XYZ)) {
445+
return FALSE;
446+
}
447447

448448
float x, y;
449-
WB_coeffs_to_illuminant_xy(CAM_to_XYZ, WB, &x, &y);
449+
WB_coeffs_to_illuminant_xy(CAM_to_XYZ, wb_coeffs, &x, &y);
450450
*chroma_x = x;
451451
*chroma_y = y;
452452

453453
return TRUE;
454454
}
455455

456+
// returns FALSE if failed; TRUE if successful
457+
static gboolean find_temperature_from_as_shot_coeffs(const dt_image_t *img, const dt_aligned_pixel_t correction_ratios,
458+
float *chroma_x, float *chroma_y)
459+
{
460+
if(img == NULL) return FALSE;
461+
462+
gboolean has_valid_coeffs = TRUE;
463+
const int num_coeffs = (img->flags & DT_IMAGE_4BAYER) ? 4 : 3;
464+
465+
// Check coeffs
466+
for(int k = 0; has_valid_coeffs && k < num_coeffs; k++)
467+
if(!dt_isnormal(img->wb_coeffs[k]) || img->wb_coeffs[k] == 0.0f) has_valid_coeffs = FALSE;
468+
469+
if(!has_valid_coeffs) return FALSE;
470+
471+
// Get as-shot white balance camera factors (from raw)
472+
// component wise raw-RGB * wb_coeffs should provide R=G=B for a neutral patch under
473+
// the scene illuminant
474+
dt_aligned_pixel_t WB = { img->wb_coeffs[0], img->wb_coeffs[1], img->wb_coeffs[2], img->wb_coeffs[3] };
475+
476+
// Adapt the camera coeffs with custom D65 coefficients if provided ('caveats' workaround)
477+
// this can deal with WB coeffs that don't use the input matrix reference
478+
// adaptation_ratios[k] = chr->D65coeffs[k] / chr->wb_coeffs[k]
479+
if(correction_ratios)
480+
for(size_t k = 0; k < 4; k++) WB[k] *= correction_ratios[k];
481+
// for a neutral surface, raw RGB * img->wb_coeffs would produce neutral R=G=B
482+
483+
return find_temperature_from_wb_coeffs(img, WB, chroma_x, chroma_y);
484+
}
485+
456486

457487
DT_OMP_DECLARE_SIMD()
458488
static inline float planckian_normal(const float x, const float t)

src/develop/develop.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ typedef struct dt_dev_viewport_t
147147
- the currently used wb_coeffs in temperature module
148148
- D65coeffs and as_shot are read from exif data
149149
f) - late_correction set by temperature if we want to process data as following
150-
If we use the new DT_IOP_TEMP_D65_LATE mode in temperature.c and don#t have
151-
any temp parameters changes later we can calc correction coeffs to modify
152-
as_shot rgb data to D65
150+
If we use the new DT_IOP_TEMP_D65_LATE mode or enable this in user modes of temperature.c
151+
and don't have any temp parameters changes later we can calc correction ratios
152+
to take white-balanced (neutralized) data to D65
153153
*/
154154
typedef struct dt_dev_chroma_t
155155
{

0 commit comments

Comments
 (0)