Remove White Background from an Image and Make It Transparent

后端 未结 9 987
一向
一向 2020-11-29 16:01

We\'re trying to do the following in Mathematica - RMagick remove white background from image and make it transparent.

But with actual photos it ends up looking lous

9条回答
  •  心在旅途
    2020-11-29 16:41

    This function implements the reverse blend described by Mark Ransom, for an additional small but visible improvement:

    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}]
      ]
    

    This is the background removal function. The threshold parameter is used for the initial binarization of the image, the minSizeCorrection is for tweaking the size limit of small junk components to be removed after binarization.

    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]
      ]
    

    Testing the function:

    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]
    

    Brief explanation of how it works:

    1. Choose your favourite binariaztion method that produces relatively precise sharp edges

    2. Apply it to an up-scaled image, then downscale the obtained mask to the original size. This gives us antialiasing. Most of the work is done.

    3. For a small improvement, blend the image onto the background using the brightness of its negative as alpha, then blend the obtained image over the original in a thin region around the edges (edgemask) to reduce the visibility of white pixels on the edges. The alpha channel corresponding to these operations is calculated (the somewhat cryptic ImageMultiply/Add expression).

    4. Now we have an estimate of the alpha channel so we can do a reverse blend.

    Steps 3 & 4 don't improve that much, but the difference is visible.

提交回复
热议问题