本次我们来看图像分割,同样也是OpenCV中较为重要的一个部分。图像分割是按照一定的原则,将一幅图像分为若干个互不相交的小局域的过程,它是图像处理中最为基础的研究领域之一。目前有很多图像分割方法,其中分水岭算法是一种基于区域的图像分割算法,分水岭算法因实现方便,已经在医疗图像,模式识别等领域得到了广泛的应用。

传统分水岭算法基本原理

分水岭比较经典的计算方法是L.Vincent于1991年在PAMI上提出的[1]。传统的分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆地,而集水盆地的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸人水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝如下图所示,即形成分水岭。我们来看传统分水岭算法示意图:

然而基于梯度图像的直接分水岭算法容易导致图像的过分割,产生这一现象的原因主要是由于输入的图像存在过多的极小区域而产生许多小的集水盆地,从而导致分割后的图像不能将图像中有意义的区域表示出来。所以必须对分割结果的相似区域进行合并。

改进的分水岭算法基本原理

因为传统的分水岭分割算法会由于图像中的噪声或其他不规则性而产生过度分割的结果。因此OpenCV实现了一个基于标记的分水岭算法,可以指定哪些是要合并的山谷点,哪些不是。这是一个交互式的图像分割。我们所做的是给我们知道的对象赋予不同的标签。用一种颜色(或强度)标记我们确定为前景或对象的区域,用另一种颜色标记我们确定为背景或非对象的区域,最后用0标记我们不确定的区域。这是我们的标记。然后应用分水岭算法。然后我们的标记将使用我们给出的标签进行更新,对象的边界值将为-1。传统的基于梯度的分水岭算法和改进后基于标记的分水岭算法示意图如下图所示:

从上图可以看出,传统基于梯度的分水岭算法由于局部最小值过多造成分割后的分水岭较多。而基于标记的分水岭算法,水淹过程从预先定义好的标记图像(像素)开始,较好的克服了过度分割的不足。本质上讲,基于标记点的改进算法是利用先验知识来帮助分割的一种方法。因此,改进算法的关键在于如何获得准确的标记图像,即如何将前景物体与背景准确的标记出来。

OpenCV中的图像分割

OpenCV提供了相关的函数API进行分水岭分割操作,我们来看函数原型:

markers=cv.watershed(image, markers)

image:输入8位3通道图像。

markers:标记的输入/输出32位单通道图像(图)。 它的大小应与image相同。

我们使用示例图像:

首先我们使用Otsu的二值化找到硬币的近似估计值:def watershed(img):

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

cv2.imshow('show', thresh)

cv2.waitKey(0)

现在我们需要去除图像中的任何小的白噪声,因此我们要使用形态学开运算,为了去除物体上的小洞,我们要使用形态学闭运算,所以,现在我们可以确定,靠近物体中心的区域是前景,远离物体的区域是背景,只有硬币的边界区域是我们不确定的区域.

我们需要提取出我们确信它们是硬币的区域,腐蚀边界像素,不管剩下的是什么,我们都可以确定它是硬币.如果它们不相互接触还可以继续,如果它们相互接触,另一个好的选择是找到距离变换并应用一个合适的阈值.

为此,我们对结果进行了扩张,扩张将对象边界增加为背景,通过这种方法,我们可以确保背景中的任何区域都是真正的背景,因为边界区域被移除.

剩下的区域是我们不知道的区域,无论是硬币还是背景.分水岭算法应该找到它, 这些区域通常围绕着前景和背景相遇的硬币边界(甚至两个不同的硬币相遇),它可以从sure_bg区域中减去sure_fg区域获得。

来看代码:# 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)

# Finding sure foreground area

dist_transform = cv2.distanceTransform(opening,cv.DIST_L2,5)

ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(),255,0)

# Finding unknown region

sure_fg = np.uint8(sure_fg)

unknown = cv2.subtract(sure_bg,sure_fg)

我们看处理之后的图像,sure_bg:

sure_fg:

看一下处理之后的图像:

现在我们可以确定哪些是硬币的区域,哪些是背景,哪些是背景.因此,我们创建标记(它是一个与原始图像相同大小的数组,但使用int32数据类型)并对其内部的区域进行标记。

cv2.connectedComponents()

将图像的背景标记为0,然后其他对象从1开始标记为整数。

我们知道,如果背景是0,那么分水岭将会被认为是未知的区域, 所以我们用不同的整数来标记它,用0表示由未知定义的未知区域。# 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

标记已经准备好了,现在是最后一步的时候了,应用分水岭,最终代码:def watershed(img):

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)

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)

ret, markers = cv2.connectedComponents(sure_fg)

markers = markers + 1

markers[unknown == 255] = 0

markers = cv2.watershed(img, markers)

img[markers == -1] = [255, 0, 0]

cv2.imshow('img', img)

cv2.waitKey(0)

可以看到,最终结果显示完美分割。

更多openvino技术信息可以入群交流~

OpenVINO技术交流群QQ223824636

