I'm trying to make a program to calculate the size distribution of rock fragments based on images from a conveyor belt. I can only achieve that by image segmentation and labeling. Unfortunately, my results are not satisfactory because the program has a problem with dark spots on rock fragments. These spots are incorrectly recognized as edges of the fragments (e.g in the left top corner program found a lot of small fragments, where in reality this is just one big fragment. Did anyone deal with a problem like that?
What I tried until now:
- Canny edge detector
- thresholding with various parameters
- findContours in opencv
- sharpening / bilateral filtering
- meijering, sato, frangi, hessian ridge detectors from skimage.filters - I'm not sure if I used them in a proper way - maybe someone has more experience with these and know how to find parameters that would fit.
- opening/closing (dilate, erode) with different kernels
- current approach: opening -> finding background area -> finding foreground area -> subtracting background and foreground area -> watershed.
code for the current approach:
import numpy as np
import cv2
from skimage import data, util, filters, color, measure
from skimage.segmentation import watershed, clear_border
import matplotlib.pyplot as plt
from skimage import img_as_ubyte
name = 'cut.png'
img = cv2.imread(name, 0)
img_color_org = cv2.imread(name)
ret, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
kernel2 = np.ones((2, 2), np.uint8)
kernel3 = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(
thresh, cv2.MORPH_OPEN, kernel2, iterations=1)
sure_bg = cv2.dilate(opening, kernel3, iterations=3)
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 3)
ret2, sure_fg = cv2.threshold(
dist_transform, 0.15*dist_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
ret3, markers = cv2.connectedComponents(sure_fg)
markers = markers + 10
markers[unknown == 255] = 0
markers = cv2.watershed(img_color_org, markers)
img_color_org[markers == -1] = [0, 0, 255]
img2 = color.label2rgb(markers, bg_label=0)
cv2.imwrite('img.png', img_color_org)
cv2.waitKey(0)
Image after background subtraction, and before watershed operation
Watershed applied to the original image
hand-made segmentation with desired edges
Original image with better quality
Any help will be greatly appreciated!
