Question

Je suis en train de convertir RVB à HSL et je veux aussi convertir HSL en RVB, Je l'ai écrit une classe pour elle, mais si je fais RVB-> HSL-> RGB pour essayer si cela fonctionne, je reçois une valeur différente.

Exemple de cas: si vous créez un objet HSLColor en faisant HSLColor MyTestConversion = HSLColor.FromRGB(Colors.Green); puis ne Color ExpectedGreenHere = MyTestConversion.ToRGB() vous obtenez une couleur différente de celle Colors.Green alors qu'il était l'entrée d'origine si quelque chose va mal ..

Ceci est le code j'utilise:

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

Référence occasion:

Était-ce utile?

La solution

En plus des problèmes de précision, je pense que votre algorithme réel est incorrect. Cela devrait être votre 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);
    }

La prochaine chose que vous devez comprendre est que nous prenons entier des valeurs RVB de 0 à 255 et les convertir en valeurs décimales de 0 à 1. Le HSL que nous revenions devra donc être converti en degré normal / pour cent / pour cent que vous êtes habitué. La valeur H retournée doit être de 0 à 6 afin de le convertir en degrés que vous venez de multiplier par 60. H peut effectivement être parfois négative si elle est juste ajouter 360;

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

S et L doivent également être multiplié par 100 pour vous donner un pourcentage de 0 à 100.

UPDATE

Ce code devrait vous obtenir de HSL RVB. Il suppose que les valeurs HSL sont encore dans leur format décimal. En outre, je double au lieu de flotter dans le code ci-dessous pour une meilleure précision.

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

Autres conseils

bug commun. Vous avez

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

Dites-moi précisément quelles sont les valeurs de R peuvent entraîner _R ne pas être 0. (Astuce: il n'y a qu'une seule).

Edit:. Vous avez le même problème dans ToRGB () avec 1/3

The problem I see in your code is the following:

float _R = (R / 255);

You are basically doing integer division here, so you are losing tons of precision.

Try changing it to:

float _R = (R / 255f);

(and the same for the other 2 lines).

Also, to increase precision even more, better to use double instead of float.

scroll top