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

Image 从图像中删除白色背景并使其透明,image,image-processing,wolfram-mathematica,masking,Image,Image Processing,Wolfram Mathematica,Masking,在Mathematica中,我们尝试做以下工作- 但实际照片最终看起来很糟糕(就像在图像周围有一个光环) 以下是我们迄今为止所做的尝试: unground0[img_] := With[{mask = ChanVeseBinarize[img, TargetColor->{1.,1.,1.}]}, Rasterize[SetAlphaChannel[img, ImageApply[1-#&, mask]], Background->None]]] 下面是一个这样做的例子

在Mathematica中,我们尝试做以下工作-

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

以下是我们迄今为止所做的尝试:

unground0[img_] := With[{mask = ChanVeseBinarize[img, TargetColor->{1.,1.,1.}]},
  Rasterize[SetAlphaChannel[img, ImageApply[1-#&, mask]], Background->None]]]
下面是一个这样做的例子

原始图像:

将白色背景替换为无背景的图像(或者,出于演示目的,使用粉色背景):

有没有摆脱光环的办法?通过调整levelpoulding之类的东西,我只能让光环消失,而代价是丢失一些图像


编辑:因此我可以比较赏金的解决方案,请按照上面的方式构造您的解决方案,即一个名为ungound的自包含函数,它获取图像并返回具有透明背景的图像。

我建议对此使用Photoshop并保存为PNG。

您可以采取的可能步骤:

  • 放大面具
  • 模糊它
  • 使用遮罩,按与白色的距离设置透明度
  • 使用遮罩,调整饱和度,使先前更多的白色更饱和

    • 我将泛泛地讲,而不是具体地讲数学。我不知道这些行动是困难的还是琐碎的

      第一步是估计图像边缘像素的alpha(透明度)级别。现在使用的是严格的阈值,因此alpha要么是0%完全透明,要么是100%完全不透明。您应该定义背景的总白色和图像中无可争议的部分颜色之间的范围,并设置适当的比例-如果颜色更接近背景,则为低alpha,如果更接近较暗的截止,则为高alpha。之后,您可以根据周围的alpha值进行调整-像素被透明度包围的越多,其本身就越可能是透明的


      一旦有了alpha值,就需要进行反向混合以获得正确的颜色。当图像显示在背景上时,使用公式
      c=bc*(1-a)+fc*a
      根据alpha值进行混合,其中
      bc
      是背景色,
      fc
      是前景色。在您的例子中,背景是白色(255255255),前景颜色是未知的,因此我们颠倒公式:
      fc=(c-bc*(1-a))/a
      。当
      a=0
      公式要求除以0,但颜色无论如何都不重要,所以只需使用黑色或白色。

      只需将任何“几乎接近白色”的像素替换为具有相同RGB颜色的像素和透明通道上的S形梯度。您可以应用从实体到透明的线性过渡,但正弦、S形或Tanh看起来更自然,这取决于您正在寻找的边缘的锐度,它们会快速从介质移动到实体或透明,但不会以分步/二元的方式,这就是您现在所拥有的

      这样想:

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

      把每种颜色都去掉一点会使它有点“灰白色”,但把所有3种颜色都去掉一点会使它比任何一种颜色都要瘦很多。假设您允许在任何一个通道上减少10%:1.0*.10=.1,现在将此损失分散到所有三个通道上,并将其绑定在0和1之间(对于alpha通道),如果它小于.1,则(损失=0.9)=>0和(损失=1.0)=>1:


      你在这方面唯一的危险(或好处?)是,这与照片中的白人无关。它删除所有的白色。所以,如果你有一张白色汽车的照片,它最后会有透明的补丁。但从您的示例来看,这似乎是一个理想的效果。

      我对图像处理完全不熟悉,但下面是我在使用版本8的新形态学图像处理功能后得到的结果:

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

      也许,取决于您需要的边缘质量:

      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]
      

      编辑

      编辑2

      为了了解图像中光晕和背景缺陷的程度:

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


      作为一个初学者,到处玩玩——有这么多工具可供使用,真是令人惊讶

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

      在belisarius的面具生成的帮助下,这里尝试实施Mark Ransom的方法:

      定位对象的边界:

      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]
      

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


      在各种图像上运行该算法,以测试其鲁棒性,了解其自动化程度,这将是有益的。

      此函数实现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}]
        ]
      
      这是背景删除功能。
      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]
        ]
      
      测试功能:

      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]
      

      简要说明其工作原理:

    • 选择您最喜欢的生成相对精确锐利边缘的二元化方法

    • 将其应用于放大的图像,然后将获得的
      遮罩
      缩小到原始大小。这给了我们抗锯齿。大部分工作都完成了

    • 对于一个小的改进,将图像混合到背景上,使用其负片的亮度作为alpha,然后将获得的图像混合到原始图像上
      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]
      
      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}]
        ]
      
      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]
        ]
      
      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]