Image Segmentation in OpenCV

Introduction to Image Segmentation in OpenCV

Updated March 21, 2023


Hey! If you love Computer Vision and AI, let's connect on Twitter or LinkedIn. I talk about this stuff all the time!

Image segmentation is the process of dividing an image into multiple segments or regions based on various features, such as color, texture, or intensity. It is a fundamental task in computer vision and has numerous applications, including object detection, face recognition, and medical imaging. In this tutorial, we will explore how to perform image segmentation using OpenCV, a popular computer vision library.

Theoretical Background

The most common approach to image segmentation is the thresholding method. This method involves setting a threshold value and classifying each pixel in the image based on whether its intensity is above or below the threshold. Pixels with intensities above the threshold are classified as belonging to one segment, while those below the threshold are classified as belonging to another.

Another approach to image segmentation is clustering, which groups similar pixels into segments based on their proximity in feature space. Clustering algorithms, such as k-means, are commonly used for image segmentation.

Image Segmentation in OpenCV

OpenCV provides several functions for image segmentation, including thresholding, contour detection, and watershed segmentation.

Thresholding

The thresholding function in OpenCV allows us to set a threshold value and convert an image into a binary image, where pixels with values above the threshold are set to one and those below are set to zero.

Here is an example of thresholding an image using OpenCV:

import cv2

img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

cv2.imshow('Original Image', img)
cv2.imshow('Binary Image', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()

In this example, we first read in an image using cv2.imread and convert it to grayscale using cv2.cvtColor. We then use the cv2.threshold function to threshold the image with a threshold value of 127. The function returns two values: the threshold value used (‘ret’) and the thresholded image (‘thresh’).

Contour Detection

Contours are the boundaries of objects in an image. The cv2.findContours function in OpenCV can be used to detect contours in an image. Here is an

example:

import cv2

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

cv2.drawContours(img, contours, -1, (0, 255, 0), 3)

cv2.imshow('Contours', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

In this example, we first threshold the image using the same method as before. We then use the cv2.findContours function to detect contours in the thresholded image. The function returns a list of contours and a hierarchy of nested contours. We then use the cv2.drawContours function to draw the contours on the original image.

Watershed Segmentation

Watershed segmentation is a more advanced method of image segmentation that can be used to separate objects that are touching or overlapping. The cv2.watershed function in OpenCV can be used to perform watershed segmentation.

Here is an example:

import cv2
import numpy as np

img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, 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(img,markers)
img[markers == -1] = [255,0,0]

cv2.imshow('Original Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

In this example, we first read in an image using cv2.imread and convert it to grayscale using cv2.cvtColor. We then apply thresholding using the Otsu’s method to obtain a binary image.

We then perform noise removal and morphological opening to remove any small white noises in the image. We then dilate the image to obtain the sure background region.

We then use distance transform to obtain the sure foreground region. We threshold the distance transformed image to obtain a binary image, and then use it to obtain the sure foreground region.

We then find the unknown region by subtracting the sure foreground region from the sure background region. We then label the markers using the cv2.connectedComponents function.

Finally, we perform watershed segmentation using the cv2.watershed function, and mark the boundaries of the segmented regions on the original image using the cv2.imshow function.

Conclusion

In this tutorial, we explored the basics of image segmentation in OpenCV. We covered the theoretical background of image segmentation and demonstrated how to perform thresholding, contour detection, and watershed segmentation using OpenCV. We hope this tutorial has helped you understand the basics of image segmentation and how it can be used in computer vision applications.