7

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

1 Answer 1

9

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()
Sign up to request clarification or add additional context in comments.

8 Comments

I got an error in this line >>>>> line 19, in <module> labels = watershed(-distance_map, markers, mask=thresh) <<<<
Maybe you don't have scikit-image or scipy installed. Try pip install scikit-image and pip install scipy
I checked and found these packages installed and found this error also >>>> File "C:\Users\speedTECH\AppData\Local\Programs\Python\Python37-32\lib\site-packages\skimage\morphology\watershed.py", line 83, in _validate_inputs markers = np.asanyarray(markers) * mask ValueError: operands could not be broadcast together with shapes (2,) (2824,5092) <<<
I'm not able to replicate your error, it working fine for me. I'm using scipy v1.3.1, opencv-python v4.1.0.25, and scikit-image v0.15.0
Maybe because I am using python 32 bit on Windows 10 ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.