iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >OpenCV-Python使用分水岭算法实现图像的分割与提取
  • 940
分享到

OpenCV-Python使用分水岭算法实现图像的分割与提取

2024-04-02 19:04:59 940人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录图像分割分水岭算法waterShed函数形态学分割distanceTransfORM函数确定未知区域ConnectedComponents函数实战分水岭算法随着当今世界的发展,计

随着当今世界的发展,计算机视觉技术的应用越来越广泛。伴随着硬件设备的不断升级,构造复杂的计算机视觉应用变得越来越容易了。OpenCV像是一个黑盒,让我们专注于视觉应用的开发,而不必过多的关注基础图象处理的具体细节。

图像分割

了解分水岭算法之前,我们需要了解什么是图像的分割。

在图像的处理过程中,经常需要从图像中将前景对象作为目标图像分割或者提取出来。例如,在视频监控中,观测到的是固定背景下的视频内容,而我们对背景本身并无兴趣,感兴趣的是背景中出现的车辆,行人或者其他对象。我们希望将这些对象从视频中提取出来,而忽略那些没有对象进入背景的视频内容。

分水岭算法

图像分割是图像处理过程中一种非常重要的操作。分水岭算法将图像形象地比喻为地理学上的地形表面,实现图像分割,该算法非常有用。

下面,博主对分水岭算法的相关内容做简单的介绍。(详细可以参考冈萨雷斯的《数字图像处理》一书)

任何一副灰度图像,都可以被看作是地理学上的地形表面,灰度值越高的区域可以被看成是山峰,灰度值越低的区域可以被看成是山谷。

如果我们向每个山谷中灌注不同颜色的水。那么随着水位的不断升高,不同山谷的水就汇聚到一起。在这个过程中,为了防止不同山谷的水交汇,我们需要在水流可能汇合的地方构建堤坝。该过程将图像分为两个不同的集合:集水盆地和分水岭线。我们构建的堤坝就是分水岭线,也即对原始图像的分割。这就是分水岭算法的原理。

不过,一般的图像都存在着噪声,采用分水岭算法时,会经常得到过度分割的结果。为了改善图像分割的效果,人们提出了基于掩摸的改进的分水岭算法。改进的分水岭算法允许用户将它认为是同一个分割区域的部分标注出来。这样,分水岭算法在处理时,就会将标注的部分处理为同一个分割区域。

如果对于该理论不怎么了解,可以使用软件PowerPoint中的“删除背景”功能进行观察配合理解。

waterShed函数

在OpenCV中,可以使用函数cv2.watershed()函数实现分水岭算法。不过,具体实现的过程,还需要借助形态学函数,距离变换函数cv2.distanceTransform(),cv2.connectedComponents()来完成图像分割。

形态学分割

在使用分水岭算法之前,我们需要对图像进行简单的形态学处理。一般情况下,我们都是使用形态学中的开运算,因为开运算是先腐蚀后膨胀的操作,能够去除图像内的噪声。


import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("36.jpg")
k=np.ones((5,5),dtype=np.uint8)
e=cv2.erode(img,k)
result=cv2.subtract(img,e)

plt.subplot(131)
plt.imshow(img, cmap="gray")
plt.axis('off')

plt.subplot(132)
plt.imshow(e, cmap="gray")
plt.axis('off')

plt.subplot(133)
plt.imshow(result, cmap="gray")
plt.axis('off')
plt.show()

回顾一下,我们前面的开运算函数为cv2.erode(),这里我们首先经过开运算去除噪声。然后减法运算cv2.subtract()获取图像边界。运行之后,效果如下:

效果

distanceTransform函数

当图像内的各个子图没有连接时,可以直接使用形态学的腐蚀操作确定前景对象,但是如果图像内的子图连接在一起时,就很难确定前景对象了。这个时候,就需要借助变换函数cv2.distanceTransform()方便地将前景对象提取出来。

cv2.distanceTransform()反应了各个像素点与背景(值为0的像素点)的距离关系。通常情况下:

  • 如果前景对象的中心距离值为0的像素点距离较远,会得到一个较大的值。
  • 如果前景对象的边缘距离值为0的像素点较近,会得到一个较小的值。

下面,我们来使用该函数确定一副图像的前景,并观察效果。


