gpt4 book ai didi

c# - 我如何实现这个 "color difference"算法?

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:10:06 24 4
gpt4 key购买 nike

作为这个问题的后续:( How can I draw legible text on a bitmap (Winforms)? ),我通过计算文本下方的“平均”颜色并为文本选择适当的对比颜色,在位图上绘制清晰但较小的文本.

我从 https://stackoverflow.com/a/6185448/3784949 窃取了 Till 的代码用于计算“平均”bmp 颜色。现在我正在查看 http://www.w3.org/TR/AERT#color-contrast 建议的“色差”算法.

这表明我需要使我的颜色亮度至少大 125 个“单位”,并且我的色差至少大 500 个单位,其中亮度和差异是这样计算的:

颜色亮度由以下公式确定:

((红色值 X 299) + (绿色值 X 587) + (蓝色值 X 114))/1000

色差由以下公式确定:

(最大值(红色值1,红色值2) - 最小值(红色值1,红色值2)) + (最大值(绿色值1,绿色值2) - 最小值(绿色值1,绿色值2)) +(最大值(蓝色值1,蓝色值2)-最小值(蓝色值1,蓝色值2))

我该如何实现?我可以通过 ARGB 设置我的颜色(我相信,它是标签前景色);但是我如何计算要改变每个单独的值以实现此处所需的差异?我不熟悉将“差异”单位分解成它们的组成部分所需的数学。

例如,我对一张位图的“平均”是:颜色 [A=255,R=152,G=138,B=129]。如何向每个部分“添加”足够的内容以实现这两个差异?

编辑:具体来说,我的困惑在于:

  1. 看起来我需要添加三个单独的值(R、G、B)以实现两个不同的目标(新 RGB 加起来为原始加 125,新 RGB 加起来为原始加 500

  2. 看起来我可能需要“加权”我添加的亮度值,以便为 G 添加比 R 多于 B 的亮度值。

我不知道如何解决#1。我不确定我对 #2 的看法是否正确。

编辑:建议的解决方案

我目前正在试验这个:

private Color GetContrastingFontColor(Color AverageColorOfBitmap,
List<Color> FavoriteColors)
{
IEnumerable<Color> AcceptableColors =
(IEnumerable<Color>)FavoriteColors.Where(clr =>
(GetColorDifferenceAboveTarget(AverageColorOfBitmap, clr, (float)200) > 0)
&& (GetBrightnessAboveTarget(AverageColorOfBitmap, clr, (float).125) > 0))
.OrderBy(clr => GetColorDifferenceAboveTarget(
AverageColorOfBitmap, clr, (float)200));
return AcceptableColors.DefaultIfEmpty(Color.Aqua).First();
}

这是一个很好的框架,但我需要努力从列表中选择“最佳”候选人。现在它只是返回“符合亮度标准的具有最大色差的合格颜色”。但是,这允许我修改浮点值(W3 的“需要 500 色差”完全是废话,零个已知颜色符合条件)并进行实验。

支持代码:

private float GetBrightnessAboveTarget(Color AverageColorOfBitmap, 
Color proposed, float desiredDifference)
{
float result = proposed.GetBrightness() - AverageColorOfBitmap.GetBrightness();
return result - desiredDifference;
}

private float GetColorDifferenceAboveTarget(Color avg, Color proposed,
float desiredDifference)
{
float r1 = Convert.ToSingle(MaxByte(Color.Red, avg, proposed));
float r2 = Convert.ToSingle(MinByte(Color.Red, avg, proposed));
float r3 = Convert.ToSingle(MaxByte(Color.Green, avg, proposed));
float r4 = Convert.ToSingle(MinByte(Color.Green, avg, proposed));
float r5 = Convert.ToSingle(MaxByte(Color.Blue, avg, proposed));
float r6 = Convert.ToSingle(MinByte(Color.Blue, avg, proposed));

float result = (r1 - r2) + (r3 - r4) + (r5 - r6);
return result - desiredDifference;
}

private byte MaxByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R >= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G >= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B >= y.B) ? x.B : y.B;
return byte.MinValue;
}

