本篇博客主要介绍分水岭算法。
任何一副图像都可以看成拓扑平面,灰度值高的区域可以看成是山峰,灰度值低的地方可以看成是山谷,我们向每一个山谷中灌注不同颜色的水,随着水位的上升,不用山谷的水就会相遇汇合,为了防止不同颜色的水汇合,我们需要在水汇合的地方构建堤坝,不停的灌水的同时不停的构建堤坝,知道所有的山峰都被水淹没,我们构建好的堤坝就是对图像的分割,这就是分水岭算法背后的原理。
示例:
示例代码:
# encoding:utf-8
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('../data/water_coins.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 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)
'''
距离变换基本含义是计算一个图像中费像素点到最近的零像素点的距离
也就是到零像素点的最短距离
最常见的距离变换算法就是通过连续的腐蚀操作来实现
腐蚀操作的停止条件是所有前景像素都被完全腐蚀
这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心骨架像素点的距离
根据各个像素点的距离值,设置为不同的灰度值,这样就完成了二值图像的距离变换
'''
distance_transform = cv2.distanceTransform(opening, 1, 5)
ret, sure_fg = cv2.threshold(distance_transform, 0.7 * distance_transform.max(), 255, 0)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg) # 图像相减
cv2.imshow('unknown', unknown)
# 创建标签
ret, markers1 = cv2.connectedComponents(sure_fg)
# 把背景标签为0,其他的使用从1开始的正整数标
markers = markers1 + 1
markers[unknown == 255] = 0
markers3 = cv2.watershed(img, markers)
img[markers3 == -1] = [255, 0, 0]
cv2.imshow('watershed', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
原图:
结果图片: