文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

python中的opencv图像分割与提取的方法

2023-06-30 17:40

关注

这篇文章主要介绍了python中的opencv图像分割与提取的方法的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python中的opencv图像分割与提取的方法文章都会有所收获,下面我们一起来看看吧。

图像分割与提取

图像中将前景对象作为目标图像分割或者提取出来。对背景本身并无兴趣分水岭算法及GrabCut算法对图像进行分割及提取。

用分水岭算法实现图像分割与提取

分水岭算法将图像形象地比喻为地理学上的地形表面,实现图像分割,该算法非常有效。

算法原理

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

左图是原始图像,右图是其对应的“地形表面”。

python中的opencv图像分割与提取的方法

该过程将图像分成两个不同的集合:集水盆地和分水岭线。我们构建的堤坝就是分水岭线,也即对原始图像的分割。这就是分水岭算法。

python中的opencv图像分割与提取的方法

由于噪声等因素的影响,采用上述基础分水岭算法经常会得到过度分割的结果。过度分割会将图像划分为一个个稠密的独立小块,让分割失去了意义。为了改善图像分割效果,人们提出了基于掩模的改进的分水岭算法。改进的分水岭算法允许用户将他认为是同一个分割区域的部分标注出来(被标注的部分就称为掩模)。分水岭算法在处理时,就会将标注的部分处理为同一个分割区域。

例如:

原始图像,对其做标注处理,其中被标注为深色的三个小色块表示,在使用掩模分水岭算法时,这些部分所包含的颜色都会被分割在同一个区域内。

python中的opencv图像分割与提取的方法

相关函数介绍

在OpenCV中,可以使用函数cv2.watershed()实现分水岭算法。

在具体的实现过程中,还需要借助于形态学函数、距离变换函数cv2.distanceTransform()、cv2.connectedComponents()来完成图像分割。

import cv2import numpy as npimport matplotlib.pyplot as plto=cv2.imread("my.bmp", cv2.IMREAD_UNCHANGED)k=np.ones((5,5), np.uint8)e=cv2.erode(o, k)b=cv2.subtract(o, e)plt.subplot(131)plt.imshow(o)plt.axis('off')plt.subplot(132)plt.imshow(e)plt.axis('off')plt.subplot(133)plt.imshow(b)plt.axis('off')plt.show()

使用形态学操作和减法运算能够获取图像的边界信息。但是,形态学操作仅适用于比较简单的图像。如果图像内的前景对象存在连接的情况,使用形态学操作就无法准确获取各个子图像的边界了。

如果像素点本身的值为0,则这个距离也为0。

通常情况下:

如果对上述计算结果进行阈值化,就可以得到图像内子图的中心、骨架等信息。距离变换函数cv2.distanceTransform()可以用于计算对象的中心,还能细化轮廓、获取图像前景等

函数cv2.distanceTransform()的语法格式为:

dst=cv2.distanceTransform(src, distanceType, maskSize[, dstType]])

python中的opencv图像分割与提取的方法

python中的opencv图像分割与提取的方法

使用距离变换函数cv2.distanceTransform(),计算一幅图像的确定前景

import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('water_coins.jpg')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)ishow=img.copy()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, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)plt.subplot(131)plt.imshow(ishow)plt.axis('off')plt.subplot(132)plt.imshow(dist_transform)plt.axis('off')plt.subplot(133)plt.imshow(fore)plt.axis('off')plt.show()

fore图像中: 比较准确地显示出左图内的“确定前景”。确定前景,通常是指前景对象的中心。之所以认为这些点是确定前景,是因为它们距离背景点的距离足够远,都是距离大于足够大的固定阈值(0.7*dist_transform.max())的点。

为了方便说明将确定背景称为B。

“图像O-确定背景B”,可以通过对图像进行形态学的膨胀操作得到。

标注一幅图像的确定前景、确定背景及未知区域。

import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('water_coins.jpg')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)ishow=img.copy()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)bg = cv2.dilate(opening, kernel, iterations=3)dist = cv2.distanceTransform(opening, cv2.DIST_L2,5)ret, fore = cv2.threshold(dist,0.7*dist.max(),255,0)fore = np.uint8(fore)un = cv2.subtract(bg, fore)plt.subplot(221)plt.imshow(ishow)plt.axis('off')plt.subplot(222)plt.imshow(bg)plt.axis('off')plt.subplot(223)plt.imshow(fore)plt.axis('off')plt.subplot(224)plt.imshow(un)plt.axis('off')plt.show()

