3

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

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

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

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

示例图片

4

4 回答 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);
}

导致:

在此处输入图像描述

于 2013-04-16T19:48:17.080 回答
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)

这只是标准的图像乘法。

具体来说

如果您不担心性能,您可以使用(非常慢的)方法GetPixelSetPixel在您的身上Bitmap为其中的每个像素应用此变换。如果不清楚如何执行此操作,请在评论中说明,我会为该部分添加详细说明。

比较

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

比较

这是两者的图像差异:

不同之处

事后诸葛亮

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

于 2013-04-18T22:54:06.957 回答
1

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

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

PS不知道如何获得最新的。

于 2013-04-15T13:56:55.840 回答
1

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

假设您有一张彩色图像。

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

绘制像素 (x) 的数值与该值 (y) 的图像中像素数的关系图(比喻地说)。阿卡。亮度直方图。

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

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

一旦你有了背景的亮度像素范围,你可以遍历原始图像像素,将它们的亮度值与你拥有的范围进行比较,如果它在范围内,将原始图像中的像素替换为所需的颜色,最好是亮度基于原始像素和样本像素移动,因此被替换的背景也看起来是抗锯齿的。

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

还有很多性能改进机会,包括 GPGPU 等。

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

于 2013-04-16T19:06:33.950 回答