5 Best Ways to Mask an Image in OpenCV Python

πŸ’‘ Problem Formulation: When working with image processing in OpenCV with Python, a common task is to mask an image. This involves defining a region of interest and applying operations only to that area, while ignoring the rest of the image. For example, you might want to highlight a specific object, remove a section, or apply effects selectively. An input would be an original image, and the desired output is the same image with the mask effect applied to it.

Method 1: Using Basic Numpy Operations

One of the simplest methods for masking in OpenCV involves using Numpy operations. By creating an array of the same size as the image but with a boolean or binary representation of the mask, we can easily apply this mask to the image. The function cv2.bitwise_and is typically used for this purpose, as it performs element-wise conjunction.

Here’s an example:

import cv2
import numpy as np

# Load the image
image = cv2.imread('path_to_image.jpg')

# Create a blank mask
mask = np.zeros(image.shape[:2], dtype="uint8")

# Define the ROI
cv2.rectangle(mask, (x_start, y_start), (x_end, y_end), 255, -1)

# Apply the mask
masked_image = cv2.bitwise_and(image, image, mask=mask)

The output is masked_image, with the region of interest highlighted and the rest of the image masked out.

This code snippet reads an image using OpenCV, creates a mask with a rectangle over the region of interest, and uses cv2.bitwise_and to apply the mask. The output is a new image with the masked region visible.

Method 2: Using Polygonal Masks

For more complex shapes, you can define a polygonal mask. This approach allows you to specify the vertices of a polygon, which OpenCV will fill in to create the mask. With the polygon in place, you can use cv2.bitwise_and as before to apply this mask.

Here’s an example:

import cv2
import numpy as np

# Load the image
image = cv2.imread('path_to_image.jpg')

# Create a blank mask
mask = np.zeros(image.shape[:2], dtype=np.uint8)

# Define a list of vertices for the polygon
points = np.array([[100,50], [200,300], [700,200], [500,100]], dtype=np.int32)

# Create the polygonal mask
cv2.fillPoly(mask, [points], 255)

# Apply the mask
masked_image = cv2.bitwise_and(image, image, mask=mask)

The output is masked_image, with a polygon-shaped area masked.

This snippet uses the cv2.fillPoly function to create a mask with the provided polygonal points, which are then applied to the original image using cv2.bitwise_and.

Method 3: Masking with Thresholding

Thresholding can also be used to create masks. In this method, the mask is created based on pixel values. For instance, you can set a threshold to differentiate the object from the background based on color or intensity, and create a binary mask where the object pixels are white, and the background pixels are black.

Here’s an example:

import cv2
import numpy as np

# Load the image in grayscale
image = cv2.imread('path_to_image.jpg', 0)

# Apply a binary threshold to create a mask
_, mask = cv2.threshold(image, 120, 255, cv2.THRESH_BINARY)

# Convert original image to color
image_colored = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

# Apply the mask
masked_image = cv2.bitwise_and(image_colored, image_colored, mask=mask)

The output is masked_image with the areas meeting the threshold criteria highlighted.

In this code, cv2.threshold creates a binary mask by setting pixel values above 120 to white (255) and the rest to black (0). This mask is then applied to the color-converted image using cv2.bitwise_and.

Method 4: Using Color Spaces for Masking

When dealing with colored images, it can be more effective to convert the image to a different color space, such as HSV, which separates image intensity (brightness) from color information. This is particularly useful for color-based segmentation.

Here’s an example:

import cv2
import numpy as np

# Load the image
image = cv2.imread('path_to_image.jpg')

# Convert to HSV color space
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

# Define color range for masking
lower_val = np.array([30, 50, 50])
upper_val = np.array([80, 255, 255])

# Create mask based on color range
mask = cv2.inRange(hsv, lower_val, upper_val)

# Apply the mask
masked_image = cv2.bitwise_and(image, image, mask=mask)

The output is masked_image, with the colors within the specified range highlighted.

This snippet uses the cv2.cvtColor to convert the image to HSV color space, creates a binary mask with cv2.inRange function specifying the color range, and then applies this mask to the original image using cv2.bitwise_and.

Bonus One-Liner Method 5: Simple Circle Mask

For quickly creating a circular mask with a one-liner, you can use the cv2.circle function to draw a filled circle within a mask matrix. This is a short and straightforward approach when a circular region of interest is needed.

Here’s an example:

import cv2
import numpy as np

# Load the image
image = cv2.imread('path_to_image.jpg')

# Apply the circular mask directly in one line
masked_image = cv2.bitwise_and(image, image, mask=cv2.circle(np.zeros(image.shape[:2], dtype="uint8"), (center_x, center_y), radius, 255, -1))

The output is masked_image, with a circular area masked.

This code comprises an inline creation of a circular mask using cv2.circle, which is directly fed into cv2.bitwise_and function to apply to the image.

Summary/Discussion

  • Method 1: Using Basic Numpy Operations. Strengths: Simple, flexible for rectangular shapes. Weaknesses: Limited to rectangular ROI.
  • Method 2: Using Polygonal Masks. Strengths: Allows masks of arbitrary shapes. Weaknesses: More complex to implement for non-standard shapes.
  • Method 3: Masking with Thresholding. Strengths: Good for separating objects from background. Weaknesses: Not suitable for complex images with varying intensity and color.
  • Method 4: Using Color Spaces for Masking. Strengths: Effective for color segmentation. Weaknesses: Requires knowledge of the color space and target colors.
  • Bonus One-Liner Method 5: Simple Circle Mask. Strengths: Quick and concise for circular ROIs. Weaknesses: Limited to circular shapes only.