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

问题描述 投票:0回答:4

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

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

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

有什么方法可以做到这一点,或者有其他我没有考虑过的方法来实现这一点吗?

c# graphics antialiasing
4个回答
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


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
上使用(非常慢的)方法
SetPixel
Bitmap
对其中的每个像素应用此变换。如果不清楚如何执行此操作,请在评论中说明,我将为该部分添加详细说明。

比较

将此与 LarsTech 提出的方法进行比较。这里介绍的方法在顶部; LarsTech 提出的方法在底部。请注意底部图标上的不良边缘效果(边缘上有白色薄雾)。

Comparison

这是两者的图像差异:

Difference

事后思考

如果您的源图像具有透明(即透明白色)背景和黑色前景(如您的示例中所示),那么您可以简单地进行变换 T(a, r, g, b) = (a, 0, 0, 0)然后按照 LarsTech 的建议,在您想要的任何背景颜色上绘制图像。


1
投票

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

您可以使用 GIMP 的 Color To Alpha 源代码(它是 GPL),这是它的 版本

附注不知道如何获取最新的。


1
投票

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

假设您有一张彩色图像。

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

绘制像素 (x) 数值与图像中该值 (y) 的像素数量的关系图(比喻而言)。又名。亮度直方图。

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

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

一旦获得背景的亮度像素范围,您可以遍历原始图像像素,将它们的亮度值与您拥有的范围进行比较,如果在范围内,则将原始图像中的像素替换为所需的颜色,最好亮度根据原始像素和样本像素发生变化,因此替换的背景看起来也抗锯齿。

这不是一个完美的解决方案,在很多情况下它可能会失败/部分失败,但它同样适用于您随问题附上的示例图像。

还有很多性能提升机会,包括GPGPU等。

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

© www.soinside.com 2019 - 2024. All rights reserved.