c# colors rgb hsl

c# - RGB a HSL y viceversa, problemas de cálculo



colors (3)

Además de los problemas de precisión, creo que su algoritmo real es incorrecto. Este debería ser tu FromRGB:

public static HSLColor FromRGB(Byte R, Byte G, Byte B) { float _R = (R / 255f); float _G = (G / 255f); float _B = (B / 255f); float _Min = Math.Min(Math.Min(_R, _G), _B); float _Max = Math.Max(Math.Max(_R, _G), _B); float _Delta = _Max - _Min; float H = 0; float S = 0; float L = (float)((_Max + _Min) / 2.0f); if (_Delta != 0) { if (L < 0.5f) { S = (float)(_Delta / (_Max + _Min)); } else { S = (float)(_Delta / (2.0f - _Max - _Min)); } if (_R == _Max) { H = (_G - _B) / _Delta; } else if (_G == _Max) { H = 2f + (_B - _R) / _Delta; } else if (_B == _Max) { H = 4f + (_R - _G) / _Delta; } } return new HSLColor(H, S, L); }

Lo siguiente que debe entender es que estamos tomando valores RGB enteros de 0 a 255 y convirtiéndolos a valores decimales de 0 a 1. Por lo tanto, la HSL que obtenemos debe ser convertida al grado / porcentaje / normal por ciento a que estás acostumbrado. El valor de H devuelto debe ser de 0 a 6, por lo tanto, para convertirlo a grados, simplemente multiplique por 60. H puede ser negativo a veces, de modo que si solo agrega 360;

//Convert to degrees H = H * 60f; if (H < 0) H += 360;

S y L también necesitan multiplicarse por 100 para darte un porcentaje de 0 a 100.

ACTUALIZAR

Este código debería llevarlo de HSL a RGB. Supone que los valores de HSL todavía están en su formato decimal. Además, utilicé el doble en lugar de flotar en el siguiente código para una mejor precisión.

public Color ToRGB() { byte r, g, b; if (Saturation == 0) { r = (byte)Math.Round(Luminosity * 255d); g = (byte)Math.Round(Luminosity * 255d); b = (byte)Math.Round(Luminosity * 255d); } else { double t1, t2; double th = Hue / 6.0d; if (Luminosity < 0.5d) { t2 = Luminosity * (1d + Saturation); } else { t2 = (Luminosity + Saturation) - (Luminosity * Saturation); } t1 = 2d * Luminosity - t2; double tr, tg, tb; tr = th + (1.0d / 3.0d); tg = th; tb = th - (1.0d / 3.0d); tr = ColorCalc(tr, t1, t2); tg = ColorCalc(tg, t1, t2); tb = ColorCalc(tb, t1, t2); r = (byte)Math.Round(tr * 255d); g = (byte)Math.Round(tg * 255d); b = (byte)Math.Round(tb * 255d); } return Color.FromArgb(r, g, b); } private static double ColorCalc(double c, double t1, double t2) { if (c < 0) c += 1d; if (c > 1) c -= 1d; if (6.0d * c < 1.0d) return t1 + (t2 - t1) * 6.0d * c; if (2.0d * c < 1.0d) return t2; if (3.0d * c < 2.0d) return t1 + (t2 - t1) * (2.0d / 3.0d - c) * 6.0d; return t1; }

Estoy tratando de convertir RGB a HSL y también quiero convertir de HSL a RGB, he escrito una clase para eso, pero si hago RGB-> HSL-> RGB para probar si funciona, obtengo un valor diferente.

Ejemplo de caso: si crea un objeto HSLColor MyTestConversion = HSLColor.FromRGB(Colors.Green); haciendo HSLColor MyTestConversion = HSLColor.FromRGB(Colors.Green); y luego haga Color ExpectedGreenHere = MyTestConversion.ToRGB() obtendrá un color diferente que Colors.Green mientras era la entrada original, por lo que algo sale mal.

Este es el código que estoy usando:

public class HSLColor { public float Hue; public float Saturation; public float Luminosity; public HSLColor(float H, float S, float L) { Hue = H; Saturation = S; Luminosity = L; } public static HSLColor FromRGB(Color Clr) { return FromRGB(Clr.R, Clr.G, Clr.B); } public static HSLColor FromRGB(Byte R, Byte G, Byte B) { float _R = (R / 255f); float _G = (G / 255f); float _B = (B / 255f); float _Min = Math.Min(Math.Min(_R, _G), _B); float _Max = Math.Max(Math.Max(_R, _G), _B); float _Delta = _Max - _Min; float H = 0; float S = 0; float L = (float)((_Max + _Min) / 2.0f); if (_Delta != 0) { if (L < 0.5f) { S = (float)(_Delta / (_Max + _Min)); } else { S = (float)(_Delta / (2.0f - _Max - _Min)); } float _Delta_R = (float)(((_Max - _R) / 6.0f + (_Delta / 2.0f)) / _Delta); float _Delta_G = (float)(((_Max - _G) / 6.0f + (_Delta / 2.0f)) / _Delta); float _Delta_B = (float)(((_Max - _B) / 6.0f + (_Delta / 2.0f)) / _Delta); if (_R == _Max) { H = _Delta_B - _Delta_G; } else if (_G == _Max) { H = (1.0f / 3.0f) + _Delta_R - _Delta_B; } else if (_B == _Max) { H = (2.0f / 3.0f) + _Delta_G - _Delta_R; } if (H < 0) H += 1.0f; if (H > 1) H -= 1.0f; } return new HSLColor(H, S, L); } private float Hue_2_RGB(float v1, float v2, float vH) { if (vH < 0) vH += 1; if (vH > 1) vH -= 1; if ((6 * vH) < 1) return (v1 + (v2 - v1) * 6 * vH); if ((2 * vH) < 1) return (v2); if ((3 * vH) < 2) return (v1 + (v2 - v1) * ((2 / 3) - vH) * 6); return (v1); } public Color ToRGB() { Color Clr = new Color(); float var_1, var_2; if (Saturation == 0) { Clr.R = (Byte)(Luminosity * 255); Clr.G = (Byte)(Luminosity * 255); Clr.B = (Byte)(Luminosity * 255); } else { if (Luminosity < 0.5) var_2 = Luminosity * (1 + Saturation); else var_2 = (Luminosity + Saturation) - (Saturation * Luminosity); var_1 = 2 * Luminosity - var_2; Clr.R = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue + (1 / 3))); Clr.G = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue)); Clr.B = (Byte)(255 * Hue_2_RGB(var_1, var_2, Hue - (1 / 3))); } return Clr; } }

Referencia utilizada: EasyRGB Color Math


El problema que veo en tu código es el siguiente:

float _R = (R / 255);

Básicamente estás haciendo una división de enteros aquí, así que estás perdiendo toneladas de precisión.

Intenta cambiarlo a:

float _R = (R / 255f);

(y lo mismo para las otras 2 líneas).

Además, para aumentar la precisión aún más, mejor usar doble en lugar de flotar.


Error común Tienes

public static HSLColor FromRGB(Byte R, Byte G, Byte B) { float _R = (R / 255); float _G = (G / 255); float _B = (B / 255);

Dígame con precisión qué valores de R pueden dar como resultado que _R no sea 0. (Sugerencia: solo hay uno).

Editar: tienes el mismo problema en ToRGB () con 1/3.