Image processing 我变了。背景移除只是将alpha(不透明度)设置为颜色空间差。如果前景图像中不出现背景色,则效果良好。如果出现这种情况,要么背景无法移除,要么必须使用BFS算法仅漫游外部像素(类似于在GIMP中使用魔杖选择,然后移除选择)
如果前景图像的孔和像素的颜色与背景颜色相似,则无法删除背景。这样的图像需要一些人工处理。我尽我所能将colortoalpha方法从gimp翻译成C。问题是,RGBA值在库(如)中被视为每个通道的字节。有些转换在转换过程中丢失了数据,但我尽力保留了尽可能多的数据。这使用ImageSharp进行图像突变。ImageSharp是完全管理的,因此它可以跨平台工作。它也很快。整个方法的运行时间约为10毫秒(小于10毫秒)。Image processing 我变了。背景移除只是将alpha(不透明度)设置为颜色空间差。如果前景图像中不出现背景色,则效果良好。如果出现这种情况,要么背景无法移除,要么必须使用BFS算法仅漫游外部像素(类似于在GIMP中使用魔杖选择,然后移除选择),image-processing,graphics,raster-graphics,Image Processing,Graphics,Raster Graphics,如果前景图像的孔和像素的颜色与背景颜色相似,则无法删除背景。这样的图像需要一些人工处理。我尽我所能将colortoalpha方法从gimp翻译成C。问题是,RGBA值在库(如)中被视为每个通道的字节。有些转换在转换过程中丢失了数据,但我尽力保留了尽可能多的数据。这使用ImageSharp进行图像突变。ImageSharp是完全管理的,因此它可以跨平台工作。它也很快。整个方法的运行时间约为10毫秒(小于10毫秒)。 以下是C#实现的代码: public static unsafe void Col
以下是C#实现的代码:
public static unsafe void ColorToAlpha(this Image<Rgba32> image, Rgba32 color)
{
double alpha1, alpha2, alpha3, alpha4;
double* a1, a2, a3, a4;
a1 = &alpha1;
a2 = &alpha2;
a3 = &alpha3;
a4 = &alpha4;
for (int j = 0; j < image.Height; j++)
{
var span = image.GetPixelRowSpan(j);
for (int i = 0; i < span.Length; i++)
{
ref Rgba32 pixel = ref span[i];
// Don't know what this is for
// *a4 = pixel.A;
if (pixel.R > color.R)
*a1 = (pixel.R - color.R) / (255.0 - color.R);
else if (pixel.R < color.R)
*a1 = (color.R - pixel.R) / color.R;
else
*a1 = 0.0;
if (pixel.G > color.G)
*a2 = (pixel.G - color.G) / (255.0 - color.G);
else if (pixel.G < color.G)
*a2 = (color.G - pixel.G) / color.G;
else
*a2 = 0.0;
if (pixel.B > color.B)
*a3 = (pixel.B - color.B) / (255.0 - color.B);
else if (pixel.B < color.B)
*a3 = (color.B - pixel.B) / color.B;
else
*a3 = 0.0;
if (*a1 > *a2)
*a4 = *a1 > *a3 ? *a1 * 255.0 : *a3 * 255.0;
else
*a4 = *a2 > *a3 ? *a2 * 255.0 : *a3 * 255.0;
if (*a4 < 1.0)
return;
pixel.R = (byte)Math.Truncate((255.0 * (*a1 - color.R) / *a4 + color.R));
pixel.G = (byte)Math.Truncate((255.0 * (*a2 - color.G) / *a4 + color.G));
pixel.B = (byte)Math.Truncate((255.0 * (*a3 - color.B) / *a4 + color.B));
pixel.A = (byte)Math.Truncate(*a4);
}
}
}
公共静态不安全无效颜色到Alpha(此图像,Rgba32颜色)
{
双字母1,字母2,字母3,字母4;
双*a1、a2、a3、a4;
a1=&alpha1;
a2=&alpha2;
a3=&alpha3;
a4=&alpha4;
对于(int j=0;jcolor.R)
*a1=(pixel.R-color.R)/(255.0-color.R);
else if(像素.R颜色.G)
*a2=(pixel.G-color.G)/(255.0-color.G);
else if(像素.G颜色B)
*a3=(pixel.B-color.B)/(255.0-color.B);
else if(像素B*a2)
*a4=*a1>*a3?*a1*255.0:*a3*255.0;
其他的
*a4=*a2>*a3?*a2*255.0:*a3*255.0;
如果(*a4<1.0)
返回;
pixel.R=(字节)Math.Truncate((255.0*(*a1-color.R)/*a4+color.R));
pixel.G=(字节)Math.Truncate((255.0*(*a2-color.G)/*a4+color.G));
pixel.B=(字节)Math.Truncate((255.0*(*a3-color.B)/*a4+color.B));
pixel.A=(字节)Math.Truncate(*a4);
}
}
}
我在我的编辑器中的filter-Other-Color-to-Alpha下实现了这个过滤器。结果与GIMP完全一致。该算法非常简单
想法:使用透明度值a将背景色B与前景色F组合,以获得新的颜色N:
N = A * F + (1 - A) * B;
您知道N(图像中的实际颜色)和B(过滤器的参数),并且希望恢复前景色F及其透明度A
这样做:
A = max( abs(N.r - B.r), abs(N.g - B.g), abs(N.b - B.b) )
现在,你知道N,B,A。只需使用上面的公式计算F。相关问题:@MarkRansom我知道你发布链接的问题与提出该问题的人是我有关:)即使你的公式可以达到这个Gimp的功能的效果,但谜团仍然存在,因为我在Gimp的源代码中看到的东西的复杂性比你的公式中看到的要高。@MarkRansom继续:但是你的方法似乎比Gimp的更灵活,因为有了重写的方程组的解,你可以“剪切”从一种颜色的背景中提取图像,并将其放置在另一种颜色的背景上,图像看起来仍然相同。所以我想这个问题已经没有什么意义了,所以如果没有人介意的话,我会注册删除这个问题。我甚至没有注意到另一个问题是你的问题!这一个更难,因为你有一个额外的未知-最大阿尔法值能够保留输出颜色。这是一个有趣的问题,我只是还没有时间去解决它。我不会删除这个问题。谢谢,但我已经看到了源代码,它不够简单,而且文档也不完整。你在回答的第一部分所写的内容已经在我的问题版本中提到了,用简单的话来说,这意味着不难估计两种颜色之间的相似性,而是如何处理alpha从1.0变为其他值的像素的颜色,实际上,也不复杂:你似乎知道GIMP。你能回答我的问题吗?看来问题已经被删除了,所以我不知道实际的问题是什么。很抱歉我还没有测试它,但你的工作已经+1;)我需要算法将其应用于svg图像,但我还没有找到解决方案……我想知道为什么它与矢量图形相关。顺便说一句,现在当我看到它时,我想知道
mA
和mX
参数意味着什么。它缺少RGB到实验室颜色空间的转换。如果有人对从光栅图像中移除固体背景感兴趣,我有一些C#中的工作代码,实现了我在这里写的所有内容(LAB color space和BFS algo,在移除背景时保持对象完好无损)。再问一个问题,因为这不仅仅是“颜色到阿尔法”的效果。我称之为智能背景移除。适用于“绿色屏幕”图片。
N = A * F + (1 - A) * B;
A = max( abs(N.r - B.r), abs(N.g - B.g), abs(N.b - B.b) )