python图像分割_OpenCV-Python系列之图像分割与Watershed算法相关推荐

  1. python手势识别_OpenCV+python手势识别框架和实例讲解

    基于OpenCV2.4.8和 python 2.7实现简单的手势识别. 以下为基本步骤 1.去除背景,提取手的轮廓 2. RGB->YUV,同时计算直方图 3.进行形态学滤波,提取感兴趣的区域 ...

  2. ostu阈值分割python实现_opencv python 图像二值化/简单阈值化/大津阈值法

    1简单的阈值化 cv2.threshold第一个参数是源图像,它应该是灰度图像. 第二个参数是用于对像素值进行分类的阈值, 第三个参数是maxVal,它表示如果像素值大于(有时小于)阈值则要给出的值. ...

  3. 图像分割:Python的SLIC超像素分割

    图像分割:Python的SLIC超像素分割 1. 什么是超像素? 2. 为什么超像素在计算机视觉方面有重要的作用? 3. 简单线性迭代聚类(SLIC) 4. 效果图 5. 源码 参考 1. 什么是超像 ...

  4. Python计算机视觉编程学习笔记 九 图像分割

    图像分割 (一)图割(Graph Cut) 1.1 从图像创建图 1.2 用户交互式分割 (二)利用聚类进行分割 (三)变分法 图像分割是将一幅图像分割成有意义区域的过程.区域可以是图像的前景与背景或 ...

  5. 基于模糊C均值聚类(FCM)的图像分割原理+python代码详解

    一.模糊 "模糊":一个元素可以不同程度的属于某几个子集,也就是说元素对于集合的隶属度可以在[0,1]上取连续值. 二.步骤 2.1步骤 翻译一下: S1:初始化参数:加权指数m, ...

  6. 九十八、轻松搞定Python中的Markdown系列

    @Author:Runsen @Date:2020/7/15 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏 ...

  7. 大牛推荐的30本经典编程书籍,从Python到前端全系列。

    注:为了方便阅读与收藏,我们也制作了30本书籍完整清单的Markdown.PDF版以及思维导图版,大家可以在实验楼公众号后台回复关键字"书籍推荐"获取. Python 系列(10本 ...

  8. django 按钮的样式_【实战演练】Python+Django网站开发系列11-成绩查询与成绩录入...

    #本文欢迎转载,转载请注明出处和作者 终于做到最后一步了,选课.删除.已选展示.修改密码等功能都已经完成,剩下查询已选课程的成绩(学生界面)与成绩录入(老师界面).其中成绩查询的页面与之前做过的基本上 ...

  9. python items函数用法,Python中dictionary items()系列函数的用法实例

    本文实例讲述了Python中dictionary items()系列函数的用法,对Python程序设计有很好的参考借鉴价值.具体分析如下: 先来看一个示例: import html # availab ...

  10. 【基于Python+Flask项目部署系列--03】开发测试环境配置-基于Ubuntu16.04

    一.开发测试环境介绍 前提已经部署完[基于Python+Flask项目部署系列--02]Ubuntu16.04服务器安装.建议部署2套环境:开发测试环境+生产环境. 这篇文章主要讲解测试环境如何配置p ...

最新文章

  1. css3 3d变换和动画——回顾
  2. OpenStack在线迁移
  3. 前端学习(3053):vue+element今日头条管理-展示列表分页
  4. 如何理解指向指针的指针?
  5. Java 各种日期/时间 对象转Long时间戳
  6. 数据结构 /ord ;集合;dict()
  7. Unix下oracle备份,Linux下Oracle备份与数据迁移
  8. [CDLinux]安装向导
  9. 基于HoG 的图像特征提取及其分类研究
  10. 局域网搭建git服务器
  11. Html控制舵机,舵机速度控制原理细解
  12. Python三目表达式
  13. ubuntu14.04 安装 GTX 1060 显卡驱动
  14. python wx模块下choice列表框值怎么更新,python的内置模块
  15. E. Fruit Slicer--计算几何+两圆公切线
  16. Unity获取系统信息SystemInfo(CPU、显卡、操作系统等信息)
  17. 华为瘦胖ap互转_华为胖ap转换瘦apv200r006c10spc100指导书
  18. 裸奔系列之博科SAN交换机(3)---SAN交换机初始化
  19. 01 【nodejs简介】
  20. 效率倍增!4 个鲜为人知却功能强大的魔法命令!

热门文章

  1. 工业互联网在现阶段给制造业带来什么?
  2. python中dict.update与__dict__的使用
  3. 全球工业互联网发展实践及启示!
  4. 恋物志(一):网红带货,宠主追捧,2021年宠物智能硬件会火吗?
  5. 用html做垃圾邮件1005无标题,垃圾邮件传播新型FTCode无文件勒索病毒
  6. CKA真题 :2019年12月英文原题和分值
  7. 完整的FreeBSD软件安装方法
  8. 交管12123服务器维护,交管12123服务异常怎么办?交管12123 APP服务异常解决方法...
  9. Ymir初级使用教程
  10. ueditor编辑器对接米秀