关于图像的腐蚀和膨胀,网上介绍的资料非常多,老猿也看了很多,总体来说主要偏向于就使用OpenCV腐蚀和膨胀函数的应用,另外原理介绍的有一小部分,对于初学者有很多的帮助,但如果想知其所以然则总体来说是不够的。
从《OpenCV-Python常用图像运算:加减乘除幂开方对数及位运算:https://blog.csdn.net/LaoYuanPython/article/details/108879397》这篇博文发布到现在,老猿花了较多的时间针对腐蚀和膨胀的原理以及一些比较偏门的问题进行了比较深入的研究,这半个月每晚都花近三个小时在与此相关的研究上。研究期间查阅了大量资料、做了大量测试,还咨询了一个做这方面的老同学,到今天基本上自认为弄清楚了,因此准备就这个方面写3-5篇与网上已有资料有些差异的博文,通过不同角度来阐述相关内容,希望于对这方面细节感兴趣的同仁有所裨益。
本文是老猿关于图像腐蚀与膨胀系列博文之一,该系列包括如下博文:
本文作为老猿介绍图像腐蚀和膨胀处理的首篇文章,主要介绍腐蚀和膨胀的基础概念、腐蚀和膨胀的基本运算过程、OpenCV腐蚀和膨胀函数erode、dilate语法以及简单应用,并提供了老猿觉得有参考价值的一些博文参考。
图像的膨胀(Dilation)和腐蚀(Erosion)是两种基本的形态学运算,主要用来寻找图像中的极大区域和极小区域。其中膨胀类似于“领域扩张”,将图像中的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更大;腐蚀类似于“领域被蚕食”,将图像中的高亮区域或白色部分进行缩减细化,其运行结果图比原图的高亮区域更小。
具体处理时,腐蚀和膨胀都类似于在在《数字图像处理:理解什么是卷积(滤波)、卷积核以及相关参考资料(博文地址:https://blog.csdn.net/LaoYuanPython/article/details/108841819))》介绍的卷积处理。
卷积处理是针对图像对应的矩阵使用一个参考矩阵(卷积核)在图像矩阵中从左到右、从上到下的进行移动,移动到指定位置时,卷积核矩阵与图像矩阵重合范围内的对应元素相乘后得到积矩阵,卷积就是将积矩阵各元素和相加得到的值作为结果图像矩阵锚点对应位置元素的值。
腐蚀则是将对应核矩阵元素不为0位置的图像矩阵中所有元素的最小值作为结果图像矩阵锚点位置的对应元素值,膨胀则是将对应核矩阵元素不为0位置的图像矩阵中所有元素的最大值作为结果图像矩阵锚点位置的对应元素值。
erode(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)#腐蚀函数
dilate(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None)#膨胀函数
腐蚀和膨胀函数的参数相同,返回值都是结果矩阵,相关参数含义如下:
kernel核矩阵可以通过getStructuringElement函数构建,也可以自己单独构建。通过getStructuringElement构建时,可以传入两个参数,对应语法如下:
getStructuringElement(shape, ksize, anchor=None)
cv2.MORPH_CROSS:内置十字形矩阵,矩阵中和锚点同一列或同一行的每个元素都为1,其他元素都为0。下图为一个锚点为(2,3)的5*5内置十字形矩阵:
cv2.MORPH_ELLIPSE:内接椭圆形矩阵,矩阵中为1的元素构成一个椭圆,为该矩阵对应长方形的内接椭圆。下图为一个5*5内接椭圆矩阵:
参数ksize:矩阵的大小,表示宽和高的二元组,(3,3)表示3行3列矩阵,(6,4)表示4行6列的核矩阵
anchor:矩阵锚点,当shape为MORPH_CROSS时需要使用锚点的坐标
返回值:构造的矩阵
在此直接以官网的表格来说明bordType取值的含义:
由于borderType不只是腐蚀和膨胀函数使用,在其他函数中也会使用,所以上述列表中的值并不能都在腐蚀和膨胀函数中使用:
cv2.error: OpenCV(4.3.0) C:\projects\opencv-python\opencv\modules\core\src\copy.cpp:1179: error: (-5:Bad argument) Unknown/unsupported border type in function 'cv::borderInterpolate'
,老猿没有找到c++源代码进行核实,但测试来看应该也是不支持的。另外缺省值为None时,老猿进行验证发现与cv2.BORDER_ISOLATED 值含义值相同,与列表中的说明可以相互印证。
在《数字图像处理:理解什么是卷积(滤波)、卷积核以及相关参考资料》介绍了卷积核对图像处理过程,腐蚀和膨胀时核矩阵在图像矩阵中的移动过程与卷积是一样的,在此不重复介绍。下面通过案例来介绍腐蚀和膨胀结果矩阵的图像元素的生成过程。
锚点为红色标记的缺省中心位置,则针对源矩阵的S11和S88两个位置腐蚀和膨胀计算过程如下:
以核矩阵锚点位置与S11、S88对齐,形成核矩阵和源矩阵的重叠,对源矩阵来说,重叠区域请见上面两个颜色标记区域,其中深蓝色标记位置为核矩阵锚点对齐位置
由于核矩阵全为1,则腐蚀后结果矩阵ED的两个对应位置元素值为:
ED11 = min(S00,S01,S02,S01,S11,S12,S20,S21,S22) = 0
ED88 = min(S77,S78,S79,S87,S88,S89,S97,S98,S99) = 49
膨胀后结果矩阵DD的两个对应位置元素值为:
DD11 = max(S00,S01,S02,S01,S11,S12,S20,S21,S22) = 4
DD88 = max(S77,S78,S79,S87,S88,S89,S97,S98,S99) = 81
import cv2,sys
import numpy as np
img = np.zeros((10, 10),np.uint8)
for row in range(10):
for col in range(10):
img[row,col] = row*col
kernalInt = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
imgErode = cv2.erode(img, kernalInt, borderType=cv2.BORDER_CONSTANT, borderValue=0)
imgDilate = cv2.dilate(img, kernalInt, borderType=cv2.BORDER_CONSTANT, borderValue=0)
本案例和案例1的区别主要体现在两方面:
图像源矩阵案例1相同,核矩阵调整为了十字形,锚点为(0,0),还是以源矩阵的S11和S88为例,由于核的锚点与S88对齐时,核矩阵范围超出了源矩阵范围,在此采用扩充边界模式(扩充边界值固定为0),此时两个位置与核矩阵的重叠范围为下图浅蓝色标记区域:
针对源矩阵的S11和S88两个位置腐蚀和膨胀计算过程如下:
以核矩阵锚点位置与S11、S88对齐,形成核矩阵和源矩阵的重叠,对源矩阵来说,重叠区域请见上面两个颜色标记区域,其中深蓝色标记位置为核矩阵锚点对齐位置
取重叠区域核矩阵为1的源矩阵元素的最小值,则腐蚀后结果矩阵ED的两个对应位置元素值为:
ED11 = min(S12,S22,S32,S21,S23) = 2
ED88 = min(S89,S99,Sa9,S98,S9a) = 0
膨胀后结果矩阵DD的两个对应位置元素值为:
DD11 = max(S12,S22,S32,S21,S23) = 6
DD88 = max(S89,S99,Sa9,S98,S9a) = 81
img = np.zeros((10, 10),np.uint8)
for row in range(10):
for col in range(10):
img[row,col] = row*col
kernalInt = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
imgErode = cv2.erode(img, kernalInt, anchor=(0,0),borderType=cv2.BORDER_CONSTANT, borderValue=0)
imgDilate = cv2.dilate(img, kernalInt, anchor=(0,0), borderType=cv2.BORDER_CONSTANT, borderValue=0)
下面是老猿博文中与形态变换相关的博文列表:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!
小技巧: 可以通过点击博文下面的一键三连按钮实现对相关文章的点赞、收藏和对博客的关注,谢谢!
更多OpenCV-Python的介绍请参考专栏《OpenCV-Python图形图像处理 》
专栏网址:https://blog.csdn.net/laoyuanpython/category_9979286.html
老猿的付费专栏《使用PyQt开发图形界面Python应用 》(https://blog.csdn.net/laoyuanpython/category_9607725.html)专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》 (https://blog.csdn.net/laoyuanpython/category_10232926.html)详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏都适合有一定Python基础但无相关知识的小白读者学习。
付费专栏文章目录:《moviepy音视频开发专栏文章目录》(https://blog.csdn.net/LaoYuanPython/article/details/107574583)、《使用PyQt开发图形界面Python应用专栏目录 》(https://blog.csdn.net/LaoYuanPython/article/details/107580932)。
对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》(https://blog.csdn.net/laoyuanpython/category_9831699.html)从零开始学习Python。
如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。