1 原理

任何一副灰度图像都可以被看成拓扑平面,灰度值高的区域可以被看成是山峰,灰度值低的区域可以被看成是山谷。我们向每一个山谷中灌不同颜色的水。随着水的位的升高,不同山谷的水就会相遇汇合,为了防止不同山谷的水汇合,我们需要在水汇合的地方构建起堤坝。不停的灌水,不停的构建堤坝直到所有的山峰都被水淹没。我们构建好的堤坝就是对图像的分割。这就是分水岭算法的背后思想。

但是这种方法通常都会得到过度分割的结果,这是由噪声或者图像中其他不规律的因素造成的。为了减少这种影响OpenCV 采用了基于掩模的分水岭算法,在这种算法中我们要设置那些山谷点会汇合,那些不会。这是一种交互式的图像分割。我们要做的就是给我们已知的对象打上不同的标签。如果某个区域肯定是前景或对象,就使用某个颜色(或灰度值)标签标记它。如果某个区域肯定不是对象而是背景就使用另外一个颜色标签标记。而剩下的不能确定是前景还是背景的区域就用 0 标记。这就是我们的标签。然后实施分水岭算法。每一次灌水,我们的标签就会被更新,当两个不同颜色的标签相遇时就构建堤坝,直到将所有山峰淹没,最后我们得到的边界对象(堤坝)的值为 -1。

2 代码

import cv2
import numpy as np
import matplotlib.pyplot as pltimg = cv2.imread('coin.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 大津阈值分割并将前后景颜色反转
ret,thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
plt.imshow(thresh,cmap='gray')
plt.show()

现在我们要去除图像中的所有的白噪声。这就需要使用形态学中的开运算。为了去除对象上小的空洞我们需要使用形态学闭运算。所以我们现在知道靠近对象中心的区域肯定是前景,而远离对象中心的区域肯定是背景。而不能确定的区域就是硬币之间的边界。

所以我们要提取肯定是硬币的区域。腐蚀操作可以去除边缘像素。剩下就可以肯定是硬币了。当硬币之间没有接触时,这种操作是有效的。但是由于硬币之间是相互接触的,我们就有了另外一个更好的选择:距离变换再加上合适的阈值。接下来我们要找到肯定不是硬币的区域。这是就需要进行膨胀操作了。膨胀可以将对象的边界延伸到背景中去。这样由于边界区域被去处理,我们就可以知道那些区域肯定是前景,那些肯定是背景。如下图所示。

# 得到前后景
kernel = np.ones((3, 3), dtype=np.uint8)
# 开运算去除白噪声
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 膨胀操作得到背景
sure_bg = cv2.dilate(opening, kernel, iterations=3)# Finding sure foreground area
# 距离变换的基本含义是计算一个图像中非零像素点到最近的零像素点的距离,也就是到零像素点的最短距离
# 其最常见的距离变换算法就是通过连续的腐蚀操作来实现,腐蚀操作的停止条件是所有前景像素都被完全
# 腐蚀。这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心骨架像素点的
# 距离。根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离变换
# cv2.distanceTransform(src, distanceType, maskSize)
# 第二个参数 0,1,2 分别表示 CV_DIST_L1, CV_DIST_L2 , CV_DIST_C
dist_transform = cv2.distanceTransform(opening, 1, 5)
print(np.unique(dist_transform))
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)plt.subplot(141), plt.imshow(sure_bg, cmap='gray')
plt.title('bg'), plt.xticks([]), plt.yticks([])
plt.subplot(142), plt.imshow(sure_fg, cmap='gray')
plt.title('fg'), plt.xticks([]), plt.yticks([])
plt.subplot(143), plt.imshow(dist_transform, cmap='gray')
plt.title('dist_transfrom'), plt.xticks([]), plt.yticks([])
plt.subplot(144), plt.imshow(unknown, cmap='gray')
plt.title('unknown'), plt.xticks([]), plt.yticks([])plt.show()

[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35.]

现在知道了那些是背景那些是硬币了。那我们就可以创建标签(一个与原图像大小相同,数据类型为 in32 的数组),并标记其中的区域了。对我们已经确定分类的区域(无论是前景还是背景)使用不同的正整数标记,对我们不确定的区域使用 0 标记。我们可以使用函数cv2.connectedComponents()来做这件事。它会把将背景标记为 0,其他的对象使用从 1 开始的正整数标记。

但是,我们知道如果背景标记为 0,那分水岭算法就会把它当成未知区域了。所以我们想使用不同的整数标记它们。而对不确定的区域(函数cv2.connectedComponents 输出的结果中使用 unknown 定义未知区域)标记为 0。

ret, markers1 = cv2.connectedComponents(sure_fg)
markers = markers1 + 1
markers[unknown == 255] = 0
print (np.unique(markers))
plt.imshow(markers,cmap='jet')
plt.title('markers'),plt.xticks([]),plt.yticks([])
plt.show()

[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25]

结果使用 JET 颜色地图表示。深蓝色区域为未知区域。肯定是硬币的区域使用不同的颜色标记。其余区域就是用浅蓝色标记的背景了。

