You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

岩石Edge (Contour) Detection效果优化求助(基于Watershed Segmentation实现)

岩石Edge (Contour) Detection效果优化求助(基于Watershed Segmentation实现)

大家好,我现在在做一个用图像处理技术检测岩石/石块尺寸的项目——完成轮廓检测后,计算尺寸的Python代码已经能用了,但目前卡在边缘/轮廓检测(图像分割)这一步,急需优化建议。

查了不少文献后,我认为分水岭分割算法是最适合我场景的方案,但如果有其他更合适的方法,我也愿意尝试。

我想要达到的理想分割效果是能清晰勾勒出每块岩石的边缘,类似这样:

  • 理想效果示例1:Edge Detection Example 1
  • 理想效果示例2:Edge Detection Example 2
  • 理想效果示例3:Edge Detection Example 3

但我自己用Python尝试后,得到的结果和理想效果差距很大,要么漏检轮廓,要么存在大量冗余噪声:

  • 我的尝试结果1:My Calculation Example 1
  • 我的尝试结果2:My Calculation Example 2
  • 我的尝试结果3:My Calculation Example 3
  • 我的尝试结果4:My Calculation Example 4
  • 我的尝试结果5:My Calculation Example 5

我已经反复调整过不少参数了(下面代码里我用加粗标出来的就是我试过的可调参数,比如亮度、伽马值、滤波权重、迭代次数等),但不管怎么调,都没法接近理想效果。我是图像处理和Python的新手,有没有大佬能帮我看看代码里的问题,或者给点优化方向的建议?

下面是我使用的Python代码:

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()

备注:内容来源于stack exchange,提问作者Nazım Çimen

火山引擎 最新活动