颜色和谐理论和算法,计算互补、三元组、四元组等

JPS*_*ard 1 .net c# rgb colors color-space

目前正在开发一个应用程序,并试图从提供的基色中查找颜色(互补色、分裂互补色、类似色、三元色、四色、方形等...)。

我现在在做什么:

  1. 将 RGB 颜色转换为 HSV
  2. 调整 H 值以获得 360 度轮周围的颜色(S 和 V 值不变)
  3. 将 HSV 转换回 RGB

以下是 Triad 的示例(hsv 对象表示基色):

colors.Add(new HSVData() { h = hsv.h + 120, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h - 120, s = hsv.s, v = hsv.v });
Run Code Online (Sandbox Code Playgroud)

对于 Square:

colors.Add(new HSVData() { h = hsv.h + 90, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h + 180, s = hsv.s, v = hsv.v });
colors.Add(new HSVData() { h = hsv.h + 270, s = hsv.s, v = hsv.v });
Run Code Online (Sandbox Code Playgroud)

RGB 到 HSV:

public static HSVData RGBtoHSV(RGBResult RGB)
{
    double min;
    double max;
    double delta;

    double r = (double)RGB.r / 255;
    double g = (double)RGB.g / 255;
    double b = (double)RGB.b / 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)
    {
        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;
        } 
    }

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

    return new HSVData()
    {
        h = (int)(h / 360 * 255),
        s = (int)(s * 255),
        v = (int)(v * 255)
    };
}
Run Code Online (Sandbox Code Playgroud)

HSV 到 RGB:

public static Color ConvertHsvToRgb(float h, float s, float v)
{
    byte MAX = 255;

    h = h / 360;
    if (s > 0)
    {
        if (h >= 1)
            h = 0;
        h = 6 * h;
        int hueFloor = (int)Math.Floor(h);
        byte a = (byte)Math.Round(MAX * v * (1.0 - s));
        byte b = (byte)Math.Round(MAX * v * (1.0 - (s * (h - hueFloor))));
        byte c = (byte)Math.Round(MAX * v * (1.0 - (s * (1.0 - (h - hueFloor)))));
        byte d = (byte)Math.Round(MAX * v);

        switch (hueFloor)
        {
            case 0: return Color.FromArgb(MAX, d, c, a);
            case 1: return Color.FromArgb(MAX, b, d, a);
            case 2: return Color.FromArgb(MAX, a, d, c);
            case 3: return Color.FromArgb(MAX, a, b, d);
            case 4: return Color.FromArgb(MAX, c, a, d);
            case 5: return Color.FromArgb(MAX, d, a, b);
            default: return Color.FromArgb(0, 0, 0, 0);
        }
    }
    else
    {
        byte d = (byte)(v * MAX);
        return Color.FromArgb(255, d, d, d);
    }
}
Run Code Online (Sandbox Code Playgroud)

根据许多在线颜色工具,我得到的颜色是错误的!我应该使用 HSL 而不是 HSV?我究竟做错了什么?

在线工具与:

http://colorschemedesigner.com/

http://www.colorsontheweb.com/colorwizard.asp

提前致谢!

Dou*_*oug 5

您希望在 ConvertHsvToRgb 方法中获得什么范围的值?在我看来,它是这样的:

0 <= h <= 360
0 <= s <= 1.0
0 <= v <= 1.0
Run Code Online (Sandbox Code Playgroud)

您没有展示您如何调用此方法,但如果您不传递这些范围内的值,您将无法获得正确的转换。如果您计划减去色调,您可能希望包括一种将色调标准化为 0 - 360 的方法,就像您在三重奏中所做的那样。

我认为您的转换是正确的,除非您不应该将 h、s、v 值转换为整数;在上面显示的范围内将它们保持为双打。

public static HSVData RGBtoHSV(Color RGB)
{
    double r = (double)RGB.R / 255;
    double g = (double)RGB.G / 255;
    double b = (double)RGB.B / 255;

    double h;
    double s;
    double v;

    double min = Math.Min(Math.Min(r, g), b);
    double max = Math.Max(Math.Max(r, g), b);
    v = max;
    double delta = max - min;
    if (max == 0 || delta == 0)
    {
        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;
        }

    }

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

    return new HSVData()
    {
        h = h,
        s = s,
        v = v
    };
}
Run Code Online (Sandbox Code Playgroud)

现在您可以将这些 h,s,v valuew 直接传递到 ConvertHsvToRgb 方法中。我已将参数更改为 double,验证饱和度和值输入,并标准化色调。

public static Color ConvertHsvToRgb(double h, double s, double v)
{
    Debug.Assert(0.0 <= s && s <= 1.0);
    Debug.Assert(0.0 <= v && v <= 1.0);

    // normalize the hue:
    while (h < 0)
        h += 360;
    while (h > 360)
        h -= 360;

    h = h / 360;

    byte MAX = 255;

    if (s > 0)
    {
        if (h >= 1)
            h = 0;
        h = 6 * h;
        int hueFloor = (int)Math.Floor(h);
        byte a = (byte)Math.Round(MAX * v * (1.0 - s));
        byte b = (byte)Math.Round(MAX * v * (1.0 - (s * (h - hueFloor))));
        byte c = (byte)Math.Round(MAX * v * (1.0 - (s * (1.0 - (h - hueFloor)))));
        byte d = (byte)Math.Round(MAX * v);

        switch (hueFloor)
        {
            case 0: return Color.FromArgb(MAX, d, c, a);
            case 1: return Color.FromArgb(MAX, b, d, a);
            case 2: return Color.FromArgb(MAX, a, d, c);
            case 3: return Color.FromArgb(MAX, a, b, d);
            case 4: return Color.FromArgb(MAX, c, a, d);
            case 5: return Color.FromArgb(MAX, d, a, b);
            default: return Color.FromArgb(0, 0, 0, 0);
        }
    }
    else
    {
        byte d = (byte)(v * MAX);
        return Color.FromArgb(255, d, d, d);
    }
}
Run Code Online (Sandbox Code Playgroud)

根据我的测试,这两种方法现在可以为从 RGB 到 HSV 和返回的任何颜色提供“往返”转换。

对于“三合会”,您要从原始颜色调整 +/- 120 度。例如,如果您以红色作为基色,则 +/- 120 度的颜色是绿色和蓝色。这些转换似乎工作正常:

HSVData hsv = HSVData.RGBtoHSV(Color.FromArgb(255, 0, 0));
HSVData hsv2 = new HSVData() { h = hsv.h + 120, s = hsv.s, v = hsv.v };
HSVData hsv3 = new HSVData() { h = hsv.h - 120 , s = hsv.s, v = hsv.v };

Color red = HSVData.ConvertHsvToRgb(hsv.h, hsv.s, hsv.v);
Color green = HSVData.ConvertHsvToRgb(hsv2.h, hsv2.s, hsv2.v);
Color blue = HSVData.ConvertHsvToRgb(hsv3.h, hsv3.s, hsv3.v);

HSVData hsv4 = HSVData.RGBtoHSV(Color.YellowGreen);
Color yellowGreen = HSVData.ConvertHsvToRgb(hsv4.h, hsv4.s, hsv4.v);
Run Code Online (Sandbox Code Playgroud)