Jump to content

Hue math formula (it matches Microsoft's, but not others') what is it?


Go to solution Solved by Rick Brewster,

Recommended Posts

Microsoft Window's has a ColorRGBToHLS function that matches Paint.net's Hue readout. This function is in the range 0-240 and doesn't do lossless conversion of the same color in and out (round trip).
Other sources give vastly different results for hue: 
https://www.chilliant.com/rgb2hsv.html
https://en.wikipedia.org/wiki/Hue

I think it might be a sRGB/linear color space thing, but linearizing my inputs to these functions doesn't appreciably change the results. Paint.net's looks better, but I just started by using its data via its color picker, and now I don't have a color picker that matches these other functions. I may try GIMP later. I'd like to know what math/formula Paint.net is using please.

Thank you!

Link to comment
Share on other sites

This is the code for it. Hue is between 0-360, Saturation is 0-100, and Value is 0-100.

 

Paint.NET always uses sRGB, unless you are a plugin developer implementing a GpuEffect in which case the default is linear (converted from sRGB) (and you can specify you don't want linearization).

 

public readonly Int32RgbColor ToRgb()
{
    // Int32HsvColor contains values scaled as in the color wheel:

    // Scale Hue to be between 0 and 360. Saturation
    // and value scale to be between 0 and 1.
    double h = (double)(this.Hue % 360);
    double s = (double)this.Saturation / 100;
    double v = (double)this.Value / 100;

    double r;
    double g;
    double b;
    if (s == 0)
    {
        // If s is 0, all colors are the same.
        // This is some flavor of gray.
        r = v;
        g = v;
        b = v;
    }
    else
    {
        // The color wheel consists of 6 sectors.
        // Figure out which sector you're in.
        double sectorPos = h / 60.0;
        int sectorNumber = (int)(Math.Floor(sectorPos));

        // get the fractional part of the sector.
        // That is, how many degrees into the sector
        // are you?
        double fractionalSector = sectorPos - sectorNumber;

        // Calculate values for the three axes
        // of the color. 
        double p = v * (1 - s);
        double q = v * (1 - (s * fractionalSector));
        double t = v * (1 - (s * (1 - fractionalSector)));

        // Assign the fractional colors to r, g, and b
        // based on the sector the angle is in.
        switch (sectorNumber)
        {
            default:
            case 0:
                r = v;
                g = t;
                b = p;
                break;

            case 1:
                r = q;
                g = v;
                b = p;
                break;

            case 2:
                r = p;
                g = v;
                b = t;
                break;

            case 3:
                r = p;
                g = q;
                b = v;
                break;

            case 4:
                r = t;
                g = p;
                b = v;
                break;

            case 5:
                r = v;
                g = p;
                b = q;
                break;
        }
    }

    // return an RgbColor structure, with values scaled
    // to be between 0 and 255.
    return new Int32RgbColor(
        DoubleUtil.ClampToByte(r * 255),
        DoubleUtil.ClampToByte(g * 255),
        DoubleUtil.ClampToByte(b * 255));
}

 

  • Like 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

I'm sorry. Can you please share your corresponding RGB to HSV function? Your function here is smoother here than others. But I'm getting a green shift when using Microsoft's ColorRGBToHLS function combined with HSL->HSV to pump into your function. (The printout of its hue table looks promising. I can't figure out what I'm doing wrong, but so far only Microsoft's code is succeeding for me, and I'm a seasoned developer. I think if I have both of yours then I can see how it stands up. I still feel like I'm missing something though, since I can't seem to get approximate success with any of my own functions I've written.)

Link to comment
Share on other sites

  • Solution
public readonly Int32HsvColor ToHsv()
{
    // In this function, R, G, and B values must be scaled 
    // to be between 0 and 1.
    // Int32HsvColor.Hue will be a value between 0 and 360, and 
    // Int32HsvColor.Saturation and value are between 0 and 1.

    double min;
    double max;
    double delta;

    double r = (double)this.Red / 255;
    double g = (double)this.Green / 255;
    double b = (double)this.Blue / 255;

    double h;
    double s;
    double v;

    min = Math.Min(Math.Min(r, g), b);
    max = Math.Max(Math.Max(r, g), b);
    v = max;
    delta = max - min;

    if (max == 0 || delta == 0)
    {
        // R, G, and B must be 0, or all the same.
        // In this case, S is 0, and H is undefined.
        // Using H = 0 is as good as any...
        s = 0;
        h = 0;
    }
    else
    {
        s = delta / max;
        if (r == max)
        {
            // Between Yellow and Magenta
            h = (g - b) / delta;
        }
        else if (g == max)
        {
            // Between Cyan and Yellow
            h = 2 + (b - r) / delta;
        }
        else
        {
            // Between Magenta and Cyan
            h = 4 + (r - g) / delta;
        }

    }
    // Scale h to be between 0 and 360. 
    // This may require adding 360, if the value
    // is negative.
    h *= 60;

    if (h < 0)
    {
        h += 360;
    }

    return new Int32HsvColor((int)h, (int)(s * 100), (int)(v * 100));
}

 

  • Hugs 1

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

I found my main problem finally, it was I'd swapped the G and B members in my makeshift float4 structure. But luckily it led me to find your group's source code that matches Microsoft's. Basically it seems to provide a higher quality mapping of values than most of the code floating around the net. I don't know if it's more color correct, but it works with Paint.net! Thank you :)

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...