【问题标题】:How do I determine darker or lighter color variant of a given color?如何确定给定颜色的较深或较浅颜色变体?
【发布时间】:2010-09-10 23:46:42
【问题描述】:

给定系统或用户的任何色调的源颜色,我想要一个简单的算法,我可以使用它来计算所选颜色的更亮或更暗的变体。类似于在 Windows Live Messenger 上用于设置用户界面样式的效果。

语言是带有 .net 3.5 的 C#。

回复评论:颜色格式为 (Alpha)RGB。将值作为字节或浮点数。

标记答案:对于我使用的上下文(一些简单的 UI 效果),我标记为接受的答案实际上是这个上下文中最简单的。但是,我也放弃了对更复杂和准确的答案的投票。任何进行更高级颜色操作并在将来找到此线程的人都应该检查一下。谢谢。 :)

【问题讨论】:

  • 仅作为补充,目前用于颜色转换和插值(例如,创建感知一致的颜色图等)的最先进颜色空间是 CIELab。

标签: c# colors


【解决方案1】:

XNA there is the Color.Lerp static method 中,这是两种颜色之间的区别。

Lerp 是两个浮点数之间的数学运算,它通过它们之间的差值的比率来改变第一个浮点数的值。

这是对float 的扩展方法:

public static float Lerp( this float start, float end, float amount)
{
    float difference = end - start;
    float adjusted = difference * amount;
    return start + adjusted;
}

那么使用 RGB 在两种颜色之间进行简单的 lerp 操作将是:

public static Color Lerp(this Color colour, Color to, float amount)
{
    // start colours as lerp-able floats
    float sr = colour.R, sg = colour.G, sb = colour.B;

    // end colours as lerp-able floats
    float er = to.R, eg = to.G, eb = to.B;

    // lerp the colours to get the difference
    byte r = (byte) sr.Lerp(er, amount),
         g = (byte) sg.Lerp(eg, amount),
         b = (byte) sb.Lerp(eb, amount);

    // return the new colour
    return Color.FromArgb(r, g, b);
}

应用它的一个例子是这样的:

// make red 50% lighter:
Color.Red.Lerp( Color.White, 0.5f );

// make red 75% darker:
Color.Red.Lerp( Color.Black, 0.75f );

// make white 10% bluer:
Color.White.Lerp( Color.Blue, 0.1f );

【讨论】:

  • @ScottSilvi 我现在已经习惯了 - 在编译的 C# 中并没有那么糟糕,但是我花了很长时间试图找出一些 HTML/CSS/JS 代码有什么问题,因为我已经正确拼写中心或颜色:S
  • 这个例子的语法让我很困惑,但我现在明白了......我猜只需要重新排列它
  • return 语句也需要我的 alpha 值:return Color.FromArgb(colour.A, r, g, b);,或 RGB 版本:return Color.FromRgb(r, g, b);
【解决方案2】:

只需将 RGB 值乘以要修改级别的量即可。如果其中一种颜色已经处于最大值,那么你不能让它更亮(无论如何使用 HSV 数学。)

这与切换到 HSV 然后修改 V 给出完全相同的结果,但数学上要少得多。这与切换到 HSL 然后修改 L 给出的结果相同,只要您不想开始失去饱和度。

【讨论】:

  • 是的,即使您不能使单个颜色通道更亮,也可以使颜色更亮。失去饱和度是不可避免的副作用。见stackoverflow.com/a/141943/5987
  • 如果颜色为黑色,则乘以 rgb 值不会做任何事情
【解决方案3】:

HSV(色相/饱和度/值)也称为 HSL(色相/饱和度/亮度)只是一种不同的颜色表示。

使用这种表示方式更容易调整亮度。所以从 RGB 转换为 HSV,使“V”变亮,然后再转换回 RGB。

下面是一些要转换的C代码

