根据背景色,将前景色设置为黑色或白色

41

类似于计算rgb分量的平均值,然后决定使用黑色还是白色?

我是否必须先将RGB转换为HSV,因为RGB并不总是人眼看到的颜色?

我正在使用C#。


2
这个问题包含了一些答案,可以帮助你:https://dev59.com/dXNA5IYBdhLWcg3wdtz5#946570 - Michael Greene
相关(但本身是重复的):https://dev59.com/DXA75IYBdhLWcg3wxcHV https://dev59.com/sW865IYBdhLWcg3wLrhE - JYelton
6个回答

81

恰好我不久前在一个项目中需要这个函数。

private int PerceivedBrightness(Color c)
{
    return (int)Math.Sqrt(
    c.R * c.R * .241 +
    c.G * c.G * .691 +
    c.B * c.B * .068);
}
我在网上找到了这个公式,它来自于 Nbd Tech ,用于处理感知颜色和颜色转换公式。该网站提供了很多有用的信息。

使用此公式来选择黑色或白色的方法如下:

var foreColor = (PerceivedBrightness(backColor) > 130 ? Color.Black : Color.White);
您可以使用除130以外的值作为截止值,这是个人偏好。
更新:根据Darel Rex Finley在他的网站上的说法:
  

我通过使用Photoshop玩耍得出的值实际上是0.241、0.691和0.068,但我后来得知值0.299、0.587和0.114更为准确。

此规范遵循ITU-R Recommendation BT.601(简称Rec. 601)。我上面提到的Nbd Tech网站尚未更新反映这一点。

基于此,以下是更新的方法 (感谢DTI-Matt的评论)

private int PerceivedBrightness(Color c)
{
    return (int)Math.Sqrt(
    c.R * c.R * .299 +
    c.G * c.G * .587 +
    c.B * c.B * .114);
}

关于阈值偏好的说明:

亮度在中间范围(例如120-140)的颜色会更加主观。例如,关于红色(FF0000),它的亮度为139,黑色或白色叠加效果更清晰存在争议。

白色和黑色叠加在红色上


这基本上是亮度的公式,将值平方以使离群值更具权重。结果是0-255刻度。http://en.wikipedia.org/wiki/Luma_%28video%29 - Rob Elliott
3
这些数值的来源已经更新:http://alienryderflex.com/hsp.html它们现在显示为:R: .299 G: .587 B: .114 - DTI-Matt
为什么“红色”被认为是一种“浅色”?黑色文字在红色背景下看起来不好看。 - Simon_Weaver
1
@Simon 如果您指的是Color.Red(R 255,G 0,B 0),则根据上述值,它评估为感知亮度为139。我同意白底红字更好,但黑底并非不可读。在120-140范围内的值将更加主观。尝试使用各种颜色和阈值140查看是否适合您的目的。 - JYelton

7

那方面怎么样?

private static Color GetReadableForeColor(Color c)
{
    return (((c.R + c.B + c.G) / 3) > 128) ? Color.Black : Color.White;
}

3
使用以下数值尝试此方法:128、255、0。这将得到一种浅绿色,更易于在黑色背景下阅读。但是,平均值为127,您的方法会返回白色。 - JYelton
在我尝试过的所有解决方案中,这是给我带来最佳结果的一个,无论是在视觉上还是在编程上确定两种颜色之间对比度方面。+1。 - nawfal

6

Color 结构支持本地转换为 HSB。

if (Color.GetBrightness() > 0.5f) {
  // win
}

您可能还需要添加一个饱和度组件,因为饱和度也会对视觉上的“亮度”产生影响。

0

你可以根据颜色深度进行简单的计算,例如如果你有一个 #FFFFFF 的颜色格式,你只需要将 RGB 值相加并计算它们是否低于一半。

在这种情况下,每个值的最大值为 255(F x F = 256),因此只需检查它是否低于该阈值:

var colorCode = ((R + B + G) < 255*3) ? "#FFFFFF" : "#000000";

如果颜色较暗,使用白色背景。如果颜色较亮,使用黑色背景。这并不完美,但是一个开始的想法。


我最初在我的项目中尝试了类似的方法,但有时白色/黑色标签在其背景颜色上并不那么明显。 - JYelton

0

这与问题直接无关(因为它没有提到Unity),但是对于其他使用Unity和UnityEngine.Color结构的读者来说,注意它们已经有一个属性可以利用来实现类似于这样的功能:{{link1:Color.grayscale}},它返回一个范围为0-1的浮点数,与主要答案中提到的"PerceivedBrightness"函数类似(它使用相同的r*.299、g*.587、b*.114的值)。对于黑色/暗色,它将更接近0,而对于白色/亮色,它将更接近1。

这是我正在使用的基于Color.grayscale的函数:

// get most visible color between black & white for a given color (e.g to put text on a color)
public static Color GetReadableForeColor(Color bg) => bg.grayscale > 0.509f ? Color.black : Color.white;

-1

如果我理解正确,一种方法可能是获取桌面壁纸图像,以某种方式检查其颜色,然后根据此更改应用程序颜色。

有一篇关于获取当前桌面壁纸的文章on geekpedia(在谷歌上有很多相关结果),但基本原理是获取当前壁纸的注册表值:

RegistryKey rkWallPaper = Registry.CurrentUser.OpenSubKey("Control Panel\\Desktop", false);
string WallpaperPath = rkWallPaper.GetValue("WallPaper").ToString();

你可以使用该路径打开图像。然后,您可以获取许多属性,例如 RGB 中的尺寸和单个像素颜色。

要确定它是“更白”还是“更黑”,您有很多选择。

其中一个想法是获取 RGB 中的每个像素颜色,平均值(以获取灰度值),然后平均每个像素的灰度值。如果这个值大于 128,则可以被视为“白色”。如果小于 128,则为“黑色”。基本上,您正在决定图像像素强度的平均值在中灰分界线的哪一侧。

// Psudo code - can't check the C# spec atm.
foreach(Pixel p in image)
{
    // get average of colour components.
    double greyScale = (p.Red + p.Green + p.Blue) / 3;
    totalIntensity += greyScale;
}

double averageImageIntensity = totalIntensity / image.NumPixels;

if(totalIntensity > 128) // image could be considered to be "white"
else // image could be considered "black".

问题:可能是一个缓慢的过程,您可能只想采样一些像素(比如每10个等)以节省时间。更普遍地说,这似乎是一个相当hacky的事情要做的。在运行时拉取用户文件并对其进行处理并不干净,并且会带来潜在的安全和稳定性问题。如果图像是有问题或损坏的呢。
个人建议只需让用户自己选择颜色/主题/皮肤,或者更好的是让他们自定义!

我不想改变整个应用程序的颜色。我正在使用一个列表视图,在其中项目具有背景颜色,每个项目的文本应该是可读的... - Kai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接