import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("36.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
k = np.ones((5, 5), dtype=np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, k, iterations=2)
distTransform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, fore = cv2.threshold(distTransform, 0.7 * distTransform.max(), 255, 0)

plt.subplot(131)
plt.imshow(img, cmap="gray")
plt.axis('off')

plt.subplot(132)
plt.imshow(distTransform, cmap="gray")
plt.axis('off')

plt.subplot(133)
plt.imshow(fore, cmap="gray")
plt.axis('off')
plt.show()

这里,我们使用cv2.morphologyEx函数进行开运算,同时使用cv2.distanceTransform得到距离图像,最后在通过cv2.threshold对距离图像进行阈值处理,确定前景。运行之后,效果如下:

前景

确定未知区域

通过距离函数,我们获取到了图像的“中心”,也就是“确定前景”。为了方便后续的讲解,我们将确定前景称为F。

图像中有了确定前景F和确定背景B,剩下的区域就是未知区域UN了。这部分区域正是分水岭算法要进一步明确的区域。

针对一副图像0,通过以下关系能够得到未知区域UN:

未知区域UN=图像0-确定背景B-确定前景F

由上述公式变换得到:

未知区域UN=(图像0-确定背景B)-确定前景F

其中(图像0-确定背景B)就是我们开始的减法操作,通过形态学膨胀得到。也只需要将上面的代码添加4行并更改显示的代码内容:


bg=cv2.dilate(opening,k,iterations=3)
fore=np.uint8(fore)
un=cv2.subtract(bg,fore)

plt.subplot(221)
plt.imshow(img, cmap="gray")
plt.axis('off')

plt.subplot(222)
plt.imshow(bg, cmap="gray")
plt.axis('off')

plt.subplot(223)
plt.imshow(fore, cmap="gray")
plt.axis('off')

plt.subplot(224)
plt.imshow(un, cmap="gray")
plt.axis('off')
plt.show()

运行之后,效果如下:

4附图

左上为原图

右上为原图膨胀后得到的图像bg,其背景图像是确定背景B。前景图像是“原始图像0-确定背景B”

左下为确定前景图像fore

右下为未知区域图像UN

ConnectedComponents函数

明确了确定前景后,就可以对确定前景进行标注了。在OpenCV中,它提供了cv2.ConnectedComponents()函数进行标注。

该函数会将背景标注为0,将其他的对象使用从1开始的正整数标注。它只有一个参数8位单通道的待标注图像。

返回值有两个:retval为返回的标注数量,labels为标注的结果图像。

下面,我们来使用该函数进行标注。代码如下(同样更改上面bg下面代码就行):


bg = cv2.dilate(opening, k, iterations=3)
fore = np.uint8(fore)
ret, markets = cv2.connectedComponents(fore)
unknown=cv2.subtract(bg,fore)
markets=markets+1
markets[unknown==255]=0

plt.subplot(131)
plt.imshow(img, cmap="gray")
plt.axis('off')

plt.subplot(132)
plt.imshow(fore, cmap="gray")
plt.axis('off')

plt.subplot(133)
plt.imshow(markets, cmap="gray")
plt.axis('off')
plt.show()

修改上面fore = np.uint8(fore)的代码,并修改输出内容。运行之后,我们会得到原图,前景图像的中心点图像fore以及标注后的结果图像markets。效果如下:

效果图

实战分水岭算法

经过前文的介绍,我们了解了使用分水岭算法进行图像分割的基本步骤:

  • 通过形态学开运算对原始图像0进行去噪
  • 通过腐蚀操作获取“确定背景B”。需要注意,这里得到“原始图像-确定背景”即可
  • 利用距离变换函数对原始图像进行运算,并对其进行阈值处理,得到“确定前景F”
  • 计算未知区域UN(UN=0-B-F)
  • 利用函数cv2.connectedComponents()对原始图像0进行标注
  • 对函数cv2.connectedComponents()的标注结果进行修正
  • 使用分水岭函数完成图像分割

完整代码如下:


import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread("36.jpg")
plt.subplot(121)
plt.imshow(img, cmap="gray")
plt.axis('off')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
k = np.ones((5, 5), dtype=np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, k, iterations=2)
distTransform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, fore = cv2.threshold(distTransform, 0.2 * distTransform.max(), 255, 0)
bg = cv2.dilate(opening, k, iterations=3)
fore = np.uint8(fore)
ret, markets = cv2.connectedComponents(fore)
unknown = cv2.subtract(bg, fore)
markets = markets + 1
markets[unknown == 255] = 0
markets = cv2.watershed(img, markets)
img[markets == -1] = [255, 0, 0]

plt.subplot(122)
plt.imshow(img, cmap="gray")
plt.axis('off')
plt.show()

运行之后,我们就可以得到分割的图像:

参数

当然,参数可以调整,可以看到大致的硬币被完整的分割出来了。

到此这篇关于OpenCV-python使用分水岭算法实现图像的分割与提取的文章就介绍到这了,更多相关OpenCV图像分割与提取内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: OpenCV-Python使用分水岭算法实现图像的分割与提取

本文链接: https://www.lsjlt.com/news/127817.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • OpenCV-Python使用分水岭算法实现图像的分割与提取
    目录图像分割分水岭算法waterShed函数形态学分割distanceTransform函数确定未知区域ConnectedComponents函数实战分水岭算法随着当今世界的发展,计...
    99+
    2022-11-12
  • OpenCV-Python怎么使用分水岭算法实现图像分割与提取功能
    小编给大家分享一下OpenCV-Python怎么使用分水岭算法实现图像分割与提取功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!随着当今世界的发展,计算机视觉技...
    99+
    2023-06-15
  • C++中实现OpenCV图像分割与分水岭算法
    分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水...
    99+
    2022-11-12
  • C++中怎么实现OpenCV图像分割与分水岭算法
    小编给大家分享一下C++中怎么实现OpenCV图像分割与分水岭算法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!分水岭算法是一种图像区域分割法,在分割的过程中,它...
    99+
    2023-06-15
  • OpenCV基于分水岭算法的图像分割怎么实现
    本文小编为大家详细介绍“OpenCV基于分水岭算法的图像分割怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“OpenCV基于分水岭算法的图像分割怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1. ...
    99+
    2023-07-05
  • OpenCV图像分割之分水岭算法与图像金字塔算法详解
    目录前言一、使用分水岭算法分割图像1、cv2.distanceTransform()函数2、cv2.connectedComponents()函数3、cv2.watershed()函...
    99+
    2022-11-12
  • OpenCV实战记录之基于分水岭算法的图像分割
    目录0. 前言1. 分水岭算法2. 分水岭算法直观理解3. 完整代码总结0. 前言 分水岭变换是一种流行的图像处理算法,用于快速将图像分割成同质区域。分水岭变换主要基于以下思想:当图...
    99+
    2023-02-22
    opencv 分水岭算法 opencv图像分割算法 opencv 分水岭算法应用
  • Python+OpenCV实现分水岭分割算法的示例代码
    目录前言1.使用分水岭算法进行分割2.Watershed与random walker分割对比前言 分水岭算法是用于分割的经典算法,在提取图像中粘连或重叠的对象时特别有用,例如下图中的...
    99+
    2022-11-11
  • Python基于均值漂移算法和分水岭算法实现图像分割
    目录一.基于均值漂移算法的图像分割二.基于分水岭算法的图像分割三.总结一.基于均值漂移算法的图像分割 均值漂移(Mean Shfit)算法是一种通用的聚类算法,最早是1975年Fuk...
    99+
    2023-01-11
    Python均值漂移算法 图像分割 Python 分水岭算法 图像分割 Python图像分割
  • python中的opencv 图像分割与提取
    目录图像分割与提取用分水岭算法实现图像分割与提取算法原理相关函数介绍分水岭算法图像分割实例交互式前景提取图像分割与提取 图像中将前景对象作为目标图像分割或者提取出来。对背景本身并无兴...
    99+
    2022-11-11
  • python中的opencv图像分割与提取的方法
    这篇文章主要介绍了python中的opencv图像分割与提取的方法的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python中的opencv图像分割与提取的方法文章都会有所收获,下面我们一起来看看吧。图像分割与...
    99+
    2023-06-30
  • Python实现基于标记的分水岭分割算法
    目录1. 原理2.代码实现2.1 利用OpenCV和c++实现分水岭算法2.2 Python实现分水岭分割(1)2.3 Python实现分水岭分割(2)分水岭技术是一种众所周知的分割...
    99+
    2022-11-11
  • 怎么使用Python第三方opencv库实现图像分割处理
    这篇文章主要介绍了怎么使用Python第三方opencv库实现图像分割处理的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用Python第三方opencv库实现图像分割处理文章都会有所收获,下面我们一起来看...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作