RGB到HSL和返回,计算问题

我正在尝试将RGB转换为HSL,我也想将HSL转换为RGB,我已经为它编写了一个类但是如果我做RGB-> HSL-> RGB来尝试它是否有效我会得到一个不同的值。

示例案例:如果通过执行HSLColor MyTestConversion = HSLColor.FromRGB(Colors.Green);创建HSLColor对象HSLColor MyTestConversion = HSLColor.FromRGB(Colors.Green); 然后做Color ExpectedGreenHere = MyTestConversion.ToRGB()你得到一个不同于Colors.Green颜色,而它是原始输入所以出错了..

这是我正在使用的代码:

 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  1) H -= 1.0f; } return new HSLColor(H, S, L); } private float Hue_2_RGB(float v1, float v2, float vH) { 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; } } 

使用参考: EasyRGB Color Math

除了精度问题,我认为你的实际算法是不正确的。 这应该是你的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); } 

接下来你要理解的是我们从0到255获取整数RGB值并将它们转换为从0到1的十进制值。我们得到的HSL因此需要转换为正常度/百分比/你习惯的百分比。 返回的H值应该是从0到6,所以要将它转换为度数,你只需乘以60. H实际上可能是负数,所以如果它只是加上360;

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

SL也需要乘以100才能得到0到100之间的百分比。

UPDATE

这段代码可以让你从HSL到RGB。 它假定HSL值仍为十进制格式。 另外,我在下面的代码中使用了double而不是float来获得更好的精度。

  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; } 

常见的bug。 你有

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

准确地告诉我R的哪些值可以导致_R不为0.(提示:只有一个)。

编辑:你在ToRGB()中有1/3的问题。

我在您的代码中看到的问题如下:

 float _R = (R / 255); 

你基本上在这里做整数除法,所以你失去了很多精度。

尝试将其更改为:

 float _R = (R / 255f); 

(和其他2行相同)。

另外,为了进一步提高精度,最好使用double而不是float。