《数字图像处理-OpenCV/Python》第15章:图像分割
本书京东 优惠购书链接 https://item.jd.com/14098452.html
本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html
第15章:图像分割
图像分割是由图像处理到图像分析的关键步骤,是计算机视觉的基础,也是图像理解的重要组成部分。图像分割的基本方法是指基于图像灰度值的不连续性和相似性,根据灰度、彩色、空间纹理和几何形状等特征,把图像划分成若干个具有特殊性质的区域,或把目标从背景中分离出来。
本章内容概要
- 介绍区域生长与分离和超像素区域分割算法。
- 学习分水岭算法,实现图像分割。
- 学习图割分割算法,实现图像分割。
- 学习均值漂移算法,实现目标描述与定位。
- 学习运动图像分割算法,如帧间差分法、背景差分法和密集光流法。
15.3 分水岭算法
分水岭算法是一种图像区域分割算法,以邻近像素间的相似性作为重要特征,从而将空间位置相近且灰度值相近的像素点连接起来,构成一个封闭的轮廓。
分水岭算法是指将像素值视为海拔高度,图像就像一张高低起伏的地形图,每个局部极小值及其影响区域称为集水盆,集水盆的边界则形成分水岭。
算法的实现过程可以理解为洪水淹没的过程:最低点首先被淹没,然后水逐渐淹没整个山谷;水位升高到一定高度就会溢出,于是在溢出位置修建堤坝;不断提高水位,重复上述过程,直到所有的点被淹没。所建立的一系列堤坝就成为分隔各个盆地的分水岭。
分水岭算法的计算过程是一个迭代标注过程,通过寻找集水盆和分水岭对图像进行分割。经典的分水岭算法分为排序过程和淹没过程两个步骤:首先对每个像素的灰度级从低到高排序;然后在从低到高的淹没过程中,对每个局部极小值在对应高度的影响域进行判断及标注。
分水岭算法是基于形态学的图像分割算法,体现了边缘检测、阈值处理和区域提取的概念和思想,往往会产生更稳定的分割结果。
最简单的分水岭算法能基于距离变换,通过像素到最近的零像素点的距离生成标注图像;基于梯度的分水岭算法能通过梯度函数使集水盆只响应想要探测的目标,对微弱边缘有良好的响应,但噪声容易导致过分割;基于标记点(标记符控制)的分水岭算法是主流的分割算法,其思想是利用先验知识来帮助分割。
OpenCV中的函数cv.watershed能实现基于标记点的分水岭算法。
使用函数cv.watershed输入标记图像,图像中每个非零像素代表一个标签,对图像的部分像素做标记,表明它的所属区域是已知的。
函数原型
cv.watershed(image, markers[, ]) → markers
参数说明
- image:输入图像,是8位三通道彩色图像。
- markers:标记图像,是32位单通道图像。
注意问题
- (1) 分水岭算法要求必须在标记图像markers中用索引勾勒出需要分割的区域,每个区域被赋值为1、2、3...等索引序号,对应不同的目标物体。
- (2) 将标记图像markers中未知区域的像素值设置为0,通过分水岭算法确定这些像素属于背景还是前景区域。
- (3) 输出的标记图像markers中,每个像素都被赋值为1、2、3...等索引序号,-1表示区域之间的边界(分水岭)。
OpenCV中的函数cv.distanceTransform能实现距离变换,计算图像中每个像素到最近的零像素点的距离。
【例程1504】基于距离变换的分水岭算法
本例程介绍基于距离变换的分水岭算法的实现方法,通过每个像素到最近的零像素点生成标注图像。
基于距离变换的分水岭算法的主要步骤如下。
(1) 通过阈值分割将灰度图像转换为二值图像,使用开运算消除噪点。
(2) 通过形态学的膨胀运算,生成确定背景区域sureBG。
(3) 通过距离变换,由阈值分割得到高亮区域,生成确定前景区域sureFG。
(4) 对确定前景区域进行连通性分析,即对多个分割目标编号。
(5) 确定前景区域与确定背景区域重合的部分,作为待定区域unknown。
(6) 从连通域标记图像中去除确定背景区域,作为标注图像。
(7) 基于标记图像使用分水岭算法进行分割,得到分割的目标轮廓,标注为-1。
python
# 【1504】基于距离变换的分水岭算法
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
if __name__ == '__main__':
img = cv.imread("../images/Fig0301.png", flags=1) # 彩色图像(BGR)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 灰度图像
# 阈值分割,将灰度图像分为黑白二值图像
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)
# 形态学操作,生成确定背景区域 sureBG
kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) # 生成 3×3 结构元
opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=2) # 开运算,消除噪点
sureBG = cv.dilate(opening, kernel, iterations=3) # 膨胀操作,生成确定背景区域
# 距离变换,生成确定前景区域 sureFG
distance = cv.distanceTransform(opening, cv.DIST_L2, 5) # DIST_L2: 3/5
_, sureFG = cv.threshold(distance, 0.1 * distance.max(), 255, cv.THRESH_BINARY) # 阈值选择 0.1max 效果较好
sureFG = np.uint8(sureFG)
# 连通域处理
ret, component = cv.connectedComponents(sureFG, connectivity=8) # 对连通区域进行标号,序号为 0-N-1
markers = component + 1 # OpenCV 分水岭算法设置标注从 1 开始,而连通域标注从 0 开始
kinds = markers.max() # 标注连通域的数量
maxKind = np.argmax(np.bincount(markers.flatten())) # 出现最多的序号,所占面积最大,选为底色
markersBGR = np.ones_like(img) * 255
for i in range(kinds):
if (i!=maxKind):
colorKind = np.random.randint(0, 255, size=(1, 3))
markersBGR[markers==i] = colorKind
# 去除连通域中的背景区域部分
unknown = cv.subtract(sureBG, sureFG) # 待定区域,前景与背景的重合区域
markers[unknown==255] = 0 # 去掉属于背景的区域 (置零)
# 用分水岭算法标注目标的轮廓
markers = cv.watershed(img, markers) # 分水岭算法,将所有轮廓的像素点标注为 -1
# 把轮廓添加到原始图像上
mask = np.zeros(img.shape[:2], np.uint8)
mask[markers==-1] = 255
mask = cv.dilate(mask, kernel=np.ones((3,3))) # 轮廓膨胀,使显示更明显
imgWatershed = img.copy()
imgWatershed[mask==255] = [255, 0, 0] # 将分水岭算法标注的轮廓点设为蓝色
plt.figure(figsize=(9, 6))
plt.subplot(231), plt.axis('off'), plt.title("1. Original")
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.subplot(232), plt.axis('off'), plt.title("2. Gray image")
plt.imshow(gray, 'gray')
plt.subplot(233), plt.axis('off'), plt.title("3. Sure background")
plt.imshow(sureBG, 'gray') # 确定背景
plt.subplot(234), plt.axis('off'), plt.title("4. Sure frontground")
plt.imshow(sureFG, 'gray') # 确定前景
plt.subplot(235), plt.axis('off'), plt.title("5. Markers")
plt.imshow(cv.cvtColor(markersBGR, cv.COLOR_BGR2RGB))
plt.subplot(236), plt.axis('off'), plt.title("6. Watershed")
plt.imshow(cv.cvtColor(imgWatershed, cv.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()
图15-4 基于距离变换的分水岭算法
程序说明:
(1) 运行结果,基于距离变换的分水岭算法如图15-4所示。图15-4(1)所示为原始图像,图15-4(2)所示为图15-4(1)的灰度图。
(2) 图15-4(3)所示为确定背景,图中的黑色区域为确定背景区域,由阈值分割和形态学处理得到。图15-4(4)所示为确定前景,图中的白色区域为确定前景区域,由距离变换和阈值处理得到。
(3) 图15-4(5)所示为由分水岭算法得到的标记图像,图15-4(6)所示为把标记的轮廓添加到图15-4(1)上的图像。其中,轮廓膨胀并非必要步骤,只是为了使图像中的轮廓显示更醒目。
【例程1505】基于轮廓标记的分水岭算法
基于轮廓标记的分水岭算法的思想是利用先验知识帮助分割。本例程先用梯度算子进行边缘检测,然后通过查找图像轮廓,生成标记图像来引导分割。
基于轮廓标记的分水岭算法的步骤如下。
(1) 对图像进行梯度处理,以获得梯度图像。
(2) 查找梯度图像和绘制图像轮廓。
(3) 基于图像轮廓生成标记图像。
(4) 基于标记图像使用分水岭算法进行分割,得到各个分割目标的轮廓。
版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/139433259)
Copyright 2024 youcans, XUPT
Crated:2024-06-04
《数字图像处理-OpenCV/Python》 独家连载专栏 : https://blog.csdn.net/youcans/category_12418787.html