分水岭概念是以对图像进行三维可视化处理为基础的:其中两个是坐标,另一个是灰度级。基于“地形学”的这种解释,我们考虑三类点:
a.属于局部性最小值的点,也可能存在一个最小值面,该平面内的都是最小值点;
b.当一滴水放在某点的位置上的时候,水一定会下落到一个单一的最小值点; c.当水处在某个点的位置上时,水会等概率地流向不止一个这样的最小值点。
对一个特定的区域最小值,满足条件(b)的点的集合称为这个最小值的“汇水盆地”或“分水岭”。满足条件©的点的集合组成地形表面的峰线,称做“分割线”或
“分水线”。
分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,目前较著名且使用较多的有 2 种算法:自下而上的模拟泛洪的算法;自上而下的模拟降水的算法。
运行代码说明
1.要改变代码中的图片地址(地址不能有中文)
更改
put(path)
函数中的路径put(r'../image/image1.jpg')
2.注意最后的
plt.savefig('1.new.jpg')
是保存plt图像,如果不使用可以注释掉代码依赖包:
matplotlib 3.4.2 numpy 1.20.3 opencv-python 4.1.2.30 imageio 2.9.0 pillow 8.2.0 PyWavelets 1.1.1 scikit-image 0.18.1
# pip安装 pip install matplotlib numpy opencv-python imageio pillow PyWavelets scikit-image
import numpy as np
import cv2
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def put(path):
src = cv2.imread(path)
img = src.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) # Otsu's 二值化
# 消除噪声
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 膨胀
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# 距离变换
dist_transform = cv2.distanceTransform(opening, 1, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
# 获得未知区域获得边界区域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
# 标记
ret, markers1 = cv2.connectedComponents(sure_fg)
# 确保背景是1不是0
markers = markers1 + 1
# 未知区域标记为0
markers[unknown == 255] = 0
markers3 = cv2.watershed(img, markers)
img[markers3 == -1] = [0, 0, 255]
plt.subplot(241), plt.imshow(cv2.cvtColor(src, cv2.COLOR_BGR2RGB)),
plt.title('原图'), plt.axis('off')
plt.subplot(242), plt.imshow(thresh, cmap='gray'),
plt.title('Otsu二值化'), plt.axis('off')
plt.subplot(243), plt.imshow(sure_bg, cmap='gray'),
plt.title('膨胀'), plt.axis('off')
plt.subplot(244), plt.imshow(dist_transform, cmap='gray'),
plt.title('距离变换'), plt.axis('off')
plt.subplot(245), plt.imshow(sure_fg, cmap='gray'),
plt.title('距离变换二值化'), plt.axis('off')
plt.subplot(246), plt.imshow(unknown, cmap='gray'),
plt.title('边界区域'), plt.axis('off')
plt.subplot(247), plt.imshow(np.abs(markers), cmap='jet'),
plt.title('标记区域'), plt.axis('off')
plt.subplot(248), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)),
plt.title('分割图像'), plt.axis('off')
# plt.savefig('3.new-img.jpg')
plt.show()
# 图像处理函数,要传入路径
put(r'../image/img5.jpg')