private byte MinByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R <= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G <= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B <= y.B) ? x.B : y.B;
return byte.MinValue;
}

最佳答案

这更像是对原始问题的回答。我称之为自制大纲

使用透明度加上你可以获得的最大和最小亮度(白色和黑色)它创造了良好的对比度,至少它在我的屏幕上看起来相当不错。

它是阴影和透明度的混合体。我从红色成分中减去一点以获得您想要的浅绿色..

它首先通过向左上方 1 个像素和向右下方 1 个像素打印文本来创建背景的较暗版本。最后它在上面打印一个明亮的版本。请注意,它并没有真正使用黑色和白色,因为它的半透明像素的色调实际上是每个背景像素的色调。

对于实际的打印输出,您必须进行试验,尤其是字体以及两个透明胶片!

此外,您还应该根据打印点的亮度在黑色阴影上的白色和白色高光上的黑色之间切换。但是有了这个 homemeade 轮廓,它确实可以在黑暗和明亮的背景上工作,只是在明亮的背景上看起来会少一些优雅。

using (Graphics G = Graphics.FromImage(pictureBox1.Image) )
{
Font F = new Font("Arial", 8);
SolidBrush brush0 = new SolidBrush(Color.FromArgb(150, 0, 0, 0))
SolidBrush brush1 = new SolidBrush(Color.FromArgb(200, 255, 255, 222))

G.DrawString(textBox1.Text, F, brush0 , new Point(x-1, y-1));
G.DrawString(textBox1.Text, F, brush0 , new Point(x+1, y+1));
G.DrawString(textBox1.Text, F, brush1, new Point(x, y));
}

编辑:这是通过单击按钮调用的,但实际上应该在绘制事件中调用。那里的 Graphics 对象及其使用 block G 将被简单地替换为 e.Graphics 事件参数..

我注意到您使用“透明”标签来显示数据以避免 Graphics.DrawString 和 Paint 事件的细节。

好吧,这是可以做到的,结果看起来很相似:

string theText ="123 - The quick brown fox..";
Label L1, L2, L3;

pictureBox1.Controls.Add(new trLabel());
L1 = (trLabel)pictureBox1.Controls[pictureBox1.Controls.Count - 1];
L1.Text = theText;
L1.ForeColor = Color.FromArgb(150, 0, 0, 0);
L1.Location = new Point(231, 31); // <- position in the image, change!

L1.Controls.Add(new trLabel());
L2 = (trLabel)L1.Controls[pictureBox1.Controls.Count - 1];
L2.Text = theText;
L2.ForeColor = Color.FromArgb(150, 0, 0, 0);
L2.Location = new Point(2, 2); // do not change relative postion in the 1st label!

L2.Controls.Add(new trLabel());
L3 = (trLabel)L2.Controls[pictureBox1.Controls.Count - 1];
L3.Text = theText;
L3.ForeColor = Color.FromArgb(200, 255, 255, 234);
L3.Location = new Point(-1,-1); // do not change relative postion in the 2nd label!

但是您会注意到,由于不可能在 Winforms 中拥有真正透明的控件,我们需要一些额外的努力。您可能使用这样的标签子类:

public partial class trLabel : Label
{
public trLabel()
{
SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
BackColor = Color.Transparent;
Visible = true;
AutoSize = true;
}
}

这似乎可行。但实际上它只是看起来那样,因为在创建时每个标签都会从其父标签获取其当前背景的副本。永远不会更新。这就是为什么我必须将第二个和第三个标签添加到我显示图像的图片框中,而不是添加到第一个和第二个分别为“透明”标签。

除非您自己绘制,否则 Winforms 控件之间根本就没有真正的透明度。

所以 DrawString 解决方案并不复杂。它给你带来的好处是允许你扭曲 Graphics 对象的几个属性,比如 Smoothingmode。 , TextContrastInterpolationMode

关于c# - 我如何实现这个 "color difference"算法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25068189/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com