9

I am searching for an alternative way for segmenting the grains in the following image of soil grains other than watershed segmentation in python as it may mislead the right detection for the grains furthermore , I am working on the edge detection image ( using HED algorithm ) as attached .. I hope to find a better way to segment the grains for further processing as I would like to get the area of each polygon in the image in my project .. Thanks in advance I am asking also about random walker segmentation or any other available method.

enter image description here enter image description here

nathancy
  • 42,661
  • 14
  • 115
  • 137
Medo2018
  • 479
  • 1
  • 4
  • 13
  • Can you take your photos on a different (bright green?) background. That would make your life much easier. – Richard Feb 21 '20 at 20:45
  • @Richard you mean for better edge detection using HED or for better segmentation ?? – Medo2018 Feb 21 '20 at 21:00
  • I think it would help with both. The edges will be easier to detect where they abut the background and you can now easily identify the background and remove any polygons/connected components which consist entirely of the background. (In the current dataset gaps can look like rocks.) – Richard Feb 21 '20 at 21:48

2 Answers2

8

You could try using Connected Components with Stats already implemented as cv2.connectedComponentsWithStats to perform component labeling. Using your binary image as input, here's the false-color image:

enter image description here

The centroid of each object can be found in centroid parameter and other information such as area can be found in the status variable returned from cv2.connectedComponentsWithStats. Here's the image labeled with the area of each polygon. You could filter using a minimum threshold area to only keep larger polygons

enter image description here

Code

import cv2
import numpy as np

# Load image, Gaussian blur, grayscale, Otsu's threshold
image = cv2.imread('2.jpg')
blur = cv2.GaussianBlur(image, (3,3), 0)
gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Perform connected component labeling
n_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(thresh, connectivity=4)

# Create false color image and color background black
colors = np.random.randint(0, 255, size=(n_labels, 3), dtype=np.uint8)
colors[0] = [0, 0, 0]  # for cosmetic reason we want the background black
false_colors = colors[labels]

# Label area of each polygon
false_colors_area = false_colors.copy()
for i, centroid in enumerate(centroids[1:], start=1):
    area = stats[i, 4]
    cv2.putText(false_colors_area, str(area), (int(centroid[0]), int(centroid[1])), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1)

cv2.imshow('thresh', thresh)
cv2.imshow('false_colors', false_colors)
cv2.imshow('false_colors_area', false_colors_area)
cv2.waitKey()
nathancy
  • 42,661
  • 14
  • 115
  • 137
4

I used U-Net for another application, and your case is very similar to what U-Net do. You can find more information here. But generally, it is a convolutional neural network for medical image segmentation.

enter image description here

To start using U-Net, you can find a pre-trained model and apply it on your images and see the result.

aminrd
  • 4,300
  • 4
  • 23
  • 45
  • I am working on it .. I would like to know if random walker segmentation would be applicable in my case ? – Medo2018 Feb 21 '20 at 21:01