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

nathancy
  • 42,661
  • 14
  • 115
  • 137
Medo2018
  • 479
  • 1
  • 4
  • 13

1 Answers1

8

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()
nathancy
  • 42,661
  • 14
  • 115
  • 137
  • I got an error in this line >>>>> line 19, in labels = watershed(-distance_map, markers, mask=thresh) <<< – Medo2018 Sep 24 '19 at 16:21
  • Maybe you don't have [scikit-image](https://scikit-image.org/docs/dev/install.html) or [scipy](https://pypi.org/project/scipy/) installed. Try `pip install scikit-image` and `pip install scipy` – nathancy Sep 24 '19 at 20:20
  • 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) << – Medo2018 Sep 25 '19 at 06:44
  • 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` – nathancy Sep 25 '19 at 20:01
  • Maybe because I am using python 32 bit on Windows 10 ? – Medo2018 Sep 26 '19 at 18:51
  • Potentially, I'm using Python 64 bit on Windows 10 – nathancy Sep 26 '19 at 19:42
  • Well it worked with me but I would like to know where is the effective part of the algorithm that will affect the efficiency of this code to detect all soil particles in the image – Medo2018 Sep 27 '19 at 13:34
  • does the `cv2.watershed` function work on a single banded image? I believe from what I have read in the documentation that it is meant to be passed a 3-band image, but I don't see why it shouldn't be able to work on a single band. – Max Duso Mar 17 '23 at 16:01