My topic is to determine sizes of rocks / stones with image processing and I need help with edge or contour detection (image segmentation) for these rock pictures. After contour detection, I will calculate sizes of the rocks easily (I found some python code that is working enough for me).
After my researches in the literature, I think, the best edge detection algorithm is to use watershed segmentation in my work, but if you advise another method, I can work with it.
At the end of my calculations, I must have the following results, indicating lines after segmentations:
Edge Detection Example 1:
Edge Detection Example 2:
Edge Detection Example 3:
After my trials in python, I am finding the following results:
My Calculation Example 1:
My Calculation Example 2:
My Calculation Example 3:
My Calculation Example 4:
My Calculation Example 5:
If you look at my results, my results are shown not good in all examples. I change image brightness, image gamma, filtering parameters, watershed parameters, however, not of them worked correctly for my ideal solution. I am new in image processing and python and if I make a mistake, can you say any idea for that?
My code is the following:
import cv2
import numpy as np
from IPython.display import Image, display
from matplotlib import pyplot as plt
from skimage import io, img_as_float, color, measure, img_as_ubyte
from skimage.segmentation import clear_border
from skimage.restoration import (denoise_tv_chambolle,denoise_bilateral,denoise_wavelet,estimate_sigma)
from PIL import Image
from PIL import ImageEnhance
path = 'OrijinalKaya5.jpg'
#BRIGHTNESS SETTING
image=Image.open(path)
enhancer=ImageEnhance.Brightness(image)
brightness_factor=**1.3**
brightened_image=enhancer.enhance(brightness_factor)
brightened_image.save('Brightened.jpg')
brightened_img=cv2.imread('Brightened.jpg')
#GAMMA SETTING
gamma=**1.45**
invGamma = 1.0 / gamma
table = np.array([((i / 255.0) ** invGamma) * 255
for i in np.arange(0, 256)]).astype("uint8")
gamma_img=cv2.LUT(brightened_img, table)
cv2.imwrite('Gamma.jpg',gamma_img)
path='Gamma.jpg'
img_ori = img_as_float(io.imread(path))
# Bilateral Filter
#denoise = denoise_bilateral(img_ori, sigma_color=**0.03**, sigma_spatial=**0.9**, channel_axis=-1)
# Total Variation Filter
denoise = denoise_tv_chambolle(img_ori, weight=**0.01**, channel_axis=-1)
# Wavelet Denoising
#denoise = denoise_wavelet(img_ori, channel_axis=-1, rescale_sigma=True)
# Wavelet Denoising in YCbCr Colorspace
#denoise = denoise_wavelet(img_ori, channel_axis=-1, convert2ycbcr=True, rescale_sigma=True)
denoise_img_ubyte = img_as_ubyte(denoise)
# turn into gray scale
gray = denoise_img_ubyte.astype("uint8")
gray=cv2.cvtColor(gray, cv2.COLOR_BGR2GRAY)
# tresholding
ret, bin_img = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# smoothing the image
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
#kernel = np.ones((**5,5**), np.uint8)
#bin_img = cv2.morphologyEx(bin_img, cv2.MORPH_CLOSE, kernel, iterations=**3**)
bin_img = cv2.morphologyEx(bin_img, cv2.MORPH_OPEN, kernel, iterations=**2**)
# removal of the objects that touch the edge of the image
bin_img = clear_border(bin_img)
# sure background area
sure_bg = cv2.dilate(bin_img, kernel, iterations=**30**)
# Distance transform
dist = cv2.distanceTransform(bin_img, **cv2.DIST_L2**, 3)
# Make the distance transform normal.
dist = cv2.normalize(dist, None, 0, 1.0, cv2.NORM_MINMAX)
# foreground area
ret, sure_fg = cv2.threshold(dist, **0.15** * dist.max(), 255, cv2.THRESH_BINARY)
sure_fg = sure_fg.astype(np.uint8)
# unknown area
unknown = cv2.subtract(sure_bg, sure_fg)
# Marker labelling sure foreground
ret, markers = cv2.connectedComponents(sure_fg)
markers += 255
markers[unknown == 255] = 0
# watershed Algorithm
gray = cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB)
markers = cv2.watershed(gray, markers)
# drawing contours from color marks
labels = np.unique(markers)
coins = []
for label in labels[3:]:
target = np.where(markers == label, 255, 0).astype(np.uint8)
contours, hierarchy = cv2.findContours(target, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
coins.append(contours[0])
#img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.drawContours(img_ori, coins, -1, color=(0, 255, 0), thickness=2)
img2 = color.label2rgb(markers, bg_label=255)
img2[img2 == 0] = 0
# display results
fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(8, 8), sharex=True, sharey=True)
ax = axes.ravel()
ax[0].imshow(gamma_img, cmap=plt.cm.gray)
ax[0].set_title("Original")
ax[1].imshow(img, cmap=plt.cm.nipy_spectral)
ax[1].set_title("Contours")
ax[2].imshow(img2, cmap=plt.cm.nipy_spectral)
ax[2].set_title("Labels")
for a in ax:
a.axis('off')
fig.tight_layout()
plt.show()
I indicated the parameters that I am changing as bold.
Thank you for your interest.