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. Continue reading...