Watershed Algorithm for Image Segmentation: Practical Implementation in OpenCV Python

Watershed Algorithm for Image Segmentation: Practical Implementation in OpenCV Python

Watershed Algorithm for Image Segmentation – Image segmentation is a crucial computer vision task that involves partitioning an image into meaningful and semantically homogeneous regions. This process simplifies the representation of an image, making it more useful for further analysis. These segments often correspond to objects or regions of interest within the image.

Watershed Algorithm for Image Segmentation – Watershed Algorithm

The Watershed Algorithm is a classical image segmentation technique based on the concept of watershed transformation. The segmentation process uses the similarity between adjacent pixels of the image as an important reference to connect pixels with similar spatial positions and gray values.

When to Use the Watershed Algorithm

The Watershed Algorithm is particularly useful when segmenting images with touching or overlapping objects. It is effective in scenarios with irregular object shapes, gradient-based segmentation requirements, and when marker-guided segmentation is feasible.

How the Watershed Algorithm Works

The Watershed Algorithm divides an image into segments using topographic information, treating the image as a topographic surface. It identifies catchment basins based on pixel intensity, marks local minima as starting points, and floods with colors to fill catchment basins until object boundaries are reached. The resulting segmentation assigns unique colors to regions, aiding object recognition and image analysis.

Watershed Algorithm for Image Segmentation The whole process of the Watershed Algorithm can be summarized in the following steps:

  1. Marker Placement: The first step is to place markers on the local minima, or the lowest points, in the image. These markers serve as the starting points for the flooding process.
  2. Flooding: The algorithm floods the image with different colors, starting from the markers. As the color spreads, it fills up the catchment basins until it reaches the boundaries of the objects or regions in the image.
  3. Catchment Basin Formation: As the color spreads, the catchment basins are gradually filled, creating a segmentation of the image. The resulting segments or regions are assigned unique colors, which can then be used to identify different objects or features in the image.
  4. Boundary Identification: The watershed algorithm uses the boundaries between the different colored regions to identify the objects or regions in the image. The resulting segmentation can be used for object recognition, image analysis, and feature extraction tasks.

Implementing the Watershed Algorithm Using OpenCV

OpenCV (Open Source Computer Vision Library) is an open-source computer vision and machine learning software library that includes hundreds of computer vision algorithms, including object detection, face recognition, image processing, and machine learning.

Here are the implementation steps for the Watershed Algorithm using OpenCV:

  1. Import the Required Libraries: Start by importing the necessary libraries, including OpenCV and NumPy.
import cv2
import numpy as np
from IPython.display import Image, display
from matplotlib import pyplot as plt

Loading the image

We define a function “imshow” to display the processed image. The code loads an image named “coin.jpg“.

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Define a function to show images using matplotlib
def imshow(img, title="Image"):
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    plt.title(title)
    plt.axis('off')  # Hide the axes
    plt.show()

# Load the image
img = cv2.imread("coins.png")

# Show the image
imshow(img)

Converting to Grayscale image
Now, let us convert the image to grayscale using OpenCV’s “cvtColor” method. The grayscale image is stored in a variable “gray”.

import cv2
import numpy as np
from matplotlib import pyplot as plt

# Define a function to show images using matplotlib
def imshow(img, title="Image"):
    plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    plt.title(title)
    plt.axis('off')  # Hide the axes
    plt.show()

# Load the image
img = cv2.imread("coins.png")

# Show the image
imshow(img)
#image grayscale conversion
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
imshow(gray)

The cv2.cvtColor() function takes two arguments: the image and the conversion flag cv2.COLOR_BGR2GRAY, which specifies the conversion from the BGR color space to grayscale.

Implementing Thresholding

A crucial step in image segmentation is thresholding, which converts a grayscale image into a binary image. This process is essential for distinguishing objects of interest from the background.

When using the cv2.THRESH_BINARY_INV thresholding method in OpenCV, the cv2.THRESH_OTSU parameter can be added to apply Otsu’s binarization process. Otsu’s method automatically determines the optimal threshold by maximizing the variance between two classes of pixels in the image. This approach aims to find a threshold that minimizes intra-class variance and maximizes inter-class variance, effectively separating the image into two groups of pixels with distinct characteristics.

Otsu’s Binarization Process
Otsu’s binarization is a technique in image processing used to separate the foreground from the background by dividing an image into two distinct classes. It works by finding the optimal threshold value that maximizes the variance between these two classes. Known for its simplicity and computational efficiency, Otsu’s method is widely used in applications such as document analysis, object recognition, and medical imaging.

