How to remove image background color using JVM?¶
| scala | jvm | computer vision |
References¶
Results¶
The table below shows results of the background removals for sample images.
Columns description:
- Original image
 - Remove color: result of single color removal (color of 
pixel (0,0)) - Remove color range: result of color range removal (
EEEEEE-EFEFEF) 
Since transparency is not easy to present I decided to use “red” color instead.
All Orinial images exept #2 have gray background, image #2 has white background. That’s why Remove color works the best for #2.
| # | Original | Remove color | Remove color range | 
|---|---|---|---|
| 1. | ![]()  |  ![]()  |  ![]()  |  
| 2. | ![]()  |  ![]()  |  ![]()  |  
| 3. | ![]()  |  ![]()  |  ![]()  |  
| 4. | ![]()  |  ![]()  |  ![]()  |  
| 5. | ![]()  |  ![]()  |  ![]()  |  
Notes¶
- The selected “default” range is too aggressive for image #4, we removed/”made transparent” even the product’s part.
 - Also, I dediced to use a wider color range (
EDEDED-F0F0F0) for sample #5. It works well for such type of images. 

Code snippets¶
import java.awt.image._
import java.awt.{Color, Image, Toolkit}
import java.io.File
import javax.imageio.ImageIO
class AddTransparency {
  /**
   * https://www.infoworld.com/article/2074105/making-white-image-backgrounds-transparent-with-java-2d-groovy.html
   *
   * Make provided image transparent wherever color matches the provided color.
   *
   * @param im BufferedImage whose color will be made transparent.
   * @param color Color in provided image which will be made transparent.
   * @return Image with transparency applied.
   */
  def transformColorToTransparency(im: BufferedImage, color: Color): Image = {
    val filter: ImageFilter = new RGBImageFilter() {
      // the color we are looking for (white)... Alpha bits are set to opaque
      val markerRGB = color.getRGB | 0xFF000000
      def filterRGB(x: Int, y: Int, rgb: Int) = {
        if ((rgb | 0xFF000000) == markerRGB) { // Mark the alpha bits as zero - transparent
          0x00FFFFFF & rgb
        } else { // nothing to do
          rgb
        }
      }
    }
    val ip: ImageProducer = new FilteredImageSource(im.getSource, filter)
    Toolkit.getDefaultToolkit.createImage(ip)
  }
  /**
   * https://stackoverflow.com/questions/665406/how-to-make-a-color-transparent-in-a-bufferedimage-and-save-as-png
   */
  def transformColorRangeToTransparency(image: BufferedImage, c1: Color, c2: Color): Image = {
    val (r1, g1, b1) = (c1.getRed, c1.getGreen, c1.getBlue)
    val (r2, g2, b2) = (c2.getRed,c2.getGreen, c2.getBlue)
    val filter = new RGBImageFilter() {
      override final def filterRGB(x: Int, y: Int, rgb: Int): Int = {
        val r = (rgb & 0xFF0000) >> 16
        val g = (rgb & 0xFF00) >> 8
        val b = rgb & 0xFF
        if ( r >= r1 && r <= r2
          && g >= g1 && g <= g2
          && b >= b1 && b <= b2) { // Set fully transparent but keep color
          return rgb & 0xFFFFFF
        }
        rgb
      }
    }
    val ip = new FilteredImageSource(image.getSource, filter)
    Toolkit.getDefaultToolkit.createImage(ip)
  }
  def imageToBufferedImage(image: Image, bgColor: Option[Color] = None): BufferedImage = {
    val bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB)
    val g2 = bufferedImage.createGraphics()
    bgColor.foreach(c => g2.setPaint(c))
    g2.fillRect(0, 0, bufferedImage.getWidth, bufferedImage.getHeight)
    g2.drawImage(image, 0, 0, null)
    g2.dispose()
    bufferedImage
  }
  def writeImage(fileName: String, bi: BufferedImage) = {
    val outputfile = new File(s"tmp/$fileName")
    println("outputfile: " + outputfile.getAbsolutePath)
    ImageIO.write(bi, "png", outputfile)
  }
  def readBufferedImage(path: String): BufferedImage = {
    val classLoader = getClass.getClassLoader
    val file = new File(classLoader.getResource(path).getFile)
    ImageIO.read(file)
  }
}
Generate images¶
class AddTransparencySpec extends AnyFlatSpec {
  behavior of "AddTransparency"
  val at = new AddTransparency()
  it should "transformColorRangeToTransparency" in {
    val files = List.range(1,6).map(s => s"img$s")
    println(files)
    files.foreach { file =>
      val source: BufferedImage = at.readBufferedImage(s"poc/$file.jpg")
      val color = new Color(source.getRGB(0, 0))
      println(s"color = $color")
      val c1 = Color.decode("#EEEEEE")
      val c2 = Color.decode("#EFEFEF")
      val imageWithTransparency: Image = at.transformColorRangeToTransparency(source, c1, c2)
      val transparentImage = at.imageToBufferedImage(imageWithTransparency, bgColor = Some(Color.RED))
      at.writeImage(s"${file}_color_range_transparent.png", transparentImage)
    }
  }
  it should "transformColorToTransparency" in {
    val files = List.range(1,6).map(s => s"img$s")
    println(files)
    files.foreach { file =>
      val image: BufferedImage = at.readBufferedImage(s"poc/$file.jpg")
      println(imgInfo(image))
      val color = new Color(image.getRGB(0, 0))
      println(s"color = $color")
      val imageWithTransparency: Image = at.transformColorToTransparency(image, color)
      val transparentImage = at.imageToBufferedImage(imageWithTransparency, Some(Color.RED))
      at.writeImage(s"${file}_color_transparent.png", transparentImage)
    }
  }
  it should "img5" in {
    val file = "img5"
    val source: BufferedImage = at.readBufferedImage(s"poc/$file.jpg")
    val color = new Color(source.getRGB(0, 0))
    println(s"color = $color")
    val c1 = Color.decode("#EDEDED")
    val c2 = Color.decode("#F0F0F0")
    val imageWithTransparency: Image = at.transformColorRangeToTransparency(source, c1, c2)
    val transparentImage = at.imageToBufferedImage(imageWithTransparency, bgColor = Some(Color.RED))
    at.writeImage(s"${file}_color_range_transparent_special.png", transparentImage)
  }
  def imgInfo(img: BufferedImage): String = {
    val info = s"w:${img.getWidth}, h:${img.getHeight}"
    info
  }
}














