Medo2018
Medo2018

Reputation: 489

How to use watershed segmentation in opencv python

I have a problem of how to segment the particles individually in this image using watershed segmentation in python .. My main goal is to remove noise by applying filter medianBlur then applying Canny edge detection method .

[![img = cv2.imread('sands.jpg')
img = cv2.medianBlur(img,7)
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
imo = cv2.Canny(img,140,255)][1]][1]

I would like to enhance the contours resulted from the Canny edge detection function as I use this images in detecting the region properties of particles within the image to estimate area .

enter image description here enter image description here

Upvotes: 7

Views: 14258

Answers (1)

nathancy
nathancy

Reputation: 46680

Here's an approach adapted from this blog post

  • Convert image to grayscale
  • Otsu's threshold to obtain a binary image
  • Compute Euclidean Distance Transform
  • Perform connected component analysis
  • Apply watershed
  • Iterate through label values and extract objects

Here's the results

enter image description here

While iterating through each contour, you can accumulate the total area

1388903.5

import cv2
import numpy as np
from skimage.feature import peak_local_max
from skimage.morphology import watershed
from scipy import ndimage

# Load in image, convert to gray scale, and Otsu's threshold
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

# Compute Euclidean distance from every binary pixel
# to the nearest zero pixel then find peaks
distance_map = ndimage.distance_transform_edt(thresh)
local_max = peak_local_max(distance_map, indices=False, min_distance=20, labels=thresh)

# Perform connected component analysis then apply Watershed
markers = ndimage.label(local_max, structure=np.ones((3, 3)))[0]
labels = watershed(-distance_map, markers, mask=thresh)

# Iterate through unique labels
total_area = 0
for label in np.unique(labels):
    if label == 0:
        continue

    # Create a mask
    mask = np.zeros(gray.shape, dtype="uint8")
    mask[labels == label] = 255

    # Find contours and determine contour area
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    c = max(cnts, key=cv2.contourArea)
    area = cv2.contourArea(c)
    total_area += area
    cv2.drawContours(image, [c], -1, (36,255,12), 4)

print(total_area)
cv2.imshow('image', image)
cv2.waitKey()

Upvotes: 8

Related Questions