#Threshold Processing
ret, bin_img = cv2.threshold(gray,
							0, 255, 
							cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
imshow(bin_img)

Noise Removal:

# noise removal
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
bin_img = cv2.morphologyEx(bin_img, 
						cv2.MORPH_OPEN,
						kernel,
						iterations=2)
imshow(bin_img)

Detecting the Black Background and Foreground of the Image

To detect the black background and foreground in an image, we need to identify the black area, which represents the background. If the white part is the region of interest and is well-filled, the rest is the background.

We can achieve this by applying several morphological operations to our binary image:

  1. Dilation: The first operation is dilation using cv2.dilate, which expands the bright regions of the image. This creates the sure_bg variable representing the sure background area. The result is displayed using the imshow function.
  2. Distance Transform: Next, we use cv2.distanceTransform to calculate the distance of each white pixel in the binary image to the nearest black pixel. The result is stored in the dist variable and displayed using imshow.
  3. Thresholding: The foreground area is obtained by applying a threshold to the dist variable using cv2.threshold. The threshold is set to 0.5 times the maximum value of dist.
  4. Calculating the Unknown Area: Finally, the unknown area is calculated as the difference between the sure background and sure foreground areas using cv2.subtract. The result is stored in the unknown variable and displayed using imshow.

Marker Image:

Handling the Gray Area in Image Segmentation

In the image segmentation process, there is often a gray area between the white part of the background and the clearly visible white part of the foreground. This gray area is undefined and needs to be addressed to achieve accurate segmentation. To handle this, we will subtract this area.

Here are the steps:

  1. Connected Components: First, we use the cv2.connectedComponents method from OpenCV to find the connected components in the sure foreground image sure_fg. The result is stored in the markers variable.
  2. Distinguishing Background and Foreground: To differentiate between the background and the foreground, we increment the values in markers by 1.
  3. Labeling the Unknown Region: The unknown region, represented by pixels with a value of 255 in unknown, is labeled with 0 in markers.
  4. Displaying the Markers: Finally, the markers image is displayed using Matplotlib’s imshow method with a color map of tab20b. The result is shown in a figure with a size of 6×6.

By following these steps, we can effectively handle the gray area and achieve accurate image segmentation.

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

# Add one to all labels so that background is not 0, but 1
markers += 1
# mark the region of unknown with zero
markers[unknown == 255] = 0

fig, ax = plt.subplots(figsize=(6, 6))
ax.imshow(markers, cmap="tab20b")
ax.axis('off')
plt.show()

Conclusion

The Watershed Algorithm is a powerful and classical technique for image segmentation, particularly effective for separating touching or overlapping objects. By treating the image as a topographic surface and using flooding from marked points, it enables precise delineation of object boundaries based on pixel intensity gradients. This makes it highly suitable for scenarios with irregular object shapes and gradient-based segmentation requirements.

In our practical implementation using OpenCV in Python, we demonstrated the entire process from image preprocessing to segmentation. Key steps included converting the image to grayscale, applying thresholding and morphological operations, and utilizing distance transforms. By carefully placing markers, we guided the watershed algorithm to accurately segment the image into meaningful regions.

The segmentation process involved:

  1. Grayscale Conversion and Thresholding: Converting the image to grayscale and applying Otsu’s binarization to create a binary image.
  2. Morphological Operations: Using dilation to identify the sure background and distance transforms to identify the sure foreground.
  3. Marker Placement: Placing markers at local minima and incrementing marker values to distinguish between different regions.
  4. Watershed Algorithm: Applying the watershed algorithm to flood the image from the markers, resulting in distinct segmentation of objects.
  5. Handling Gray Areas: Addressing the undefined regions by subtracting the unknown areas and ensuring accurate labeling of the background and foreground.

By following these steps, we achieved robust image segmentation that can be applied to various computer vision tasks such as object recognition, medical imaging, and document analysis. The use of OpenCV’s extensive library functions simplifies the implementation and enhances the efficiency of the algorithm.

In conclusion, the Watershed Algorithm, combined with OpenCV’s capabilities, provides a comprehensive and effective solution for image segmentation challenges. Understanding and implementing this algorithm equips developers and researchers with a valuable tool for processing complex images, ultimately contributing to advancements in computer vision applications.

  1. libraries, including OpenCV and NumPy.

Author

Sona Avatar

Written by

Leave a Reply

Trending

CodeMagnet

Your Magnetic Resource, For Coding Brilliance

Programming Languages

Web Development

Data Science and Visualization

Career Section

<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4205364944170772"
     crossorigin="anonymous"></script>