How to remove Background Color Removal  with Python and OpenCV

How to remove Background Color Removal with Python and OpenCV

  • 359

Image processing basics.How to remove Background Color Removal with Python and OpenCV.Automating Background Color Removal with Python and OpenCV. Sleep for the poll_time assigned (1 second). Store the file information in the directory in a dictionary called after.

A couple of days ago, I was faced with a project that demanded removing the white background of sketches when they’re dropped into a certain folder. This was all happening in a hardware scanner.

Here’s an example of a sketch:

This is image title

Example drawing

The first step is to install dependencies for this project, which are listed below. We will also be using Python 3.7.

opencv_python==4.1.0.25
pip install opencv-python
numpy==1.16.4
pip install numpy

After that, we will begin by importing all the required modules for the project:

import cv2
import os
import string
import random
from os import listdir
from os.path import isfile, join, splitext
import time
import sys
import numpy as np
import argparse

We then create three different variables: the name of the folder to watch, the name of the folder where the images will end up after being processed, and the polling time when watching the folder (i.e. how frequently it checks for changes in the folder — one second in our case)

watch_folder = ‘toprocess’
processed_folder = ‘processed’
poll_time = 1

The folders ‘toprocess’, and ‘processed’ will be in the same directory of our python script for now.

We will then move to our main function, which will watch our ‘toprocess’ directory, and if any changes happen, will process the image dropped into that folder.

before = dict([(f, None) for f in os.listdir(watch_folder)])
while 1:
  time.sleep(poll_time)
  after = dict([(f, None) for f in os.listdir(watch_folder)])
  added = [f for f in after if not f in before]
  removed = [f for f in before if not f in after]
  if added:
    print(“Added “, “, “.join(added))
  if added[0] is not None:
    processImage(added[0])
  if removed:
    print(“Removed “, “, “.join(removed))
  before = after

This code runs in an infinite loop, until the script is killed. When initiated, it stores the files in the directory inside a dictionary called “before”. Next, the steps in the infinite loop are broken down below in pseudo code:

  • Sleep for the poll_time assigned (1 second).
  • Store the file information in the directory in a dictionary called after.
  • Store what has been added by comparing what is IN after and NOT in before (f for f in after if not f in before).
  • Store what has been removed by comparing what is IN before and NOT in after.
  • Check the last added element (added[0]), if it is there, then call a function which we will discuss in a bit called processImage on the file.
  • If removed, just let the user know by printing some info.
  • Lastly, update before to after for the latest files in the directory.

Now for the processImage function, which is the heart of the program. This is where the OpenCV background removal magic happens. The code is explained the comments below (Basic OpenCV knowledge is required):

def processImage(fileName):
  # Load in the image using the typical imread function using our watch_folder path, and the fileName passed in, then set the final output image to our current image for now
  image = cv2.imread(watch_folder + ‘/’ + fileName)
  output = image
  # Set thresholds. Here, we are using the Hue, Saturation, Value color space model. We will be using these values to decide what values to show in the ranges using a minimum and maximum value. 
THESE VALUES CAN BE PLAYED AROUND FOR DIFFERENT COLORS
  hMin = 29  # Hue minimum
  sMin = 30  # Saturation minimum
  vMin = 0   # Value minimum (Also referred to as brightness)
  hMax = 179 # Hue maximum
  sMax = 255 # Saturation maximum
  vMax = 255 # Value maximum
  # Set the minimum and max HSV values to display in the output image using numpys' array function. We need the numpy array since OpenCVs' inRange function will use those.
  lower = np.array([hMin, sMin, vMin])
  upper = np.array([hMax, sMax, vMax])
  # Create HSV Image and threshold it into the proper range.
  hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # Converting color space from BGR to HSV
  mask = cv2.inRange(hsv, lower, upper) # Create a mask based on the lower and upper range, using the new HSV image
  # Create the output image, using the mask created above. This will perform the removal of all unneeded colors, but will keep a black background.
  output = cv2.bitwise_and(image, image, mask=mask)
  # Add an alpha channel, and update the output image variable
  *_, alpha = cv2.split(output)
  dst = cv2.merge((output, alpha))
  output = dst
  # Resize the image to 512, 512 (This can be put into a variable for more flexibility), and update the output image variable.
  dim = (512, 512)
  output = cv2.resize(output, dim)
  # Generate a random file name using a mini helper function called randomString to write the image data to, and then save it in the processed_folder path, using the generated filename.
  file_name = randomString(5) + ‘.png’
  cv2.imwrite(processed_folder + ‘/’ + file_name, output)

That was a pretty straightforward function and it does the job properly. Again, playing around with the thresholds can give even better results. One last thing we need to discuss is the mini helper function that generates a random string for the filename.

def randomString(length):
  letters = string.ascii_lowercase
  return ‘’.join(random.choice(letters) for i in range(length))

This is a simple function. It gets letters using the “string” library, then joins a random choice of characters based on the length you passed in. Passing in a length of 5 will generate a string of 5 characters.

The result of the processing is shown below.

This is image title

Of course, this result can be improved by playing around with the values and having better quality scans.

Thank you for sticking to the end of this piece. I hope it helps you in your upcoming projects.