python中的opencv图像分割与提取的方法

retval, labels = cv2.connectedComponents( image )

使用函数cv2.connectedComponents()标注一幅图像

import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('water_coins.jpg')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)ishow=img.copy()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, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)fore = np.uint8(fore)ret, markers = cv2.connectedComponents(fore)print(ret)plt.subplot(131)plt.imshow(ishow)plt.axis('off')plt.subplot(132)plt.imshow(fore)plt.axis('off')plt.subplot(133)plt.imshow(markers)plt.axis('off')plt.show()

前景图像的中心点被做了不同的标注(用不同颜色区分)

函数cv2.connectedComponents()在标注图像时,会将背景标注为0,将其他的对象用从1开始的正整数标注。具体的对应关系为:

在分水岭算法中,标注值0代表未知区域。所以,我们要对函数cv2.connectedComponents()标注的结果进行调整:将标注的结果都加上数值1。经过上述处理后,在标注结果中:

为了能够使用分水岭算法,还需要对原始图像内的未知区域进行标注,将已经计算出来的未知区域标注为0即可。

关键代码:

ret, markers = cv2.connectedComponents(fore)markers = markers+1markers[未知区域] = 0

使用函数cv2.connectedComponents()标注一幅图像,并对其进行修正,使未知区域被标注为0

import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('water_coins.jpg')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)ishow=img.copy()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, fore = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)fore = np.uint8(fore)ret, markers1 = cv2.connectedComponents(fore)foreAdv=fore.copy()unknown = cv2.subtract(sure_bg, foreAdv)ret, markers2 = cv2.connectedComponents(foreAdv)markers2 = markers2+1markers2[unknown==255] = 0plt.subplot(121)plt.imshow(markers1)plt.axis('off')plt.subplot(122)plt.imshow(markers2)plt.axis('off')plt.show()

前景都有一个黑色的边缘,这个边缘是被标注的未知区域。

markers = cv2.watershed( image, markers )

cv2.watershed()函数处理之前,必须先用正数大致勾画出图像中的期望分割区域。每一个分割的区域会被标注为1、2、3等。对于尚未确定的区域,需要将它们标注为0。我们可以将标注区域理解为进行分水岭算法分割的“种子”区域。

分水岭算法图像分割实例

使用分水岭算法进行图像分割时,基本的步骤为:

使用分水岭算法对一幅图像进行分割:

import numpy as npimport cv2import matplotlib.pyplot as pltimg = cv2.imread('water_coins.jpg')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)img=cv2.cvtColor(img, cv2.COLOR_BGR2RGB)ishow=img.copy()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+1markers[unknown==255] = 0markers = cv2.watershed(img, markers)img[markers == -1] = [0,255,0] # 边界plt.subplot(121)plt.imshow(ishow)plt.axis('off')plt.subplot(122)plt.imshow(img)plt.axis('off')plt.show()

交互式前景提取

经典的前景提取技术主要使用纹理(颜色)信息,如魔术棒工具,或根据边缘(对比度)信息,如智能剪刀等。在开始提取前景时,先用一个矩形框指定前景区域所在的大致位置范围,然后不断迭代地分割,直到达到最好的效果。经过上述处理后,提取前景的效果可能并不理想,存在前景没有提取出来,或者将背景提取为前景的情况,此时需要用户干预提取过程。

用户在原始图像的副本中(也可以是与原始图像大小相等的任意一幅图像),用白色标注要提取为前景的区域,用黑色标注要作为背景的区域。然后,将标注后的图像作为掩模,让算法继续迭代提取前景从而得到最终结果。

python中的opencv图像分割与提取的方法

GrabCut算法的具体实施过程。

在OpenCV中,实现交互式前景提取的函数是cv2.grabCut(),其语法格式为:

mask, bgdModel, fgdModel =cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode] )

在最后使用模板提取前景时,会将参数值0和2合并为背景(均当作0处理),将参数值1和3合并为前景(均当作1处理)。

在通常情况下,我们可以使用白色笔刷和黑色笔刷在掩模图像上做标记,再通过转换将其中的白色像素设置为0,黑色像素设置为1。

只有当参数mode的值被设置为矩形模式cv2.GC_INIT_WITH_RECT时,参数rect才有意义。

其格式为(x, y, w, h),分别表示区域左上角像素的x轴和y轴坐标以及区域的宽度和高度。

