Erol

Posted on

# Introduction to Watershed Algorithm

Previously, I worked on Object Detection algorithm and I make detected coordinaters, rotations and dimension of objects. This project is about Watershed. Basically Watershed algoritm is used for seperating the other objects in image. After apply this algorithm, I need to apply some Low-Pass Filtering and Morphological Operations deu to determine area and edge of objects.

### In Watershed Algoritm, I will apply this techniques:

1- Median Blurring
2- Gray Scale
3- Binary Threshold
4- Opening
5- Distance Transform
6- Threshold for foreground
7- Dilation for enlarging image to use for background
8- Connected Components
9- Watershed
10- Find and Draw Contours around of objects

I'll explain these subjects again when I explain code cells.

First of all I must import my libraries I'll use:

``````import cv2
import numpy as np
import matplotlib.pyplot as plt
``````

After that, I need to read my image I want to apply Watershed:

``````coin = cv2.imread("data/coins.jpg")

plt.figure(), plt.title("Original"), plt.imshow(coin), plt.axis("off");
``````

By the way, the semicolon (;) which is in end of plt.axis("off") is a trick for ingoring some inputs of matplotlib.

To remove the noises which are on image I will apply one of Low-Pass Filtering methods called MedianBlurring

``````coin_blur = cv2.medianBlur(src=coin, ksize=13)

plt.figure(), plt.title("Low Pass Filtering (Blurring)"), plt.imshow(coin_blur), plt.axis("off");
``````

After that, I need to convert color of image to Gray

``````coin_gray = cv2.cvtColor(coin_blur, cv2.COLOR_BGR2GRAY)

plt.figure(), plt.title("Gray Scale"), plt.imshow(coin_gray, cmap="gray"), plt.axis("off");
``````

Using Binary Threshold I will make image specific between coins and background

``````ret, coin_thres = cv2.threshold(src=coin_gray, thresh=75, maxval=255, type=cv2.THRESH_BINARY)

plt.figure(), plt.title("Binary Threshold"), plt.imshow(coin_thres, cmap="gray"), plt.axis("off");
``````

As you can see after Thresholding it is almostly clear between coins and background.

Now, I will try to draw these Contours

``````contour, hierarchy = cv2.findContours(image=coin_thres.copy(), mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE)

for i in range(len(contour)):

if hierarchy[0][i][3] == -1: # external contour
cv2.drawContours(image=coin,contours=contour,contourIdx=i, color=(0,255,0), thickness=10)

plt.figure(figsize=(7,7)), plt.title("After Contour"), plt.imshow(coin, cmap="gray"),
plt.axis("off");
``````

But as you all can see it doesn't work, I couldn't seperate their edge.

I will use other method called Watershed for seperating and draw their edge. First method is not Watershed

Before Watershed, I need to apply all of this techniques. For that:

``````# read data
plt.figure(), plt.title("Original"), plt.imshow(coin), plt.axis("off");

# Blurring
coin_blur = cv2.medianBlur(src=coin, ksize=15)
plt.figure(), plt.title("Low Pass Filtering (Blurring)"), plt.imshow(coin_blur), plt.axis("off");

# Gray Scale
coin_gray = cv2.cvtColor(coin_blur, cv2.COLOR_BGR2GRAY)
plt.figure(), plt.title("Gray Scale"), plt.imshow(coin_gray, cmap="gray"), plt.axis("off");

# Binary Threshold
ret, coin_thres = cv2.threshold(src=coin_gray, thresh=65, maxval=255, type=cv2.THRESH_BINARY)
plt.figure(), plt.title("Binary Threshold"), plt.imshow(coin_thres, cmap="gray"),
plt.axis("off");
``````

First I need to remove connetion between coins. Almostly every coins connetc other self, therefor using Opening from Morphological Operations, I will Open them

``````kernel = np.ones((3,3), np.uint8)

opening = cv2.morphologyEx(coin_thres, cv2.MORPH_OPEN, kernel=kernel, iterations=2)

plt.figure(), plt.title("Opening"), plt.imshow(opening, cmap="gray"), plt.axis("off");
``````

To romevo the connection of between coins I will use Distance Transform.
After that I can see Distance between objects (coins)

``````dist_transform = cv2.distanceTransform(src=opening, distanceType=cv2.DIST_L2, maskSize=5)

plt.figure(), plt.title("Distance Transform"), plt.imshow(dist_transform, cmap="gray"), plt.axis("off");
``````

After finding distance, to find image which is in foreground what it is, I'll minimizing that using Threshold.

``````ret, sure_foreground = cv2.threshold(src=dist_transform, thresh=0.4*np.max(dist_transform), maxval=255, type=0)

plt.figure(), plt.title("Fore Ground"), plt.imshow(sure_foreground, cmap="gray"), plt.axis("off");
``````

To find background what it is, I will enlarging image using Dilate.

``````sure_background = cv2.dilate(src=opening, kernel=kernel, iterations=1) #int

sure_foreground = np.uint8(sure_foreground) # change its format to int
``````

And now, I can Subtrack them eachothers (BackGround - ForeGround) so that, the image can be more understandable. Here is the result of Opened and Dilated image

``````unknown = cv2.subtract(sure_background, sure_foreground)

plt.figure(), plt.title("BackGround - ForeGround = "), plt.imshow(unknown, cmap="gray"), plt.axis("off");
``````

After these steps, I need to find Markers for giving inputs for Watershed algorithm. And now I'll provide Connection between Components.

``````ret, marker = cv2.connectedComponents(sure_foreground)

marker = marker + 1

marker[unknown == 255] = 0 # White area is turned into Black to find island for watershed

plt.figure(), plt.title("Connection"), plt.imshow(marker, cmap="gray"), plt.axis("off");
``````

After that, now I can apply Watershed Algorithm and I can make segmentation

``````marker = cv2.watershed(image=coin, markers=marker)

plt.figure(), plt.title("Watershed"), plt.imshow(marker, cmap="gray"), plt.axis("off");
``````

As a last step, I'll find and Draw Contours around of Coins.

``````contour, hierarchy = cv2.findContours(image=marker.copy(), mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE)

for i in range(len(contour)):

if hierarchy[0][i][3] == -1:
cv2.drawContours(image=coin,contours=contour,contourIdx=i, color=(255,0,0), thickness=3)

plt.figure(figsize=(7,7)), plt.title("After Contour"), plt.imshow(coin, cmap="gray"), plt.axis("off");
``````

You can find the notebook here: https://github.com/ierolsen/Object-Detection-with-OpenCV/blob/main/7-watershed.ipynb

Also other things about Object Detection: https://github.com/ierolsen/Object-Detection-with-OpenCV