如何获得任何背景图像的相反颜色
Posted
技术标签:
【中文标题】如何获得任何背景图像的相反颜色【英文标题】:how to get the opposite color of any background images 【发布时间】:2011-05-24 18:07:38 【问题描述】:如何根据背景自动获得正确的颜色?如果其背景图像较暗,则会自动将字体颜色更改为较亮的颜色。 有可能吗?有什么想法吗?
【问题讨论】:
与#808080(灰色)背景相反的是什么? +1 这是此类函数的经典陷阱 实际上,它非常依赖于所选择的感知模型,以及使用哪个线性指标作为“对立性” @user205376 你愿意详细说明吗? @David Heffernan:其实挺大的,你会无聊的,保证! :) 我的意思是:RGB 颜色表示笛卡尔坐标 (0,0,0)->(R,G,B) 中的向量。将 RGB 颜色空间视为立方体很方便,但是当涉及到感知模型(如感知相反颜色)时,值得回忆一下 人眼 的通道权重大约为 [0.299, 0.587,0.114](分别为 R、G、B 通道) 【参考方案1】:大卫的回答通常效果很好。但是有几个选项,我会提到其中的一些。首先,最幼稚的做法是做
function InvertColor(const Color: TColor): TColor;
begin
result := TColor(Windows.RGB(255 - GetRValue(Color),
255 - GetGValue(Color),
255 - GetBValue(Color)));
end;
但这会遇到 #808080 问题(为什么?)。一个非常好的解决方案是大卫的,但对于一些不幸的背景颜色来说它看起来很糟糕。虽然文字肯定是可见的,但它看起来很可怕。一种这样的“不幸”背景颜色是#008080。
通常,如果背景为“浅色”,我更喜欢文本为黑色,如果背景为“深色”,则我更喜欢白色。我是这样做的
function InvertColor(const Color: TColor): TColor;
begin
if (GetRValue(Color) + GetGValue(Color) + GetBValue(Color)) > 384 then
result := clBlack
else
result := clWhite;
end;
另外,如果您使用的是 Delphi 2009+ 并针对 Windows Vista+,您可能对 TLabel
的 GlowSize
参数感兴趣。
【讨论】:
@Andreas 关于我的 xorColor 函数的一点是,我将它与背景颜色进行异或,因此它的意图与您的例程略有不同。 嗯,测试实际上只是[Red(C) + Green(C) + Blue(C)]/3 > 128
,其中 128 介于 0(绝对黑暗)和 255(全强度)之间。
代码运行良好。但是如果背景是图像呢?由于像素不均匀,我们如何才能得到背景的反面?
基本上迭代 exery 像素。您希望每个字符具有相同的颜色,还是每个字符的颜色应该反映当地的平均背景颜色?无论如何,您只需要在相关字符下找到“平均”颜色即可。我认为最简单的方法是将每个像素的 R、G 和 B 分量相加(即计算 R_tot = R_pixel1 + R_pixel2 + ...),对于 G_tot 和 B_tot 也是如此。然后找到 R_average = R_tot / num_pixels 和 G_average 和 B_average 类似。
@Andreas 您还需要在这里的某个地方调用 ColorToRGB,然后再四处寻找 RGB 值。【参考方案2】:
我使用以下内容给我一个与指定颜色形成对比的颜色:
function xorColor(BackgroundColor: TColor): TColor;
begin
BackgroundColor := ColorToRGB(BackgroundColor);
Result := RGB(
IfThen(GetRValue(BackgroundColor)>$40, $00, $FF),
IfThen(GetGValue(BackgroundColor)>$40, $00, $FF),
IfThen(GetBValue(BackgroundColor)>$40, $00, $FF)
);
end;
【讨论】:
@user205376 您通常会使用 Pen.Mode := pmXor 将 Pen 设置为 xor 模式,使用 Pen.Color := xorColor(backgroundColor) 设置颜色,然后绘制 啊,后续xor的颜色为F(background-color),明白了,谢谢【参考方案3】:我尝试根据“线性”配色方案计算对比度,但它在粉红色和青色输入值上确实不好。 更好的是它是基于 RGB 公式计算的:
brightness = sqrt( .241 * R^2 + .691 * G^2 + .068 * B^2 )
在 Delphi 中,我创建了这个子例程:
function GetContrastingColor(Color: TColor): TColor;
var r,g,b:double;i:integer;
begin
Color := ColorToRGB(Color);
r:=GetRValue(Color) ;
g:=GetGValue(Color) ;
b:=GetBValue(Color) ;
i:=round( Sqrt(
r * r * 0.241 +
g * g * 0.691 +
b * b * 0.068));
if (i > 128) then // treshold seems good in wide range
Result := clBlack
else
Result := clWhite;
end;
【讨论】:
FWIW 十年后:这优于 Andreas 的上述例程。我已经对两者进行了广泛的测试。两者都不错,但总体而言,这提供了明显更好的结果。【参考方案4】:当TColor
是clWindow
时,我遇到了D6 的问题。我发现如果我没有先运行ColorToRGB(Color)
,GetXValue(Color)
会分别将clWindow
的 R、G、B 值报告为 5,0,0。这几乎是黑色的,而 clWindow
在我的测试环境中被定义为 255,255,255。这似乎只是使用常量发送的值的问题,如果我发送 hex 或 int 等效项,它可以正常工作。
function InvertColor(const Color: TColor): TColor;
begin
if (GetRValue(ColorToRGB(Color)) +
GetGValue(ColorToRGB(Color)) +
GetBValue(ColorToRGB(Color)))/3 > 128 then
result := clBlack //color is light
else
result := clWhite; //color is dark
end;
【讨论】:
以上是关于如何获得任何背景图像的相反颜色的主要内容,如果未能解决你的问题,请参考以下文章
使用 MS Office 图片管理器从 JPEG 图像中裁剪颜色