一 分水岭算法
基于任何灰度图像都可以视为地形表面,其中高强度表示山峰和山丘,而低强度表示山谷。首先,开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水位的上升,根据附近的山峰(梯度),来自不同山谷的水,显然具有不同的颜色,将开始合并。为了避免这种情况,我们需要在水汇合的位置建造水坝或者屏障。如果继续注水和建造屏障的工作,直到所有的山峰都在水下。然后,之前创建的屏障会提供细分的结果。这就是分水岭背后的“哲学”。
①首先,找到前景的近似估计值。可以使用 Otsu 的二值化操作实现。
注意:靠近物体中心的区域是前景,而远离物体的区域是背景。不确定的唯一区域是硬币的边界区域。
③通过膨胀操作获取“确定的背景区域Background region“。
④利用距离变换函数cv2.distanceTransform()对图像进行处理,并对其结果进行阈值分割,得到”确定前景区域Front reign“。
⑤获取未知的区域UN。UN =img – Background region – Front reign。
⑥利用cv.connectedComponents()实现图像的标注工作和对标注结果进行修正。
⑦使用分水岭分割函数cv.watershed()完成对图像的分割。
二 利用OpenCV实现分水岭算法的过程
img = cv2.imread(img_path)
im = img.copy()
gray = cv2.cvtColor(im, 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)
④确定的前景区域。
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 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)
⑥利用cv.connectedComponents()实现图像的标注,并且对标注结果进行修正。
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0
⑦使用分水岭分割函数cv.watershed()完成对目标的分割处理。
markers = cv2.watershed(im, markers)
# The boundary region will be marked with -1.
三 实践
import numpy as np
import cv2
import matplotlib.pyplot as plt
def dealImg(img):
b, g, r = cv2.split(img)
img_rgb = cv2.merge([r, g, b])
return img_rgb
def dealImageResult(img_path):
img = cv2.imread(img_path)
im = img.copy()
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# noise removal
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# sure background area
sure_bg = cv2.dilate(opening, kernel, iterations=3)
# sure foreground area
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 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)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0
markers = cv2.watershed(im, markers)
# The boundary region will be marked with -1.
im[markers == -1] = [255, 255, 0]
fig = plt.figure(figsize=(10, 10))
img = dealImg(img)
im = dealImg(im)
titles = ["im", " OTSU", "open", "sure_bg", "sure_fg", "unknown", "result_im"]
images = [img, thresh, opening, sure_bg, sure_fg, unknown, im]
for i in range(7):
plt.subplot(2, 4, i + 1), plt.imshow(images[i], "gray")
plt.title("{}".format(titles[i]), fontsize=20, ha='center')
plt.xticks([]), plt.yticks([])
#plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0.3, hspace=0)
# plt.tight_layout()
plt.show()
fig.savefig('test_results.jpg', bbox_inches='tight')
if __name__ == '__main__':
dealImageResult("test.jpg")
pass
从上图中可以看出,对于某些硬币,它们接触的区域可以被正确分割开,而对于某些硬币,则没有分割开。
前文回顾
入门篇目录
实践篇目录
数字图像处理(实践篇)一 将图像中的指定目标用bBox框起来吧!
数字图像处理(实践篇)四 图像拼接-基于SIFT特征点和RANSAC方法
原文地址:https://blog.csdn.net/wss794/article/details/134738277
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_23454.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!