5 Best Ways to Extract the Foreground of an Image Using OpenCV Python

πŸ’‘ Problem Formulation: In many computer vision tasks, separating the subject of an image from its background is essential. Imagine you have a photo of a person or an object and you want to isolate them from the rest of the scene. The input is a standard image file and the desired output is a new image file where the foreground is separated out.

Method 1: Background Subtraction Using MOG2

Background subtraction is a widely used approach for foreground extraction in videos where the background is relatively static. OpenCV provides a function called createBackgroundSubtractorMOG2() that implements the MOG2 background subtraction algorithm. This method builds a model of the background and then computes the foreground mask.

Here’s an example:

import cv2
background_subtractor = cv2.createBackgroundSubtractorMOG2()
foreground_mask = background_subtractor.apply(image)

Output: A binary image with the foreground depicted as white and the background as black.

The code snippet demonstrates the simplicity of applying MOG2 for background subtraction. By initializing a background subtractor object and applying it to an image, you get a binary foreground mask.

Method 2: GrabCut Algorithm

The GrabCut algorithm is an iterative method that uses graph cuts for image segmentation, effectively distinguishing between foreground and background. OpenCV’s grabCut() function applies the algorithm which requires a rectangle around the object as a starting point.

Here’s an example:

import cv2
import numpy as np

image = cv2.imread('photo.jpg')
mask = np.zeros(image.shape[:2], np.uint8)

bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)

rect = (10,10,300,500) # Rectangle containing the foreground
cv2.grabCut(image,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
image = image*mask2[:,:,np.newaxis]

Output: The original image with the background removed, showing only the foreground object.

This code snippet demonstrates how to use the GrabCut algorithm to segment the foreground from the background. A rectangle is defined around the object, and after processing, the mask2 array is used to create the final image that only contains the foreground.

Method 3: Watershed Algorithm

The Watershed algorithm is a segmentation technique used to identify regions within an image. By treating the grayscale version of an image as a topographic surface, it distinguishes different objects in the image. OpenCV implements Watershed in the watershed() function.

Here’s an example:

import cv2
import numpy as np

image = cv2.imread('photo.jpg')
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)

# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)

# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)

# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)

# Add one to all labels so that sure background is not 0, but 1
markers = markers+1

# Now, mark the region of unknown with zero
markers[unknown==255] = 0

markers = cv2.watershed(image, markers)
image[markers == -1] = [255,0,0] # Marking the borders with red

Output: The image with discovered object boundaries highlighted in red.

This code applies the watershed algorithm to segment the objects in the photo. The regions are clearly delineated, and the boundaries are marked, helping to identify the foreground for further processing if needed.

Method 4: Contour Detection

Contour detection is a technique used to identify the outlines of objects within images. OpenCV’s findContours() function is useful for such tasks, particularly when applied to binary images.

Here’s an example:

import cv2
import numpy as np

image = cv2.imread('photo.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, 0)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

for contour in contours:
    cv2.drawContours(image, [contour], 0, (0,255,0), 3)

Output: The original image with all detected contours drawn over it.

Here we use contour detection to find and draw all the contours within an image. This serves as a step towards extracting the foreground by first identifying the edges that separate different objects.

Bonus One-Liner Method 5: Simple Thresholding

Simple thresholding can sometimes serve as a quick method to extract foreground objects by converting grayscale images to pure black and white based on a defined threshold value, using OpenCV’s threshold() function.

Here’s an example:

import cv2
image = cv2.imread('photo.jpg', 0)
ret, thresh = cv2.threshold(image, 127, 255, cv2.THRESH_BINARY)

Output: A binary image with the potential foreground in white and background in black.

This snippet demonstrates simple thresholding, where every pixel value above 127 is set to white (foreground) and below to black (background), which might help isolate the subject in high-contrast situations.

Summary/Discussion

  • Method 1: Background Subtraction Using MOG2. Effective in videos and conditions with minimal background change. Might require additional morphological operations to refine the foreground mask.
  • Method 2: GrabCut Algorithm. Provides a more accurate cutout of the foreground but requires initial user input to define the foreground area. Can be computationally intensive.
  • Method 3: Watershed Algorithm. Good at separating different objects and their contours. Can be complex to set up and may need further processing for clean segmentation.
  • Method 4: Contour Detection. Useful for edge-based foreground extraction. Best suited for simple and well-defined objects.
  • Bonus Method 5: Simple Thresholding. Quick and easy to implement, but only effective when there’s high contrast between the foreground and background.