目录
形态学转换
结构元素
腐蚀
膨胀
开运算
闭运算
形态学梯度
顶帽
黑帽
图像轮廓
查找轮廓
绘制轮廓
形态学转换
·形态变换是一些基于图像形状的简单操作。通常在二值图像上执行。它需要两个输入,一个是我们的原始图像,第二个是决定操作性质的结构元素或内核。两种基本的形态学算子是侵蚀和膨胀。然后,它的变体形式(如“打开”,“关闭”等)也开始起作用。形态变换是一些基于图像形状的简单操作。通常在二值图像上执行。它需要两个输入,一个是我们的原始图像,第二个是决定操作性质的结构元素或内核。两种基本的形态学算子是侵蚀和膨胀。然后,它的变体形式(如“打开”,“关闭”等)也开始起作用。基本思想:使用具有一定形状的结构元素去度量和提取图像中对应的形状,以达到对图像进行处理的目的。
形态学操作图像的数学基础是集合论
集合的交集和并集
集合的补集和差集
集合的反射
集合的平移
结构元素
二值图像形态学处理的运算对象是集合
设A为像素集合,B为结构元素(本身也是一个像素集合,其元素是感兴趣目标的像素),处理过程就是用B对A进行操作。结构元素B对A的具体操作
-
通过让B在A上平移,以便B的原点访问A的每一个元素,以此得到一个新的像素集合
结构元素必须指定一个原点
- 结构元素的原点就是形态学运算的参考点(当结果元素对称且未显示原点时,通常将原点假定在对称中心处)
当对图像操作时,要求结构元素时矩形阵列(通过添加最小可能数量的背景元素组成一个矩阵阵列来实现)
注意:形态学处理中,只考虑图像和结构元素中有效像素点,也就是只考虑感兴趣的前景部分,背景部分不予考虑
为什么结构元素是奇数:
旋转180°不变,反射之后还是他本身
原点方便定位中心点
cv2.getStructuringElement(shape, ksize, anchor)
函数用于返回一个指定形状和尺寸的结构元素,该结构元素可用于形态学操作,如腐蚀、膨胀、开运算和闭运算等。其语法参数说明:
shape
:表示结构元素的形状,可以是以下几种取值:
cv2.MORPH_RECT
:矩形结构元素
cv2.MORPH_CROSS
:十字形结构元素
cv2.MORPH_ELLIPSE
:椭圆形结构元素
ksize
:表示结构元素的大小
anchor
:表示结构元素的锚点位置,默认为(-1,-1),表示结构元素的中心
在图像处理中,使用cv2.getStructuringElement
函数创建结构元素时,将ksize
参数设置为奇数有以下几个原因:
-
对称性:奇数尺寸的结构元素具有对称性,这在一些形态学操作中是很重要的。例如,在腐蚀和膨胀操作中,使用对称的结构元素可以确保操作的结果在图像的不同位置上具有相似的效果。
-
中心性:奇数尺寸的结构元素有一个明确的中心像素。这个中心像素在形态学操作中起着重要的作用,例如在腐蚀操作中
-
边界处理的便利性:在处理图像边界时,奇数尺寸的结构元素可以更方便地处理边界像素。对于奇数尺寸,能够以更对称和一致的方式处理靠近图像边缘的部分,减少边界效应带来的不一致性。
-
更好的局部特征提取:在一些应用中,奇数尺寸的结构元素可以更准确地捕捉图像的局部特征。这是因为其中心像素能够更精确地定位在目标区域内,从而对局部结构的描述更加准确。
-
数学计算的简洁性:在某些形态学运算的数学实现中,奇数尺寸的结构元素可能会使计算更加简洁和高效,减少计算过程中的复杂性和可能出现的错误。
腐蚀
.Common Names: Erode, Shrink, Reduce(常用名称:腐蚀,侵蚀,收缩,减少)。侵蚀是数学形态学领域的两个基本算子之一,另一个是膨胀算子。
·侵蚀通常适用于二值图像,但也有适用于灰度图像的版本。算子对二值图像的基本作用是侵蚀掉前景像素(即白色像素)区域的边界。因此,前景像素的区域缩小了。
效果:缩小图像中的物体
定义:假设A是原始的二值图像,B是结构元素,则A被B腐蚀的定义为:将结构元素B相对于集合A进行平移,只要平移后结构元素都包含在集合A中,则这些位移Z的点(前景像素点)的集合即为腐蚀后的结果
def erode(src, kernel, dst=None, anchor=None, iterations=None, borderType=None, borderValue=None):
src
:输入图像,可以是多通道图像,深度应为CV_8U
、CV_16U
、CV_16S
、CV_32F
或CV_64F
之一。
dst
:输出与输入图像相同大小和类型的图像。
kernel
:用于腐蚀的结构元素。如果kernel=Mat()
,则使用3x3矩形结构元素。可以使用getStructuringElement()
函数创建内核。
anchor
:锚点在元素内的位置,默认值为(-1,-1),表示锚点位于元素中心。
iterations
:腐蚀的次数,默认值为1。
borderType
:像素外推方法,可选项包括BORDER_CONSTANT
、BORDER_REPLICATE
等。
borderValue
:边界不变的边界值。
腐蚀的过程
eg:去掉两个物体之间连接的细线
im=np.zeros((200,200),np.uint8)
im[20:23,20:23]=255# 获取一个3*3的结构元素
# 第一个参数:结果元素的形状,矩阵还是十字型
# 第二个参数:结构元素的大小
kernel=cv2.getStructuringElement(cv2.MORPH_RECT,(3,3))
dst=cv2.erode(im,kernel)
cv2.imshow("im",im)
cv2.imshow("dst",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
用3*3的卷积核腐蚀3*3的矩阵(原图--右,效果图--左)
膨胀
·效果:扩大图像中的物体,在二值图中扩大白色的部分,收缩黑色的部分
·定义:假设A是原始的二值图像,B是结构元素,则A被B膨胀的定义为:
又被定义为:
也就是,A被B膨胀的结果是满足上面公式的所有位移z的点(前景像素点)的集合。
dilation = cv.dilate(img,kernel,iterations =1)
img
:要进行膨胀操作的输入图像。
kernel
:用于膨胀操作的结构元素,通常通过cv2.getStructuringElement
函数获取。
iterations
:膨胀操作的迭代次数。默认值为 1,表示执行一次膨胀操作。如果设置为大于 1 的值,则会连续执行指定次数的膨胀操作,使得膨胀效果更加强烈。
开运算
效果: 断开较窄的粘连线,消除较细的突出物和噪音,使图像的轮廓变得光滑(去除白点)
定义: 假设A是原始的二值图像,B是结构元素,则A被B开运算的定义为:
也就是,先用B对A继续腐蚀,然后再用B对腐蚀的结果进行膨胀
opening = cv2.morphologyEx(img, cv.MORPH_OPEN, kernel)
闭运算
效果:关闭前景对象内部的小孔或对象上的小黑点时很有用。使图像的
轮廓变得光滑(去除黑点)
定义:假设A是原始的二值图像,B是结构元素,则A被B闭运算的定义
为: 先用B对A继续膨胀,然后再用B对膨胀的结果进行腐蚀
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
形态学梯度
效果:
图像边界提取
·定义:假设A是原始的二值图像,B是结构元素,则定义为:
也就是,腐蚀的部分
·gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
示例:获取图像边界
import cv2
im = cv2.imread("grad.png")
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
im2 = cv2.morphologyEx(im, cv2.MORPH_GRADIENT, kernel)
cv2.imshow("im", im)
cv2.imshow("gradient", im2)
# cv2.imshow("im3", im3)
cv2.waitKey(0)
cv2.destroyAllWindows()
顶帽
顶帽是输入图像和图像开运算之差
-
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
细小结构。因此,顶帽运算能够突出原始图像中比周围环境更亮的区域
或者斑点,有助于分离出这些亮区域,比如寻找图像中的亮点物体或者
高亮细节。这对于背景相对均匀而前景目标较亮的图像特别有用,例如,
在医学成像或文本识别中强调局部高亮区域。(找小白点)
-
·开运算由先腐蚀后膨胀组成,能够去除图像中的小亮点(比如噪声)
黑帽
是输入图像和图像闭运算之差
-
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT,kernel)
闭运算由先膨胀后腐蚀组成,能够填充图像中的小暗点和细小缝隙。因此,黑帽运算能突出显示原始图像中比周围环境更暗的区域或者斑块,有助于发现图像中的暗区域或者阴影部分,对于背景去除或者凸显图像中的暗结构非常有效。在一些应用场景下,如检测路面坑洞或寻找图像中的暗色目标时非常有用。
图像轮廓
图像轮廓是具有相同颜色或灰度的连续点的曲线,轮廓在形状分析和物
体的检测和识别中很有用。
·轮廓的作用:
-图形分析-物体的检测和识别
.注意点:
函数返回两个值:轮廓列表 contours
和轮廓的层次结构 hierarchy
。
.Mode查找轮廓的模式:
RETR EXTERNAL=0这是最简单的检索模式,只检索最外层的轮廓,即不包括任何嵌套轮廓。如果你只关心物体的外部边界,而不考虑其内部结构或孔洞,这个模式就很适用。
RETR LIST=1该模式检索所有轮廓,并将其作为列表返回,但不创建任何层次结构。每个轮廓都是独立的,没有父子关系信息。适用于需要所有轮廓但不需要它们之间关系的场景。
RETR CCOMP =2在这种模式下,检索到的轮廓被组织成两层层次结构。顶层是外部边界,第二层是孔和内部边界。如果一个对象内有多个孔,则孔被视为同一层级。这对于需要区分外边界和内部孔洞的场景很有用。
RETR_TREE =3这是最复杂的检索模式,构建了一个完整的轮廓层次树。每个轮廓都有一个层次信息,可以区分出父轮廓和子轮廓(内部轮廓),非常适合于需要分析复杂结构和多级嵌套轮廓的场景。(常用这个)
-
需要先对图像进行二值化处理
-
画轮廓会修改原始图像,如果后面像继续使用原始图像,应该设置原始图像副本
-
查找轮廓
findContours(image, mode, method[, contours[,hierarchy[ offset]]]) -> contours, hierarchy
图片只能是单通道u8的
cv2.findContours
函数用于在二值图像中查找轮廓,其参数如下:
image
:输入的 8 位单通道图像,可以是二值图像。
mode
:轮廓的检索模式,常见的取值有:
cv2.RETR_EXTERNAL
:只检测最外层轮廓。
cv2.RETR_LIST
:检测所有轮廓,不建立层次关系。
cv2.RETR_CCOMP
:检测所有轮廓,并将其组织为两层的层次结构。
cv2.RETR_TREE
:检测所有轮廓,并重建完整的层次结构。
method
:轮廓的近似方法,常见的取值有:
cv2.CHAIN_APPROX_NONE
:存储所有的轮廓点。
cv2.CHAIN_APPROX_SIMPLE
:压缩水平、垂直和对角线段,只保留其端点。
-
函数返回两个值:轮廓列表
contours
和轮廓的层次结构hierarchy
。.Mode查找轮廓的模式:
RETR EXTERNAL=0这是最简单的检索模式,只检索最外层的轮廓,即不包括任何嵌套轮廓。如果你只关心物体的外部边界,而不考虑其内部结构或孔洞,这个模式就很适用。
RETR LIST=1该模式检索所有轮廓,并将其作为列表返回,但不创建任何层次结构。每个轮廓都是独立的,没有父子关系信息。适用于需要所有轮廓但不需要它们之间关系的场景。
RETR CCOMP =2在这种模式下,检索到的轮廓被组织成两层层次结构。顶层是外部边界,第二层是孔和内部边界。如果一个对象内有多个孔,则孔被视为同一层级。这对于需要区分外边界和内部孔洞的场景很有用。
RETR_TREE =3这是最复杂的检索模式,构建了一个完整的轮廓层次树。每个轮廓都有一个层次信息,可以区分出父轮廓和子轮廓(内部轮廓),非常适合于需要分析复杂结构和多级嵌套轮廓的场景。(常用这个)
findContours(image, mode, method[, contours[,hierarchy[,offset]]]) -> contours(轮廓), hierarchy(层级)
·Method:
-
CHAIN APPROX NONE=1:轮廓中的每一点都会被精确保存下来
-
CHAIN APPROX SIMPLE = 2: 仅保留轮廓的端点和具有拐角的点来简化轮廓表示
绘制轮廓
drawContours(image, contours, contourldx, color[, thickness[,lineType[,hierarchy[,maxLevel[, offset]]]]]) -> image
Image 要绘制的轮廓图像
Contours 轮廓点
contourldx 要绘制的轮廓编号,-1表示绘制所有轮廓,0是最外层,1是内层
:Color: 轮廓的颜色
Thickness:线宽,-1表示填充
代码示例:绘制左图中的所有边框轮廓
import cv2im = cv2.imread("p1.png")
im_orgin = im.copy()
im1 = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)# 查找轮廓
contours, _ = cv2.findContours(im1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 绘制轮廓cv2.drawContours(im, contours, -1, (0, 0, 255), 2, cv2.LINE_AA)
cv2.imshow("im_orgin", im_orgin)
cv2.imshow("im", im)
cv2.waitKey(0)
cv2.destroyAllWindows()