从图像中删除白色背景,并使其透明

我们正在尝试在Mathematica中执行以下操作:
RMagick从图像中删除白色背景,并使其透明

但是,实际的照片最终看起来很糟糕(就像在图像周围有一个光环)。

以下是我们到目前为止的尝试:

unground0[img_] := With[{mask = ChanVeseBinarize[img, TargetColor->{1.,1.,1.}]}, Rasterize[SetAlphaChannel[img, ImageApply[1-#&, mask]], Background->None]]] 

这是一个例子。

原始图像:

原始图像

用白色背景replace没有背景的图像(或者为了演示的目的,这里是粉色背景):

透明背景图像 - 这里实际上是一个粉红色的背景,使光环问题变得明显

任何想法摆脱这个光环? 调整LevelPenalty之类的东西,我只能让光环消失,而不惜损失一些图像。

编辑:所以我可以比较解决scheme的赏金,请像上面那样构build你的解决scheme,即一个名为unground的自包含的函数 – 东西,需要一个图像,并返回一个图像的透明背景。 非常感谢大家!

也许,根据您需要的边缘质量:

 img = Import@"http://i.stack.imgur.com/k7E1F.png"; mask = ChanVeseBinarize[img, TargetColor -> {1., 1., 1.}, "LengthPenalty" -> 10] mask1 = Blur[Erosion[ColorNegate[mask], 2], 5] Rasterize[SetAlphaChannel[img, mask1], Background -> None] 

在这里输入图像说明

编辑

Stealing a bit from @Szabolcs

 img2 = Import@"http://i.stack.imgur.com/k7E1F.png"; (*key point:scale up image to smooth the edges*) img = ImageResize[img2, 4 ImageDimensions[img2]]; mask = ChanVeseBinarize[img, TargetColor -> {1., 1., 1.}, "LengthPenalty" -> 10]; mask1 = Blur[Erosion[ColorNegate[mask], 8], 10]; f[col_] := Rasterize[SetAlphaChannel[img, mask1], Background -> col, ImageSize -> ImageDimensions@img2] GraphicsGrid[{{f@Red, f@Blue, f@Green}}] 

在这里输入图像说明

点击放大

编辑2

只是想知道图像中光晕和背景不完整的程度:

 img = Import@"http://i.stack.imgur.com/k7E1F.png"; Join[{img}, MapThread[Binarize, {ColorSeparate[img, "HSB"], {.01, .01, .99}}]] 

在这里输入图像说明

 ColorNegate@ImageAdd[EntropyFilter[img, 1] // ImageAdjust, ColorNegate@img] 

在这里输入图像说明

这个函数实现了Mark Ransom所描述的反向混合,这是一个小而明显的改进:

 reverseBlend[img_Image, alpha_Image, bgcolor_] := With[ {c = ImageData[img], a = ImageData[alpha] + 0.0001, (* this is to minimize ComplexInfinitys and considerably improve performance *) bc = bgcolor}, ImageClip@ Image[Quiet[(c - bc (1 - a))/a, {Power::infy, Infinity::indet}] /. {ComplexInfinity -> 0, Indeterminate -> 0}] ] 

这是背景删除function。 threshold参数用于图像的初始二值化, minSizeCorrection用于调整二值化后要去除的小垃圾成分的大小限制。

 removeWhiteBackground[img_, threshold_: 0.05, minSizeCorrection_: 1] := Module[ {dim, bigmask, mask, edgemask, alpha}, dim = ImageDimensions[img]; bigmask = DeleteSmallComponents[ ColorNegate@ MorphologicalBinarize[ColorNegate@ImageResize[img, 4 dim], threshold], Round[minSizeCorrection Times @@ dim/5]]; mask = ColorNegate@ ImageResize[ColorConvert[bigmask, "GrayScale"], dim]; edgemask = ImageResize[ ImageAdjust@DistanceTransform@Dilation[EdgeDetect[bigmask, 2], 6], dim]; alpha = ImageAdd[ ImageSubtract[ ImageMultiply[ColorNegate@ColorConvert[img, "GrayScale"], edgemask], ImageMultiply[mask, edgemask]], mask]; SetAlphaChannel[reverseBlend[img, alpha, 1], alpha] ] 

testingfunction:

 img = Import["http://i.stack.imgur.com/k7E1F.png"]; background = ImageCrop[ Import["http://cdn.zmescience.com/wp-content/uploads/2011/06/\ forest2.jpg"], ImageDimensions[img]]; result = removeWhiteBackground[img] ImageCompose[background, result] Rasterize[result, Background -> Red] Rasterize[result, Background -> Black] 

样品

简要说明它是如何工作的:

  1. select您最喜爱的binariaztion方法,产生相对精确的锐利边缘

  2. 将其应用于放大的图像,然后将获取的mask缩减为原始大小。 这给了我们抗锯齿。 大部分工作已经完成。

  3. 对于一个小的改进,将图像混合到背景上,使用其负像素的亮度作为alpha,然后将获得的图像混合在边缘周围的薄区域(边缘edgemask )中的原始图像上,以降低边缘上白色像素的可见性。 计算这些操作对应的alpha通道(有些ImageMultiply/Addexpression式)。

  4. 现在我们估计了alpha通道,所以我们可以做一个反向混合。

步骤3和步骤4并没有提高那么多,但差别是可见的。

我将会泛泛而谈,并不是特指Mathematica。 我不知道这些行动是困难的还是微不足道的。

第一步是估计图像边缘的像素的alpha(透明度)级别。 现在你正在使用一个严格的阈值,所以alpha是0%完全透明或100%完全不透明。 你应该定义一个背景的总白色和图像中无可争议的颜色之间的范围,并设置一个适当的比例 – 如果颜色接近于背景,则为低alpha,如果它接近较暗的截止点,那么它是高阿尔法。 之后,您可以根据周围的alpha值进行调整 – 像素被透明度包围的越多,透明度越高。

一旦你有阿尔法值,你需要做一个反向混合来获得正确的颜色。 当图像显示在背景上时,根据alpha值使用公式c = bc*(1-a)+fc*a ,其中bc是背景色, fc是前景色。 在你的情况下,背景是白色的(255,255,255),前景色是未知的,所以我们反转公式: fc = (c - bc*(1-a))/a 。 当a=0 ,公式要求除以零,但颜色无关紧要,只需使用黑色或白色即可。

以下是在实施Mark Ransom的方法上的一个尝试,在Belisarius的面具生成的帮助下:

find对象的边界:

 img1 = SetAlphaChannel[img, 1]; erosionamount=2; mb = ColorNegate@ChanVeseBinarize[img, TargetColor -> {1., 1., 1}, "LengthPenalty" -> 10]; edge = ImageSubtract[Dilation[mb, 2], Erosion[mb, erosionamount]]; ImageApply[{1, 0, 0} &, img, Masking ->edge] 

图边缘

设置alpha值:

 edgealpha = ImageMultiply[ImageFilter[(1 - Mean[Flatten[#]]^5) &, ColorConvert[img, "GrayScale"], 2, Masking -> edge], edge]; imagealpha = ImageAdd[edgealpha, Erosion[mb, erosionamount]]; img2 = SetAlphaChannel[img, imagealpha]; 

反向混色:

 img3 = ImageApply[Module[{c, \[Alpha], bc, fc}, bc = {1, 1, 1}; c = {#[[1]], #[[2]], #[[3]]}; \[Alpha] = #[[4]]; If[\[Alpha] > 0, Flatten[{(c - bc (1 - \[Alpha]))/\[Alpha], \[Alpha]}], {0., 0., 0., 0}]] &, img2]; Show[img3, Background -> Pink] 

粉色的背景

注意一些边缘有白色绒毛? 将它与第一幅图像中的红色轮廓进行比较。 我们需要更好的边缘检测器。 增加侵蚀量有助于模糊,但其他方面变得太透明,所以在边缘掩模的宽度上存在折衷。 不过,考虑到本身没有模糊操作,这是相当不错的。

在各种图像上运行该algorithm以testing其鲁棒性,看看它是多么自动,这将是有益的。

作为一个初学者,玩起来真是太棒了,有多less种工具可以使用。

 b = ColorNegate[ GaussianFilter[MorphologicalBinarize[i, {0.96, 0.999}], 6]]; c = SetAlphaChannel[i, b]; Show[Graphics[Rectangle[], Background -> Orange, PlotRangePadding -> None], c] 

我对image processing是全新的,但是这是我在玩了8版本的新形态image processingfunction后得到的结果:

 mask = DeleteSmallComponents[ ColorNegate@ Image[MorphologicalComponents[ColorNegate@img, .062, Method -> "Convex"], "Bit"], 10000]; Show[Graphics[Rectangle[], Background -> Red, PlotRangePadding -> None], SetAlphaChannel[img, ColorNegate@mask]] 

图片

我build议使用Photoshop来保存为PNG格式。

你可能采取的步骤:

  • 扩张面具
  • 模糊它
  • 使用蒙版,从白色的距离设置透明度
  • 使用蒙版,调整饱和度,使以前更白的颜色更饱和。

只需用透明度通道上的相同RGB颜色和Sigmoid渐变的像素replace“接近白色”的任何像素即可。 您可以应用从实体到透明的线性转换,但是Sinusoid或Sigmoid或Tanh看起来更自然,这取决于您正在查找的边缘的锐度,它们会从介质快速移动到固体或透明,但不能以逐步/二进制方式,这是你现在拥有的。

这样想:

假设R,G,B分别为0.0-1.0,那么我们将白色表示为一个单一的数字,如R + G + B = 1.0 * 3 = 3.0。

每种颜色的一点点使它有点“灰白色”,但是采取一点点的三点比任何一点点都less得多。 假设您允许在任何一个频道上减less10%:1.0 * .10 = .1,现在将这个损失在所有三个频道上进行分散,并将其绑定到0到1之间,如果它小于.1,损失= 0.9)=> 0和(损失= 1.0)=> 1:

 threshold=.10; maxLoss=1.0*threshold; loss=3.0-(R+G+B); alpha=If[loss>maxLoss,0,loss/maxLoss]; (* linear scaling is used above *) (* or use 1/(1 + Exp[-10(loss - 0.5maxLoss)/maxLoss]) to set sigmoid alpha *) (* Log decay: Log[maxLoss]/Log[loss] (for loss and maxLoss <1, when using RGB 0-255, divide by 255 to use this one *) setNewPixel[R,G,B,alpha]; 

以供参考:

 maxLoss = .1; Plot[{ 1/(1 + Exp[-10(loss - 0.5maxLoss)/maxLoss]), Log[maxLoss]/Log[loss], loss/maxLoss }, {loss, 0, maxLoss}] 

唯一的危险(或好处?)你在这里,这是不关心白人实际上是照片的一部分。 它删除所有的白人。 所以,如果你有一张白色的汽车的照片,它最终会有透明的补丁。 但从你的例子来看,这似乎是一个理想的效果。