如果前景位于右下方,又不想判断原始图像的大小,对于w 和h可以直接用一个很大的值。

使用掩模模式时,将该值设置为none即可。

mode表示迭代模式。其可能的值与含义如下:

python中的opencv图像分割与提取的方法

RECT 和MASK可以组合使用( 并的关系 )

使用GrabCut算法提取图像的前景

import numpy as npimport cv2import matplotlib.pyplot as plto = cv2.imread('lenacolor.png')orgb=cv2.cvtColor(o, cv2.COLOR_BGR2RGB)mask = np.zeros(o.shape[:2], np.uint8)bgdModel = np.zeros((1,65), np.float64)fgdModel = np.zeros((1,65), np.float64)rect = (50,50,400,500)cv2.grabCut(o, mask, rect, bgdModel, fgdModel,5, cv2.GC_INIT_WITH_RECT)mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')ogc = o*mask2[:, :, np.newaxis]ogc=cv2.cvtColor(ogc, cv2.COLOR_BGR2RGB)plt.subplot(121)plt.imshow(orgb)plt.axis('off')plt.subplot(122)plt.imshow(ogc)plt.axis('off')plt.show()

为了得到完整的前景对象,需要做一些改进。

这里对原始图像进行标注,将需要保留的部分设置为白色,将需要删除的背景设置为黑色。以标记好的图像作为模板,使用函数cv2.grabCut()完成前景的提取。

这个过程主要包含以下步骤:

在GrabCut算法中使用模板提取图像的前景:

import numpy as npimport cv2import matplotlib.pyplot as plto= cv2.imread('lenacolor.png')orgb=cv2.cvtColor(o, cv2.COLOR_BGR2RGB)mask = np.zeros(o.shape[:2], np.uint8)bgd = np.zeros((1,65), np.float64)fgd = np.zeros((1,65), np.float64)rect = (50,50,400,500)cv2.grabCut(o, mask, rect, bgd, fgd,5, cv2.GC_INIT_WITH_RECT)mask2 = cv2.imread('mask.png',0)mask2Show = cv2.imread('mask.png', -1)m2rgb=cv2.cvtColor(mask2Show, cv2.COLOR_BGR2RGB)mask[mask2 == 0] = 0mask[mask2 == 255] = 1mask, bgd, fgd = cv2.grabCut(o, mask, None, bgd, fgd,5, cv2.GC_INIT_WITH_MASK)mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')ogc = o*mask[:, :, np.newaxis]ogc=cv2.cvtColor(ogc, cv2.COLOR_BGR2RGB)plt.subplot(121)plt.imshow(m2rgb)plt.axis('off')plt.subplot(122)plt.imshow(ogc)plt.axis('off')plt.show()

在函数cv2.grabCut()的实际使用中,也可以不使用矩形初始化,直接使用模板模式。构造一个模板图像,其中:

构造完模板后,直接将该模板用于函数cv2.grabCut()处理原始图像,即可完成前景的提取。

一般情况下,自定义模板的步骤为:

在GrabCut算法中直接使用自定义模板提取图像的前景

import numpy as npimport cv2import matplotlib.pyplot as plto= cv2.imread('lenacolor.png')orgb=cv2.cvtColor(o, cv2.COLOR_BGR2RGB)bgd = np.zeros((1,65), np.float64)fgd = np.zeros((1,65), np.float64)mask2 = np.zeros(o.shape[:2], np.uint8)#先将掩模的值全部构造为0(确定背景),在后续步骤中,再根据需要修改其中的部分值mask2[30:512,50:400]=3 #lena头像的可能区域mask2[50:300,150:200]=1 #lena头像的确定区域,如果不设置这个区域,头像的提取不完整cv2.grabCut(o, mask2, None, bgd, fgd,5, cv2.GC_INIT_WITH_MASK)mask2 = np.where((mask2==2)|(mask2==0),0,1).astype('uint8')ogc = o*mask2[:, :, np.newaxis]ogc=cv2.cvtColor(ogc, cv2.COLOR_BGR2RGB)plt.subplot(121)plt.imshow(orgb)plt.axis('off')plt.subplot(122)plt.imshow(ogc)plt.axis('off')plt.show()

对于不同的图像,要构造不同的模板来划分它们的确定前景、确定背景、可能的前景与可能的背景。

关于“python中的opencv图像分割与提取的方法”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“python中的opencv图像分割与提取的方法”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