void RGBToHSV(unsigned char cr, unsigned char cg, unsigned char cb,double *ph,double *ps,double *pv)
{
double r,g,b;
double max, min, delta;

/* convert RGB to [0,1] */

r = (double)cr/255.0f;
g = (double)cg/255.0f;
b = (double)cb/255.0f;

max = MAXx(r,(MAXx(g,b)));
min = MINx(r,(MINx(g,b)));

pv[0] = max;

/* Calculate saturation */

if (max != 0.0)
    ps[0] = (max-min)/max;
else
    ps[0] = 0.0; 

if (ps[0] == 0.0)
{
    ph[0] = 0.0f;   //UNDEFINED;
    return;
}
/* chromatic case: Saturation is not 0, so determine hue */
delta = max-min;

if (r==max)
{
    ph[0] = (g-b)/delta;
}
else if (g==max)
{
    ph[0] = 2.0 + (b-r)/delta;
}
else if (b==max)
{
    ph[0] = 4.0 + (r-g)/delta;
}
ph[0] = ph[0] * 60.0;
if (ph[0] < 0.0)
    ph[0] += 360.0;
}

void HSVToRGB(double h,double s,double v,unsigned char *pr,unsigned char *pg,unsigned char *pb)
{
int i;
double f, p, q, t;
double r,g,b;

if( s == 0 )
{
    // achromatic (grey)
    r = g = b = v;
}
else
{
    h /= 60;            // sector 0 to 5
    i = (int)floor( h );
    f = h - i;          // factorial part of h
    p = v * ( 1 - s );
    q = v * ( 1 - s * f );
    t = v * ( 1 - s * ( 1 - f ) );
    switch( i )
    {
    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;
    default:        // case 5:
        r = v;
        g = p;
        b = q;
    break;
    }
}
r*=255;
g*=255;
b*=255;

pr[0]=(unsigned char)r;
pg[0]=(unsigned char)g;
pb[0]=(unsigned char)b;
}

【讨论】:

  • HSV and HSL are different things。 HSV 也称为 HSL。
  • 但 HSV 有时也称为 HSB(亮度)。正如@romkyns 所说,这与 HSL 仍然不同。
  • @KPexEA 你写了“所以从 RGB 转换为 HSV,使 'V' 变亮,然后再转换回 RGB。” .如何*使V 部分?I need to generate n 相同颜色的阴影变亮。阴影应该越来越亮。
  • @Geek 将颜色从 RGB 转换为 HSV,然后丢弃 V。然后使用 HS 值调用 HSVtoRGB,并随着 V 值的增加进行迭代以生成不同的 RGB 阴影。或者,如果您想从初始值开始,只是让它们更亮一点,只需在每次迭代的每个 V 中添加少量而不是从 0 开始。
  • @KPexEA 所以如果最初的V=0.25 和我需要4 从给定颜色开始的较浅色调,那么V 的值将是0.25,0.5,0.75 and 1?这些数字是否总是必须在算术级数(AP)中?
【解决方案4】:

Rich Newman discusses HSL color 在他的博客上提到了 .NET System.Drawing.Color,甚至 provides an HSLColor class 为您完成了所有工作。将您的 System.Drawing.Color 转换为 HSLColor,根据 Luminosity 添加/减去值,然后转换回 System.Drawing.Color 以在您的应用中使用。

