图像分割算法实例---分水岭算法

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,

最近因为工作需求,在处理瑕疵图像时对于图像背景、图像前景、图像连通域等许多概念接触较多,使用也较为频繁,在图像分割过程中分水岭算法作为一种将图像比拟为地理环境的一种算法,其分割效果在一定程度上比较好,其主要原理是将图像的像素灰度值看作为不同高度的山峰,整个图像可以看作地球中连绵成片的山脉,因此每个灰度值之间纵越连接,形成山脊,也就是分水岭算法分割的依据,称为分水岭。

在海洋的水逐渐升高过程中,山脊从高到低会被逐渐淹没,图像的像素灰度值也是,在我们从0将灰度值逐渐提高过程中,有些灰度值逐渐会被高于(没过),此时整幅图像就会被分为两个部分,一个是被没过部分的像素,另一个是未被没过的像素,从而实现了不同像素的分割,其原理在图示中表示如下,这张图来自网络,说明已经非常清除,可以从土里中一眼感觉到分水岭算法的精髓。

image.png

说了这么多,下面直接上算法,算法主要是利用分割算法对图像的背景、前景、连通域为依据进行了分割

import cv2
import numpy as np
from matplotlib import pyplot as plt
from skimage import measure, color, io
from skimage import exposure

# 定义滤波核的大小,将滤波核填充为全1
kernel = np.ones((3, 3), np.uint8)
# 定义滤波核,并进行归一化
kernel2 = np.ones((5, 5), np.float)/9
img1 = cv2.imread("image/test.jpg", cv2.IMREAD_COLOR)
# 为了提高处理速度,将图像缩小处理
img1 = cv2.resize(img1, (700, 700))
# 灰度化处理
img = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img = cv2.resize(img, (700, 700))
# 阈值分割
ret2, thresh2 = cv2.threshold(img, 170, 255, cv2.THRESH_BINARY)
# 计算图像的前景
dist_transform = cv2.distanceTransform(thresh2, cv2.DIST_L2, 3)
ret3, sure_fg = cv2.threshold(dist_transform, 0.21 * dist_transform.max(), 255, 0)
# 先腐蚀,后膨胀
sure_fg2 = cv2.erode(thresh2, kernel, iterations=3)
sure_fg2 = cv2.dilate(thresh2, kernel, iterations=3)
sure_fg2 = np.uint8(sure_fg)
sure_fg = sure_fg2
# 直方图均衡化
median = exposure.equalize_hist(img)
median = cv2.normalize(src=median, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
plt.hist(median.flat, bins=100, range=(0, 255))
ret1, thresh = cv2.threshold(median, 210, 255, cv2.THRESH_BINARY)
print(ret1)
sure_fg = cv2.normalize(src=sure_fg, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
thresh = cv2.erode(thresh, kernel, iterations=1)
sure_bg = cv2.bitwise_not(thresh)
sure_fg = cv2.bitwise_and(sure_bg, sure_fg)
sure_fg = cv2.erode(sure_fg, kernel, iterations=3)
unknown = cv2.subtract(sure_bg, sure_fg)
# 连通域计算
ret3, markers = cv2.connectedComponents(sure_fg)
print("连通域数目:", ret3)
markers = markers+1
markers[unknown == 255] = 0
plt.imshow(markers, cmap='jet')
plt.show()
markers = cv2.watershed(img1, markers)
img1[markers == -1] = [255, 0, 255]
img2 = color.label2rgb(markers)
cv2.imshow("src image", img1)
cv2.imshow("Colored grains", img2)
cv2.imshow("Blur image", median)
cv2.imshow("real background", sure_bg)
cv2.imshow("Theroshold image", thresh)
cv2.imshow("Unknown Pixel", unknown)
cv2.imshow("sf", sure_fg)
plt.show()
cv2.waitKey(0)
cv2.destroyAllWindows()
复制代码

算法的分割效果如下

分割使用原图如下

test.jpg

分割结果图如下

image.png

image.png

扫描二维码关注公众号,回复: 14232458 查看本文章

image.png

image.png

image.png

image.png

image.png

通过分割的效果来看,整体分割效果还算可以,但是对于并经复杂的轮廓分割的结果并不是特别理想,直接使用还有较大的误差,但是由于分割特性,对于背景相对复杂的图像,其分割效果还不错,由于本人在做瑕疵检测时得到均为二值图像,因此使用时效果比对背景复杂的彩色图像要好一些。

猜你喜欢

转载自juejin.im/post/7105563683584999431
今日推荐