文章目录
- 分水岭算法
- cv2.watershed
- 示例
分水岭算法
任何灰度图像都可以看作是一个地形表面,其中高强度表示山峰,低强度表示山谷。你开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水位的上升,根据附近的山峰(坡度),来自不同山谷的水明显会开始合并,颜色也不同。为了避免这种情况,你要在水融合的地方建造屏障。你继续填满水,建造障碍,直到所有的山峰都在水下。然后你创建的屏障将返回你的分割结果。
但是这种方法会由于图像中的噪声或其他不规则性而产生过度分割的结果。因此OpenCV实现了一个基于标记的分水岭算法,你可以指定哪些是要合并的山谷点,哪些不是。这是一个交互式的图像分割。我们所做的是给我们知道的对象赋予不同的标签。用一种颜色(或强度)标记我们确定为前景或对象的区域,用另一种颜色标记我们确定为背景或非对象的区域,最后用0标记我们不确定的区域。这是我们的标记。然后应用分水岭算法。然后我们的标记将使用我们给出的标签进行更新,对象的边界值将为-1。
cv2.watershed
使用分水岭算法实现基于标记的图像分割
watershed(image, markers) -> markers
- image:8位3通道图像
- markers:标记(输入/输出的32位单通道图像,大小与图像一致)
示例
def watershed_image(image):"""分水岭算法"""# 图像二值化blurred = cv.pyrMeanShiftFiltering(image, 10, 50) # 均值迁移滤波gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY) # 转换成灰度图# cv.imshow("gray", gray)ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU) # 图像二值化# cv.imshow("binary", binary)# 去除噪声kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) # 构造25×25的方形结构元素opening = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel=kernel, iterations=2) # 开操作(需要去除图像中的任何白点噪声),迭代次数2# cv.imshow("noise removal", opening)# 确定背景区域sure_bgsure_bg = cv.dilate(opening, kernel, iterations=3) # 腐蚀,迭代次数3,会去除边界像素cv.imshow("sure_bg", sure_bg)# 寻找前景区域sure_fg""" 距离变换的基本含义是计算一个图像中非零像素点到最近的零像素点的距离,也就是到零像素点的最短距离一个最常见的距离变换算法就是通过连续的腐蚀操作来实现,腐蚀操作的停止条件是所有前景像素都被完全腐蚀。这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心像素点的距离。根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离变换。cv2.distanceTransform(src, distanceType, maskSize)distanceType为距离类型CV_DIST_L1, CV_DIST_L2 , CV_DIST_C;maskSize为距离转换掩码的大小"""dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5) # 距离变换dist_output = cv.normalize(dist_transform, 0, 1.0, cv.NORM_MINMAX) # 矩阵归一化,主要是为了显示出dist_outputcv.imshow("dist_transform", dist_output*50) # dist_output不乘50看不出来ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0) # 图像二值化cv.imshow("sure_fg", sure_fg)# 找到未知的区域unknownsure_fg = np.uint8(sure_fg)unknown = cv.subtract(sure_bg, sure_fg) # 从sure_bg区域中减去sure_fg区域来获得unknowncv.imshow("unknown", unknown)# 类别标记ret, markers1 = cv.connectedComponents(sure_fg)print(ret) # 计算数量,但此时会把图像边框也算进去,因此ret会多1# print(markers1)# 为所有的标记加1,保证背景是0而不是1markers = markers1 + 1# print(markers)# 现在让所有的未知区域为0markers[unknown == 255] = 0# 使用分水岭算法markers3 = cv.watershed(image, markers=markers) # 边界区域将被修改标记为-1image[markers3 == -1] = [0, 0, 255] # 边界区域画红色# print(markers3)cv.imshow("result", image)
结果:
参考链接:
- opencv-python——通过cv2.distanceTransform()函数将距离转换成热力图
- OpenCV学习三十五:distanceTransform 距离变换函数
- OPENCV自学记录(6)——连通域处理函数CV2.CONNECTEDCOMPONENTSWITHSTATS()和CV2.CONNECTEDCOMPONENTS()
- OpenCV3学习(7.2)——图像分割之二(分水岭算法watershed)
- opencv进阶学习笔记14:分水岭算法 实现图像分割
- 图像分割之分水岭算法
- python opencv入门 分水岭算法(29)