I am working on an image processing task using opencv python where I need to segment individual rice grains from an image. The challenge is that many grains are overlapping with each other.
I tried watershed algorithm but this is the best result I’ve got so far.
Still there are grains whose boundaries are not detected properly.
I have also tried different edge detection methods like Canny, Sobel, Laplacian, etc and also morphological operations like erosion, dilation, opening and closing. But none of it seems to give a complete solution.
So, I would appreciate any suggestions or techniques that might perform better in these scenario.
Given below is the code I used to perform watershed algorithm.
import cv2
import numpy as np
image = cv2.imread('images/155.png')
#extract the grains from the blue background
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower_blue = np.array([110, 50, 50])
upper_blue = np.array([130, 255, 255])
mask_blue = cv2.inRange(hsv, lower_blue, upper_blue)
mask_grains = cv2.bitwise_not(mask_blue)
# Morphological processing
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
mask_grains = cv2.morphologyEx(mask_grains, cv2.MORPH_OPEN, kernel, iterations=1)
# Distance transform
sure_bg = cv2.dilate(mask_grains, kernel, iterations=3)
dist_transform = cv2.distanceTransform(mask_grains, cv2.DIST_L2, 5)
_, sure_fg = cv2.threshold(dist_transform, 0.3 * dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
sure_fg = cv2.dilate(sure_fg, kernel, iterations=1)
sure_fg = cv2.morphologyEx(sure_fg, cv2.MORPH_OPEN, kernel, iterations=2)
unknown = cv2.subtract(sure_bg, sure_fg)
# Connected components and watershed
num_markers, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown == 255] = 0
markers = cv2.watershed(image, markers)
image[markers == -1] = [0, 0, 255] # Mark watershed boundaries
# Save segmented image
segmented_img = image.copy()
cv2.imshow('segment',segmented_img)
cv2.waitKey(0)
cv2.destroyAllWindows()