【讨论】:

    【解决方案5】:

    您可以将颜色转换为 HSL 颜色空间,在那里对其进行操作并转换回您选择的颜色空间(很可能是 RGB)

    颜色越浅,L 值越高,颜色越深,L 值越低。

    以下是相关内容和所有方程式:

    http://en.wikipedia.org/wiki/HSL_color_space

    另一种方法是简单地将颜色插入白色或黑色。这也会稍微降低颜色的饱和度,但计算起来更便宜。

    【讨论】:

    • 这些计算往往很便宜,但一个很大的区别是所需的编码对程序员来说是一种负担。
    【解决方案6】:

    我在System.Windows.Forms 中使用了ControlPaint.Dark().Light()

    【讨论】:

    • 太棒了。为什么它不是“颜色”命名空间的一部分?
    • 不错。请注意,“percOfLightLight”值(该方法的第二个参数,这实际上是它的名称)应该是 0 到 1 范围内的浮点数。接受其他值,但行为不会是您想要的。获得较浅颜色的示例代码:Color lighterColor = ControlPaint.Light(originalColor, 1.0f);
    【解决方案7】:

    我猜您正在使用带有字节值(0 到 255)的 RGB,因为这在任何地方都很常见。

    为了更亮,将 RGB 值与白色的 RGB 取平均值。或者,为了控制增亮程度,按一定比例混合它们。让f 在 0.0 到 1.0 之间变化,那么:

    Rnew = (1-f)*R + f*255
    Gnew = (1-f)*G + f*255
    Bnew = (1-f)*B + f*255
    

    对于较暗,使用黑色的 RGB - 全为零,使数学更容易。

    我省略了诸如将结果转换回字节之类的细节,这可能是您想要做的。

    【讨论】:

      【解决方案8】:

      如果您使用 RGB 颜色,我会将此颜色参数转换为 HSL(色调、饱和度、亮度),修改亮度参数,然后再转换回 RGB。谷歌一下,你会发现很多关于如何进行这些颜色表示转换(RGB 到 HSL,反之亦然)的代码示例。

      这是我很快发现的: http://bytes.com/forum/thread250450.html

      【讨论】:

        【解决方案9】:

        假设您获得的颜色为 RGB,首先将其转换为 HSV(色调、饱和度、值)颜色空间。然后增加/减少该值以产生更亮/更暗的颜色阴影。然后转换回 RGB。

        【讨论】:

          【解决方案10】:

          如果您的颜色是 RGB 格式(或者可能是 CMYK),您可以使用相当粗略的方法来增加颜色的每个组件的值。例如,在 HTML 中,颜色表示为三个两位数的十六进制数字。 #ff0000 会给你一个明亮的红色,然后可以通过将 G 和 B 组件的值增加相同的量来淡化它,例如 #ff5555(给出更浅的红色)。大概对于色相、饱和度和亮度 (HSL) 颜色,您可以只提高 L 分量,但我不能肯定地说;我对这个色彩空间不太熟悉。

          不过,正如我所说,这种方法相当粗糙。根据我对 Live Messenger 的记忆,听起来您正在尝试制作渐变,这可以非常容易地应用于 Windows Presentation Foundation(WPF,.NET 3.0 的一部分)。 WPF 支持许多不同类型的渐变画笔,包括线性渐变和径向渐变。

          我强烈推荐 Adam Nathan 的书 Windows Presentation Foundation Unleashed 作为对 WPF 的全面介绍。

          HTH

          【讨论】:

          • #ff5555 不会产生较浅的红色,而是会产生褪色的红色。饱和度较低。这确实会发出更多的光,但它更像是粉红色而不是更亮的红色。
          • 确实可以使用渐变,但您必须为每个渐变色标提供颜色。
          【解决方案11】:

          颜色的任何变化都最好在 HSL/HSV 中完成。

          一个很好的测试是在 RGB 空间和 HSL 空间中的两个等效值之间进行插值。 HSL 空间中的坡道看起来像是一个自然的进程。在 RGB 空间中,它通常看起来很不自然。 HSL 比 RGB 更好地映射到我们的视觉色彩空间感知。

          【讨论】:

            【解决方案12】:

            转换为 HSV 或其他颜色空间的想法似乎不错,并且对于精确的颜色工作来说可能是必要的,但对于一般目的来说,在 RGB 中工作的错误可能并不重要。此外,处理边界情况可能会很痛苦:RGB 是一个立方体形状的空间,而 HSV 不是。如果使用字节值,您可以在空间之间进行多对一和一对多映射。这可能是也可能不是问题,具体取决于应用程序。 YMMV

            【讨论】:

              【解决方案13】:

              website 指出,您可以在 BCL C# System.Windows.Forms 命名空间中使用 ControlPaint 类。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-03-31
                • 1970-01-01
                • 2013-07-21
                • 1970-01-01
                • 1970-01-01
                • 2012-07-11
                • 2018-02-17
                • 1970-01-01
                相关资源
                最近更新 更多