[darktable-dev] HSL and RGB scene-referred space
Hello, In colorspaces.c there is the following code to convert between RGB and HSL: void rgb2hsl(const float rgb[3], float *h, float *s, float *l) { const float r = rgb[0], g = rgb[1], b = rgb[2]; float pmax = fmax(r, fmax(g, b)); float pmin = fmin(r, fmin(g, b)); float delta = (pmax - pmin); float hv = 0, sv = 0, lv = (pmin + pmax) / 2.0; if(pmax != pmin) { sv = lv < 0.5 ? delta / (pmax + pmin) : delta / (2.0 - pmax - pmin); if(pmax == r) hv = (g - b) / delta; else if(pmax == g) hv = 2.0 + (b - r) / delta; else if(pmax == b) hv = 4.0 + (r - g) / delta; hv /= 6.0; if(hv < 0.0) hv += 1.0; else if(hv > 1.0) hv -= 1.0; } *h = hv; *s = sv; *l = lv; } Due to the way the saturation is computed, it looks like this function expects the RGB values to be limited to the range [0.0,1.0]. When using the filmic module and exposing for the middle gray with the exposure module, we have (in the default iop order) a set of modules (those between the exposure module and the filmic module) that may have, as input RGB, values higher than 1.0. This may cause the conversion to HSL to produce inaccurate values, right? Some examples of functionalities that could have issues: channel mixer, color picker (used in the blending and modules like the color balance), some blending modes. Some questions: - Is this a real issue or is this a bad usage of darktable? I.e. shall we never have RGB values higher that 1.0 in the pipe? - In the case this should ideally be fixed, I see three possibilities, are there others? 1. Use another hue/saturation/lightness estimator: HSV (although value is really different than lightness) or LCh (probably a lot more computationally intensive), ... 2. Scale the RGB values based on some definition of "white" (maximum luminance) using additional graphical widgets, but this would probably overwhelm the users with options and sliders 3. Scale the RGB values based on some definition of "white" (maximum luminance) using the "processed_maximum" value in the pixel pipe, but it looks like some modules do not update it: e.g. filmic, rgb curve and base curve - What is the best way to keep the backward compatibility in the case algorithms are changed? Thanks a lot in advance for your feedback, Harold ___ darktable developer mailing list to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org
Re: [darktable-dev] HSL and RGB scene-referred space
On 10.4.20 11:27, Harold le Clément wrote: - Is this a real issue or is this a bad usage of darktable? I.e. shall we never have RGB values higher that 1.0 in the pipe? As a user I would expect to keep the dynamic range throughout the pipe for as long as possible. If a module clips it would actually help if this was indicated in the UI. Maybe with a little warning sign icon or the like, on the module. - In the case this should ideally be fixed, I see three possibilities, are there others? 1. Use another hue/saturation/lightness estimator: HSV (although value is really different than lightness) or LCh (probably a lot more computationally intensive), ... Yes, I would second looking into the cylindrical models, LCh/HCL/CIELab/CIELuv, as better alternatives (https://arxiv.org/abs/1903.06490). Just my two c. As I said, I'm just a user of DT. .mm ___ darktable developer mailing list to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org
Re: [darktable-dev] HSL and RGB scene-referred space
Hi, HSL/HSV are only meant to be GUI convenience space to allow the user to quickly define an RGB parameter. They are not supposed to be used to actually push pixels, since they are neither physically-referred or perceptually-referred. No image should ever be converted to actual HSL space (aside from geeky play violating psychophysics). So, I wonder where this is a problem in a scene-linear (unbounded) workflow. Only the saturation is implicitely "bounded" (or, more exactly, will be negative if pmax and pmin > 1 or NaN if pmax = pmin = 1, wich – good catch – needs to be solved). Even if you are defining parametric masks in HSL, the only component relevant to pull a key is H, since the 2 others are meaningless pixel gibberish. One could try a cylindrical HSY for parametric masking, at least the luminance and saturation would have some perceptual connection. But the hue would still be half-garbage. And please, let Lch/Luv where they belong : in museums. This space is built around the implicit that the image has 6.5 EV dynamic range (assumed to be the static DR of the retina in 1976), so it is really not suited as a working space when your average sensor blasts easily 12 EV DR at base ISO. Cheers, Aurélien. Le 10/04/2020 à 11:27, Harold le Clément a écrit : > Hello, > > In colorspaces.c there is the following code to convert between RGB and HSL: > > void rgb2hsl(const float rgb[3], float *h, float *s, float *l) > { > const float r = rgb[0], g = rgb[1], b = rgb[2]; > float pmax = fmax(r, fmax(g, b)); > float pmin = fmin(r, fmin(g, b)); > float delta = (pmax - pmin); > > float hv = 0, sv = 0, lv = (pmin + pmax) / 2.0; > > if(pmax != pmin) > { > sv = lv < 0.5 ? delta / (pmax + pmin) : delta / (2.0 - pmax - pmin); > > if(pmax == r) > hv = (g - b) / delta; > else if(pmax == g) > hv = 2.0 + (b - r) / delta; > else if(pmax == b) > hv = 4.0 + (r - g) / delta; > hv /= 6.0; > if(hv < 0.0) > hv += 1.0; > else if(hv > 1.0) > hv -= 1.0; > } > *h = hv; > *s = sv; > *l = lv; > } > > Due to the way the saturation is computed, it looks like this function > expects the RGB values to be limited to the range [0.0,1.0]. > > When using the filmic module and exposing for the middle gray with the > exposure module, we have (in the default iop order) a set of modules > (those between the exposure module and the filmic module) that may > have, as input RGB, values higher than 1.0. This may cause the > conversion to HSL to produce inaccurate values, right? > > Some examples of functionalities that could have issues: channel > mixer, color picker (used in the blending and modules like the color > balance), some blending modes. > > Some questions: > > - Is this a real issue or is this a bad usage of darktable? I.e. shall > we never have RGB values higher that 1.0 in the pipe? > > - In the case this should ideally be fixed, I see three possibilities, > are there others? > > 1. Use another hue/saturation/lightness estimator: HSV (although value > is really different than lightness) or LCh (probably a lot more > computationally intensive), ... > > 2. Scale the RGB values based on some definition of "white" (maximum > luminance) using additional graphical widgets, but this would probably > overwhelm the users with options and sliders > > 3. Scale the RGB values based on some definition of "white" (maximum > luminance) using the "processed_maximum" value in the pixel pipe, but > it looks like some modules do not update it: e.g. filmic, rgb curve > and base curve > > - What is the best way to keep the backward compatibility in the case > algorithms are changed? > > Thanks a lot in advance for your feedback, > > Harold > ___ > darktable developer mailing list > to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org > ___ darktable developer mailing list to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org
Re: [darktable-dev] HSL and RGB scene-referred space
Hello, Thanks a lot for the feedback. Agree, the problem would be only when trying to use the saturation for parametric masking (as the color picker HSL mode is only used for that). Perhaps a cylindrical HSY could be used, but it depends how the saturation is computed (most of the information I could find on the Internet suppose that the RGB values are bounded). Anyway, in the mean time I could just disregard the saturation selector. Thanks, Harold ___ darktable developer mailing list to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org
Re: [darktable-dev] HSL and RGB scene-referred space
Hello, 1. you go from RGB to XYZ using the ICC profile of the RGB space you are using, which gives you the coeffs of the 3×3 matrix RGB -> XYZ. Call that matrix M. Do a matrix dot product [XYZ] = [M] * [RGB] 2. you go from XYZ to Yxy using x = X / (X + Y + Z) and y = Y / (X + Y + Z) 3. you subtract the x and y values by those of the white point you are using (usually, D50). That's x_D50 = 0.34567 and y_D50 = 0.35850, using 2° CIE 1931 observer. So x = X / (X + Y + Z) - x_D50 and y = Y / (X + Y + Z) - y_D50, 4. then, hue = arctan2(y, x), saturation = sqrt(x^2 + y^2) 5. since it's only to produce a boolean mask, you don't need to bother about the back transform. But in case you need : 1. x = saturation * cos(hue) + x_D50, y = saturation * sin(hue) + y_D50 2. X = xY / y, Y = Y, Z = (1 - x - y) * Y / y 3. and then, again, matrix dot product [RGB] = [M^-1] * [XYZ] where [M^-1] is the inverse of the matrix M formed with the ICC profile coefficients. Cheers, Aurélien. Le 11/04/2020 à 18:23, Harold le Clément a écrit : > Hello, > > Thanks a lot for the feedback. > > Agree, the problem would be only when trying to use the saturation for > parametric masking (as the color picker HSL mode is only used for > that). > > Perhaps a cylindrical HSY could be used, but it depends how the > saturation is computed (most of the information I could find on the > Internet suppose that the RGB values are bounded). > > Anyway, in the mean time I could just disregard the saturation selector. > > Thanks, > > Harold > ___ > darktable developer mailing list > to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org > ___ darktable developer mailing list to unsubscribe send a mail to darktable-dev+unsubscr...@lists.darktable.org