题
我建立一个网站对于一个俱乐部的一部分的母组织。我下载(榨取;))的图像,其中把个人资料页的母亲组织,以展示我自己的网页。但他们的网站具有一个漂亮的白色背景上,我的网站有一个很好的灰色渐变的背景。这并不匹配。所以我的想法是编辑的图像之前,它们保存到我的服务器。
我使用GDI+增强我的图片,当我使用的方法MakeTransparent的位,它的工作,它不会做什么,它应该做,但我仍然有这些白jpeg的文物,所有的地方。项目使图像的那么糟糕,我最好不制作的图像透明的和刚刚离开这白,但那是真的丑陋在我自己的网站。我总是可以在一个漂亮的边界一带白色的背景当然,但我宁可改变的背景下,以透明的。
所以我想知道如果我怎么可以删除一些简单的JPEG文物。有没有人曾这样做过?
感谢您的时间。
例的形象:
变形象:
解决方案
好吧,我尝试了一些远非完美的东西,但我认为它可能对其他人有用。
我已经到了:
遇到的问题:阴影远离'白色'很难自动转换它们,即使你做了阴影仍然会在图像本身。顶部眩光......毂的东西,也更接近白色和抗锯齿位。图像中有三到七个白点,它们没有连接到任何一个主角;最后,边缘仍然有一点白色(可能通过调整代码来摆脱它,但不是没有取下部分眩光顶部。
C#低效代码:
static void Main()
{
Bitmap bmp=new Bitmap("test.jpg");
int width = bmp.Width;
int height = bmp.Height;
Dictionary<Point, int> currentLayer = new Dictionary<Point, int>();
currentLayer[new Point(0, 0)] = 0;
currentLayer[new Point(width - 1, height - 1)] = 0;
while (currentLayer.Count != 0)
{
foreach (Point p in currentLayer.Keys)
bmp.SetPixel(p.X, p.Y, Color.Black);
Dictionary<Point, int> newLayer = new Dictionary<Point, int>();
foreach (Point p in currentLayer.Keys)
foreach (Point p1 in Neighbors(p, width, height))
if (Distance(bmp.GetPixel(p1.X, p1.Y), Color.White) < 40)
newLayer[p1] = 0;
currentLayer = newLayer;
}
bmp.Save("test2.jpg");
}
static int Distance(Color c1, Color c2)
{
int dr = Math.Abs(c1.R - c2.R);
int dg = Math.Abs(c1.G - c2.G);
int db = Math.Abs(c1.B - c2.B);
return Math.Max(Math.Max(dr, dg), db);
}
static List<Point> Neighbors(Point p, int maxX, int maxY)
{
List<Point> points=new List<Point>();
if (p.X + 1 < maxX) points.Add(new Point(p.X + 1, p.Y));
if (p.X - 1 >= 0) points.Add(new Point(p.X - 1, p.Y));
if (p.Y + 1 < maxY) points.Add(new Point(p.X, p.Y + 1));
if (p.Y - 1 >= 0) points.Add(new Point(p.X, p.Y - 1));
return points;
}
代码的工作方式是从两点开始;将它们设置为黑色,然后检查它们附近的邻居是否接近白色;如果他们被添加到列表然后执行。最终它会耗尽白色像素来改变。
作为替代方案,您可能需要考虑重新设计网站以使用白色背景。
其他提示
循环遍历图像中的每个像素,如果R,G和B高于,例如230,则用您想要的颜色(或透明)替换颜色。甚至可能会根据旧颜色与“真实”白色的距离来加权新颜色。
如果实际图像也是白色,则会出现问题,否则你最终会得到一个灰色的冲锋队:)
你不会是能够做到这一自动任何东西像是100%的准确性。
这是因为,只有信息,你有颜色,你知道, 一些 像素在图像正在试图混的很好。只有一些像素的图像实际上将被用颜色或接近这个价值为目的的阴影的背景,其他人将可以使用(在这种情况下白色的),因为实际的对象表示,实际上是白色(该死的精度,这些帝国的冲锋队).
这种复杂的机学习,以检测是这是一个有趣的问题领域,并且可能是一个有趣的项目,但它肯定不会让一个快速解决方案,以你的立即的问题。
另一个问题是,甚至如果你可以检测具有良好的可靠性的那些区域的图像正在试图混入回地面你会有问题'unblending'他们然后reblending他们成为你的新的背景的颜色,除非颜色是合理的兼容。在这种情况下你的灰色的工作可能由于它是一个广泛的颜色像的白色。
技术要使用如下:
- 使用洪水填写的算法来选择,从边缘的图像在内的所有像素内的x%(1)已知的背景的颜色。
- 对于那些像素置他们的alpha channel值的比例他们的比赛的原来的颜色和消除色铸这是与它相关联。
- 因此,如果背景下是RGB value a、b、c和素是a+5、b、c-7的结果 RGBA5,0,0,((a+b+c-7)/(a+b+c)*256)(1)
- 复合这个阿尔法的混合图像过去一痛苦方的新回到地面colur.
- 渲染的结果没有阿尔法渠道的新图像。
这仍然会有问题的对象,其颜色是靠近任何一背景色。*在这种情况的原则,它可能是阴影正在使用的是意味着存在的对象,因为这种洪水填补将'侵略'内部的图像。*在后一种情况下所得的图像将会丢失的定义对象并没有微妙的阴影,重点,或只是简单的线路将本来表示,其目的结束以及回地结束。
这是一个非常粗略的第一近似值,但可以复盖一个合理的百分比的目标。那些照片与透明的全封闭孔(喜欢的差距在外拱你的例子)不是有可能没有很好地工作,在一种自动的时尚,因为算法将无法区分白洞和白色的冲锋队。
你可能希望做你的算法突出显示该区域的图像,它计划在reblending并允许简单的选择的地区包括/排除(使用魔术棒的选择的工具,从Pain.Net 作为一个例子如何做到这一点,如果你想看中,允许进行简单的每一像素的选择更少的前期努力。
- 值x的东西你以为你-它可能是,根据一些方面的图像(说的比例的图像它接近于回地面的颜色)你可以调整。
- 注意,这一公式中假定一个靠近白的颜色,对于靠近黑色的你想要颠倒
另一种基于评论对话框的方法:
static void Main()
{
Bitmap mask = new Bitmap(@"mask.bmp");
Bitmap bmp=new Bitmap(@"test.jpg");
int width = bmp.Width;
int height = bmp.Height;
for(int x=0; x<width; x++)
for (int y = 0; y < height; y++)
if (mask.GetPixel(x, y).R < 250)
bmp.SetPixel(x,y,mask.GetPixel(x,y));
bmp.Save(@"test3.jpg");
}
给出面具:
你得到了结果:
在Paint.NET中稍微清理掩码的边框并禁用抗锯齿。同样,它只适用于你能辨别出正在使用哪个边框......但它确实很好......除了绿色......
你还必须处理灰白色调。可能当他们最初创建iamges并设置背景颜色时,会出现一些消除锯齿现象,然后当保存为jpg时,并非所有颜色都会被完美保留。因此,如果您使特定颜色透明,则不会获得该颜色的所有阴影,这将留下许多工件。你需要的东西会与颜色与你的关键颜色的接近程度成比例。这可能比像Photoshop这样的批处理脚本更容易,但我不知道这是否是你需要实时做的事情。
没有(远程简单的)方式以编程方式处理此问题。图像边缘周围的白色伪影区域是几乎是白色但不完全的像素的结果,因此它们不会获得透明效果。面具/咖啡杯上还有几个纯白色的斑点,因此它们变得透明,因此变成灰色。
您最好的选择是联系原始网站的网站管理员,看看他们是否可以向您发送原始图片,希望以photoshop或其他格式保存原始图层。然后你可以用保留原始透明度的格式(PNG或类似的东西)重新生成图像,或者使用渐变作为背景(这很难做到这一点,因为你不知道究竟在哪里将呈现图片的渐变。)
正如你所建议的那样,我会在图像周围使用某种边框。
感谢大家的回答......所有好建议......
这是我昨天做的:
public const int PIXEL_REGION = 60;
public const int TRANSPARENT_DISTANCE = 60;
public static readonly Color TRANSPARENT_COLOR = Color.White;
private System.Drawing.Image ProcessImage(System.Drawing.Image image)
{
Bitmap result = new Bitmap(image.Width, image.Height);
Bitmap workImage = new Bitmap(image);
for (int x = 0; x < image.Width; x++)
{
for (int y = 0; y < image.Height; y++)
{
Color color = workImage.GetPixel(x, y);
if (x < PIXEL_REGION || x > image.Width - PIXEL_REGION || y < PIXEL_REGION || y > image.Height - PIXEL_REGION)
{
double distance = CalculateColourDistance(TRANSPARENT_COLOR, color);
if(distance < TRANSPARENT_DISTANCE)
{
result.SetPixel(x, y, Color.Transparent);
continue;
}
}
result.SetPixel(x, y, color);
}
}
return result;
}
private double CalculateColourDistance(Color c1, Color c2)
{
int a = c2.A - c1.A;
int r = c2.R - c1.R;
int g = c2.G - c1.G;
int b = c2.B - c1.B;
return Math.Sqrt(Math.Pow(a, 2) + Math.Pow(r, 2) + Math.Pow(g, 2) + Math.Pow(b, 2));
}
它不是本书中最漂亮的代码,但它的作用是,对于像素区域中的每个像素,它计算Color.White和我自己的颜色之间的距离,当它低于预定距离时,它将被涂上透明的颜色..
这段代码产生以下结果:
对你来说这并不坏......但它仍然很糟糕:)
我有一个技巧,如果成功的话,我会与你们分享......
这是另一次失败的尝试;)
我有一个想法..电影使用绿屏,为什么不为我的图像使用绿色叠加.. 所以这是叠加层:
结果:
所以我学到了关于PNG压缩的另一个有价值的教训..我也用bmp尝试过,但不知怎的,我总是以绿色边框结束..我可以尝试擦除它,但也许我应该把它留在白色背景,在它周围放置一些愚蠢的边框并完成它......
啊好......;)