使用具有抗锯齿功能的C#更改抗锯齿图像的背景颜色

时间:2013-04-12 09:13:33

标签: c# graphics antialiasing

我有一张图片,我需要更改背景颜色(例如,将下面的示例图像的背景更改为蓝色)。

但是,图像是消除锯齿的,所以我不能简单地用不同的颜色替换背景颜色。

我尝试过的一种方法是创建第二个图像,它只是背景并改变它的颜色并将两个图像合并为一个,但是这不起作用,因为两个图像之间的边界是模糊的。

有没有办法做到这一点,或者其他一些方法来实现这一点,我没有考虑过?

Example image

4 个答案:

答案 0 :(得分:8)

只需使用GDI +

Image image = Image.FromFile("cloud.png");

Bitmap bmp = new Bitmap(image.Width, image.Height);
using (Graphics g = Graphics.FromImage(bmp)) {
  g.Clear(Color.SkyBlue);
  g.InterpolationMode = InterpolationMode.NearestNeighbor;
  g.PixelOffsetMode = PixelOffsetMode.None;
  g.DrawImage(image, Point.Empty);
}

导致:

enter image description here

答案 1 :(得分:4)

抽象地

图像中的每个像素都是(R,G,B)向量,其中每个分量都在[0,1]范围内。您需要一个变换T,它会在以下约束条件下将图像中的所有像素转换为新的(R',G',B'):

  • 黑色应该保持黑色
    • T(0,0,0)=(0,0,0)
  • 白色应成为您选择的颜色C *
    • T(1,1,1)= C *

一种直接的方法是选择以下转换T:

T(c) = C* .* c  (where .* denotes element-wise multiplication)

这只是标准的图像乘法。

具体

如果您不担心性能,可以使用GetPixel上的(非常慢)方法SetPixelBitmap对其中的每个像素应用此变换。如果不清楚如何做到这一点,请在评论中这样说,我将为该部分添加详细说明。

比较

将此与LarsTech提供的方法进行比较。这里介绍的方法是最重要的; LarsTech提出的方法是最底层的。注意底部图标上的不良边缘效应(边缘上的白色雾度)。

Comparison

以下是两者的图像差异:

Difference

有感

如果你的源图像有透明(即透明 - 白色)背景和黑色前景(如你的例子),那么你可以简单地使你的变换T(a,r,g,b)=(a,0, 0,0)然后将你的图像绘制在你想要的任何背景颜色之上,正如LarsTech建议的那样。

答案 2 :(得分:1)

如果您想要替换它是一种统一的颜色,您可以将其转换为alpha。我不想自己编码!

您可以使用GIMP的Color To Alpha源代码(它是GPL),这里是version of it

P.S。不知道如何获得最新信息。

答案 3 :(得分:1)

背景去除/替换,IMO更艺术而不是科学,你找不到适合所有解决方案的算法,这取决于你对解决这个问题的绝望程度或兴趣,你可能想要考虑以下解释:

我们假设你有一个彩色图像。

使用您选择的解码机制并生成彩色图像的灰度/亮度图像。

绘制(隐喻地说)像素(x)的数值与图像中该值(y)的像素数的图形(隐喻地说)。阿卡。光度直方图。

现在,如果你的背景足够大(或很小),你会看到图形的一部分代表构成你背景的一系列像素的分布。您可能希望选择稍宽的范围来处理抗锯齿(基于您在处理类似图像时定义的固定偏移),并将其称为背景的亮度范围。

如果您知道定义背景的像素范围内至少有一个像素(样本/中值像素值),这将使您的生活更轻松,这样您就可以“查找”定义您的背景的图形部分背景。

一旦获得背景的亮度像素范围,您可以浏览原始图像像素,将它们的亮度值与您所拥有的范围进行比较,如果它在其中,则用原始图像中的像素替换为所需的颜色优选地,基于原始像素和样本像素移动亮度,使得替换的背景看起来也是抗锯齿的。

这不是一个完美的解决方案,并且有很多场景可能会失败/部分失败,但同样适用于您附加问题的示例图像。

此外,还有许多性能改进机会,包括GPGPU等。

另一个可能的解决方案是使用一些预先建立的第三方图像处理库,有一些开源,如Camellia,但我不确定提供了哪些功能以及它们有多复杂。