markers3 = cv2.watershed(img, markers)
img[markers3 == -1] = [255, 0, 0]plt.subplot(121), plt.imshow(markers3, cmap='jet')
plt.title('mark'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img)
plt.title('res'), plt.xticks([]), plt.yticks([])plt.show()

现在标签准备好了。到最后一步:实施分水岭算法了。标签图像将会被修改,边界区域的标记将变为 -1.

OpenCV-Python官方教程-20-分水岭算法图像分割相关推荐

  1. OpenCV与图像处理学习十一——分水岭算法(含代码)

    OpenCV与图像处理学习十一--分水岭算法(含代码) 一.分水岭算法概要 二.分水岭算法步骤 三.代码应用 一.分水岭算法概要 任意的灰度图像可以被看做是地质学表面,高亮度的地方是山峰,低亮度的地方 ...

  2. OpenCV学习(二十) :分水岭算法:watershed()

    OpenCV学习(二十) :分水岭算法:watershed() 参考博客: OpenCV-分水岭算法 图像处理--分水岭算法 OpenCV学习(7) 分水岭算法(1) Opencv分水岭算法--wat ...

  3. Python官方教程.pdf

    人生苦短,快学Python! 之前总有人询问有没有Python的学习资料? 这次废了九牛二虎之力,为大家找到了几个最适合小白的Python的学习资料!容易入门,又全面,太好用了. 1. Python官 ...

  4. python官网 中文版-python .. 官方教程中文版.pdf

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbspPython python .. 官方教程中文版.pdf105页 ...

  5. Python OpenCV学习笔记之:分水岭算法分割图像

    为什么80%的码农都做不了架构师?>>>    # -*- coding: utf-8 -*- """ 图像分水岭分割图像 分水岭算法可以参考:http ...

  6. 使用OpenCV和C++实现的分水岭算法(Watershed)

    分水岭算法(watershed)是一种比较基本的数学形态学分割算法,其基本思想是将灰度图像转换为梯度图像,将梯度值看作高低起伏的山岭,将局部极小值及其邻域看作一个"集水盆".设想一 ...

  7. PYTHON官方教程:Python3.11中文版文档

    Python 每年都会发布新版本,上半年是功能锁定的测试版,年底是最终版本. Python 3.11 的特性集刚刚定稿,测试版本已经发布,开发人员在非生产代码上可以尝试使用这个最新版本,验证它能否在你 ...

  8. 基于matlab分水岭算法图像分割--解决凹凸性的小白DIY方法

    分水岭算法是一种图像区域分割法,分割的过程中将图片转化为灰度图,然后我会将灰度值看作是海拔,然后向较低点注水,这种基于地形学的解释.大佬链接:https://blog.csdn.net/TIQCmat ...

  9. 毛星云Opencv之8.5.2分水岭算法

    #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #i ...

  10. OpenCV - 分水岭算法图像分割(Python实现)

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

最新文章

  1. Django模板系统和admin模块
  2. 大型软件公司.Net面试题(一)
  3. python 版本比较函数 LooseVersion StrictVersion
  4. ANSYS——分析实例,平面对称问题
  5. python+OpenCV图像处理(九)图像金字塔
  6. CTF-Bugku逆向题Android方法归纳
  7. mysql负责均衡读写分离_MySQL读写分离之负载均衡
  8. 什么时候使用resulttype_柳州站东广场到底什么时候可以使用?
  9. ffmpeg 中添加264支持
  10. 1087 1 10 100 1000
  11. 全球资产管理平台提供商:Charles River Development 应用
  12. 服务器与服务器之前文件传输,客户端与服务器的文件传输
  13. 掌握Thinkphp3.2.0----标签库
  14. 远程重启h3c路由器_H3C路由器远程登陆命令 -192.168.0.1 路由器怎么设置|192.168.1.1登陆|路由器设置密码-路由器网...
  15. 用matlab绘制幅相特性曲线(Nyquist图)
  16. setImageBitmap 图片太大部分机型不显示
  17. 最强解决网页复制文字等问题
  18. ​自动驾驶什么时候才会凉凉,估计还要多久?
  19. 云+未来峰会安全专场总结:智慧安全护航企业数字化转型
  20. 网吧服务器点歌系统,和朋友在网吧五黑,看到网吧有点歌系统,就点了一首……...

热门文章

  1. 集成融云RongCloud视频通话功能PC端
  2. 算法珠玑算法总结(转)
  3. Linux进程间通信——管道通信详解
  4. 微信防撤回python_python实现微信防撤回神器
  5. 车性能测试软件是什么,3DMark制造商推首款汽车性能测试软件
  6. html b5纸尺寸,b5纸尺寸大小(b5纸宽高尺寸是多少)
  7. 阿里云云盾证书是什么?云盾证书有什么作用?
  8. AARRR模型——变现:终极目标(下)
  9. 用python画一朵鲜艳欲滴的红玫瑰
  10. 一切的闹闹哄哄,只是他在水帘洞躲避风沙那晚做的一个梦