如何获得任何背景图像的相反颜色

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+,您可能对 TLabelGlowSize 参数感兴趣。

【讨论】:

@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】:

TColorclWindow 时,我遇到了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 图像中裁剪颜色

如何使用python对相同颜色的图像区域进行分组并获取其坐标而忽略背景颜色

如何更改 UINavigationItem 的背景颜色?

如何解决 .png 背景颜色问题?

如何设置按钮的背景颜色 - xcode

如何使用SVG滤镜创建模糊的标签背景?