Python之opencv 分水岭分割算法

分水岭分割算法
分水岭分割算法的定义网上随便百度一下就可以知道了,我就说一下我的理解,有不对的希望大家也可以帮忙指正。
对于分水岭分割,我的理解是,一幅图像是由不同大小的灰度级像素值构成的,可以把不同的大小想象成不同高度的山脉,接着在地表(就是从像素灰度级0开始)向这个山脉地脉注入水,那么当一个山脉与另一个山脉将要融合的线上就是图像的边界,当水注入最高山脉后形成的现象就是整幅图的边界。

cv2.watershed(参数1,参数2)

Python中的分水岭分割算法有两个参数,第一个参数是带分割的图像,且为8位三通道彩色图像,第二个参数的掩码,第二个参数必须是32位单通道的图像。下面是完整代码,在使用分水岭分割算法之前的步骤是为了获取掩码图像

import cv2
import numpy as np
img=cv2.imread(r'D:\Python Code\waterSgmention\water_coins.jpg')
cv2.imshow('img',img)
#将图像转化为灰度图像
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#阈值化处理
ret,thresh=cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
cv2.imshow('thresh',thresh)

硬币原图 二值化图像

#noise removal
#opening operator是先腐蚀后膨胀,可以消除一些细小的边界,消除噪声
kernel=np.ones((3,3),np.uint8)
opening=cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=2)
cv2.imshow('opening',opening)

二值化后由于图像存在一些噪声(即白色的点),可以用形态学的开操作的处理。opening操作可以消除物体之间细小的粘缝,为了展示openin操作的效果,我将内核设置为5*5,并且迭代了5次,其效果如下:

opening

   获得掩码需要知道图像的前景和背景,在这里我的理解是:前景就是有硬币的图像,背景就是除硬币之前的区域。我们要确保我们获得的背景图中不包含前景图的区域,通过腐蚀操作,将硬币的区域放大,那么剩下的就一定是背景区域了,即可以确定背景图
#sure background area
sure_bg=cv2.dilate(opening,kernel,iterations=3)
cv2.imshow('bg',sure_bg)

背景图效果
背景图效果

如上所说,确定前景,就是硬币的区域
距离变化 可用来实现目标细化、骨架提取、形状插值及匹配、粘连物体的分离等。距离变换是针对二值图像的一种变换。在二维空间中,一幅二值图像可以认为仅仅包含目标和背景两种像素,目标的像素值为1,背景的像素值为0;距离变换的结果不是另一幅二值图像,而是一幅灰度级图像,即距离图像,图像中每个像素的灰度值为该像素与距其最近的背景像素间的距离(就是原二值图像中像素值为1的像素点与最近的像素点为0的像素点之间的距离)
由于掩码是一幅二值图像,所以经过距离变化后还需要将图像进行二值化
这样子的结果图像中像素点为1的区域就一定是硬币的位置,即前景图

#finding sure foreground area
dist_transfrom=cv2.distanceTransform(opening,cv2.DIST_L2 ,5)
#cv2.imshow('dist_transfrom',dist_transfrom)
ret,sure_fg=cv2.threshold(dist_transfrom,0.7*dist_transfrom.max(),255,0)

cv2.imshow('sure_fg',sure_fg)

前景图效果
sure_fg

   现在我们已经知道原图像的前景图和背景图了,但是还有一些区域是我们所不知道的就是原图像中硬币与硬币之间相连的那些或者叠加的区域,即边界,通过背景图减去前景图可以大概的获得这些未知的边界
#finding unknow region
sure_fg=np.uint8(sure_fg)
unknow=cv2.subtract(sure_bg,sure_fg) #背景-前景
cv2.imshow('unknow',unknow)

边界

官网上说connectedComponents函数可以使图像中标记背景像素点为0,飞背景像素点从1开始累加分别标记

ret,maker=cv2.connectedComponents(sure_fg)
maker=maker+1
maker[unknow==255]=0

最终使用分水岭分割算法

maker = cv2.watershed(img,maker)
cv2.imshow('maker',maker)
img[maker == -1] = [0,0,255]
cv2.imshow('result',img)

在经过分水岭分割算法后,边界处会标记为-1
这里写图片描述

这里面有几个点我还没有很清楚的理解,等后续理解了再来更新
官网参考文献

  • 12
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
基于分水岭算法的图像分割是一种常用的图像处理技术,可以将图像分割成多个区域,每个区域内的像素具有相似的特征。在 OpenCV 中,可以使用 cv2.watershed() 函数实现基于分水岭算法的图像分割。 下面是一个简单的 Python 示例,演示如何使用基于分水岭算法的图像分割: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('image.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) # 距离变换 dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.1*dist_transform.max(),255,0) # 背景区域 sure_bg = cv2.dilate(opening,kernel,iterations=3) # 不确定区域 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('image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的示例中,首先读取一张图像,并将其转换为灰度图像。然后使用阈值分割算法将图像二值化。接下来,进行形态学操作,以去除图像中的噪声。然后使用距离变换算法计算前景区域,并将其阈值化。接着,使用形态学操作计算背景区域。最后,使用 cv2.connectedComponents() 函数计算不确定区域,并使用标记连通区域的方法生成分水岭算法的输入标记图像。最后,应用 cv2.watershed() 函数进行图像分割,并在窗口中显示结果。 需要注意的是,分水岭算法的结果依赖于输入标记图像的质量,因此需要根据具体情况进行调整,比如阈值分割参数、形态学操作的参数、距离变换的参数等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值