OpenCV:图像分割之分水岭算法

发布于:2025-02-10 ⋅ 阅读:(27) ⋅ 点赞:(0)

目录

1. 什么是分水岭算法?

核心思想

适用场景

2. 分水岭算法的 OpenCV API

3. OpenCV 代码实现(分水岭分割)

3.1 代码流程

3.2 代码实现

4. 适用场景

5. 注意事项

6. 总结


1. 什么是分水岭算法?

分水岭算法(Watershed Algorithm) 是一种基于 拓扑形态学 的图像分割方法,适用于:

  • 粘连目标的分割(如硬币、细胞、种子)。
  • 边界模糊的目标分割(如医学图像、自然场景)。

核心思想

将灰度图像看作“地形图”:

  • 亮度高的区域代表 山峰,亮度低的区域代表 山谷。

在山谷中注入水:

  • 随着水面上升,不同的“水池”会相遇。
  • 相遇处形成“坝” → 这条“坝”就是分割边界。

适用场景

✅ 目标粘连(如 硬币、细胞、果实、种子)。
✅ 目标边界模糊(如 医学图像、叶片分割)。


2. 分水岭算法的 OpenCV API

cv2.watershed(image, markers)
参数 说明
image 输入图像(3 通道 BGR)。
markers 标记矩阵(单通道整数图像,前景/背景分区)。
返回 修改后的markers,其中 -1 代表分割边界。

其它 API:

API 作用
cv2.threshold() 二值化图像(用于前景检测)。
cv2.distanceTransform() 计算距离变换(用于前景提取)。
cv2.connectedComponents() 计算连通区域(用于标记目标)。
cv2.morphologyEx() 形态学操作(去噪、填充区域)。

3. OpenCV 代码实现(分水岭分割)

3.1 代码流程

  1. 图像预处理(灰度化 + 去噪)。
  2. 二值化(确定前景区域)。
  3. 形态学操作(去噪、增强前景)。
  4. 距离变换(计算前景区域的中心)。
  5. 标记前景、背景、未知区域。
  6. 应用分水岭算法,获取分割边界。
  7. 可视化结果。

3.2 代码实现

下面是使用 Python 和 OpenCV 库实现分水岭算法进行图像分割的示例代码:

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像
image = cv2.imread('D:\\resource\\filter\\coins.jpeg')

# 转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 进行高斯模糊以减少噪声
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

# 使用OTSU方法进行二值化
_, thresh = cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 进行形态学开运算以去除小的噪声点
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, cv2.DIST_L2, 5)
_, 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)

# 标记连通区域
_, markers = cv2.connectedComponents(sure_fg)

# 所有标记加1,确保背景标记为1而不是0
markers = markers + 1

# 未知区域标记为0
markers[unknown == 255] = 0

# 使用分水岭算法进行分割
markers = cv2.watershed(image, markers)
image[markers == -1] = [0, 255, 0]

# 显示结果
plt.subplot(121), plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(markers, cmap='jet')
plt.title('Markers'), plt.xticks([]), plt.yticks([])
plt.show()

🔷代码说明:

  • 读取图像并转换为灰度图像:使用cv2.imread读取图像,然后使用cv2.cvtColor将其转换为灰度图像。
  • 高斯模糊和二值化:使用cv2.GaussianBlur进行高斯模糊以减少噪声,然后使用 Otsu's 方法进行二值化。
  • 形态学开运算和膨胀操作:使用cv2.morphologyEx进行形态学开运算以去除小的噪声点,然后使用cv2.dilate进行膨胀操作得到背景区域。
  • 距离变换和前景区域提取:使用cv2.distanceTransform进行距离变换,然后使用cv2.threshold提取前景区域。
  • 找到未知区域:通过背景区域减去前景区域得到未知区域。
  • 标记连通区域:使用cv2.connectedComponents标记连通区域,并将所有标记加 1,确保背景标记为 1 而不是 0。
  • 使用分水岭算法进行分割:使用cv2.watershed进行分割,并将分割边界标记为 - 1。
  • 显示结果:使用matplotlib显示分割后的图像和标记图。

🔷运行结果: 

🔷注意事项:

分水岭算法容易受到噪声的影响,因此在进行分割之前需要进行适当的预处理,如高斯模糊和形态学操作。


4. 适用场景

应用场景 示例
医学影像 细胞分割、病灶检测
工业检测 产品缺陷检测、物体计数
自然场景 叶片分割、果实分割
OCR 预处理 分割手写字符

5. 注意事项

前景必须清晰:

  • 目标和背景 灰度差异明显,否则算法可能失败。

​​​​​​形态学处理:

  • cv2.morphologyEx() 可以 去噪、增强前景。
  • cv2.dilate() 确保背景区域足够大。

代码中 0.7 * dist_transform.max() 是经验值,可能需要调节:

  • 过低会导致前景区域过小,目标可能丢失。
  • 过高会导致分割过多,误分割目标。

适用于粘连目标:

  • 粘连目标 → 分水岭算法更有效(如硬币、细胞)。
  • 单一目标 → 其他方法更合适(如 Canny、K-means)。

6. 总结

分水岭算法是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。

分水岭算法适用于目标粘连、边界模糊的图像。

结合形态学操作、距离变换,可提升分割效果。


网站公告

今日签到

点亮在社区的每一天
去签到