1 腐蚀
腐蚀操作是一种形态学操作,它用于缩小二值图像中的对象,并去除图像中的噪声和细节。其基本原理是将图像中的每个像素与内核进行比较,如果内核覆盖的区域内所有像素值都为非零值,则该像素保持不变;否则,该像素的值会被更新为 0 0 0,从而实现缩小图像中的对象。腐蚀操作的效果通常与内核的大小、形状以及迭代次数有关,通过适当选择这些参数,可以实现不同程度的腐蚀效果。
在OpenCV中,可以使用 cv2.erode()
函数来进行腐蚀操作。该函数会将内核与图像进行卷积,从而得到腐蚀后的图像。具体而言,对于图像中的每个像素
(
i
,
j
)
(i, j)
(i,j),腐蚀操作会计算内核覆盖的区域
S
S
S 内所有像素的最小值,然后将像素
(
i
,
j
)
(i, j)
(i,j) 的值更新为该最小值。
该函数的语法如下:
cv2.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) → dst
其中,参数含义如下:
src
:输入图像。kernel
:腐蚀操作的内核。该参数是一个由非零值构成的二进制矩阵,用于定义腐蚀操作的形状和大小。内核的大小和形状会影响腐蚀程度。dst
:输出图像。如果未提供,则函数会创建一个与src
具有相同尺寸和类型的输出图像。anchor
:内核的锚点。该参数指示内核的中心位置,用于确定内核的变换方式。默认值为(-1, -1)
,表示使用内核的中心作为锚点。iterations
:腐蚀操作的迭代次数。该参数指示应该对图像执行多少次腐蚀操作。默认值为1
。borderType
:边界模式。默认值为cv2.BORDER_CONSTANT
。borderValue
:边界值。如果边界模式为cv2.BORDER_CONSTANT
,则该参数指定边界像素的值。
在定义kernel
时,通常使用numpy进行创建。
示例代码:
import cv2
import numpy as np
# 读入图像
img = cv2.imread('test.jpg')
# 定义内核
kernel = np.ones((5,5), np.uint8)
# 应用腐蚀操作
erosion = cv2.erode(img, kernel, iterations = 1)
# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到,仙人球的叶子被腐蚀了。
2 膨胀
膨胀操作是一种形态学操作,可以说与腐蚀正好相反,用于放大二值图像中的对象,同时去除图像中的噪声和细节。其基本原理是将图像中的每个像素与内核进行比较,如果内核覆盖的区域内至少有一个像素值为非零值,则该像素的值就被更新为 1 1 1,从而实现放大图像中的对象。膨胀操作的效果通常与内核的大小、形状以及迭代次数有关,通过适当选择这些参数,可以实现不同程度的膨胀效果。
在OpenCV中,可以使用 cv2.dilate()
函数来进行膨胀操作。该函数会将内核与图像进行卷积,从而得到膨胀后的图像。具体而言,对于图像中的每个像素
(
i
,
j
)
(i, j)
(i,j),膨胀操作会计算内核覆盖的区域
S
S
S 内所有像素的最大值,然后将像素
(
i
,
j
)
(i, j)
(i,j) 的值更新为该最大值。
使用 cv2.dilate()
函数来进行膨胀操作。该函数的语法如下:
cv2.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) → dst
其中,参数含义如下:
src
:输入图像。kernel
:膨胀操作的内核。该参数是一个由非零值构成的二进制矩阵,用于定义膨胀操作的形状和大小。内核的大小和形状会影响膨胀程度。dst
:输出图像。如果未提供,则函数会创建一个与src
具有相同尺寸和类型的输出图像。anchor
:内核的锚点。该参数指示内核的中心位置,用于确定内核的变换方式。默认值为(-1, -1)
,表示使用内核的中心作为锚点。iterations
:膨胀操作的迭代次数。该参数指示应该对图像执行多少次膨胀操作。默认值为1
。borderType
:边界模式。默认值为cv2.BORDER_CONSTANT
。borderValue
:边界值。如果边界模式为cv2.BORDER_CONSTANT
,则该参数指定边界像素的值。
仍然使用上面那个仙人球的例子:
import cv2
import numpy as np
# 读入图像
img = cv2.imread('test.jpg')
# 定义内核
kernel = np.ones((5,5), np.uint8)
# 应用腐蚀操作
erosion = cv2.dilate(img, kernel)
# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
这次仙人球的刺被明显放大了,有一种眼睛变近视了的感觉。LOL
3 开运算
开运算是一种常见的形态学操作,用于去除二值图像中的噪声和细节。其基本原理是先进行腐蚀操作,然后再进行膨胀操作,这样可以去除图像中的小型噪声和细节,同时保留对象的整体形状和尺寸。开运算通常用于平滑二值图像的轮廓,并且可以帮助保留对象的整体形状。
开运算可以通过串联腐蚀+膨胀完成,也可以使用CV2的自有函数cv2.morphologyEx()
函数+ MORPH_OPEN
来进行开运算。该函数的语法如下:
cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]) → dst
其中:
src
:输入图像。op
:形态学操作类型。该参数可以是cv2.MORPH_OPEN
,表示开运算。kernel
:形态学操作的内核。该参数是一个由非零值构成的二进制矩阵,用于定义膨胀和腐蚀操作的形状和大小。内核的大小和形状会影响开运算程度。dst
:输出图像。如果未提供,则函数会创建一个与src
具有相同尺寸和类型的输出图像。anchor
:内核的锚点。该参数指示内核的中心位置,用于确定内核的变换方式。默认值为(-1, -1)
,表示使用内核的中心作为锚点。iterations
:形态学操作的迭代次数。该参数指示应该对图像执行多少次形态学操作。默认值为1
。borderType
:边界模式。默认值为cv2.BORDER_CONSTANT
。borderValue
:边界值。如果边界模式为cv2.BORDER_CONSTANT
,则该参数指定边界像素的值。
示例代码如下:
import cv2
import numpy as np
# 读入图像
img = cv2.imread('test.jpg')
# 定义内核
kernel = np.ones((5,5), np.uint8)
# 应用开运算
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Opening', opening)
cv2.waitKey(0)
cv2.destroyAllWindows()
开运算后的效果为:
4 闭运算
与开运算相反,闭运算对图像先做膨胀,再做腐蚀。
闭运算的应用场景包括:
- 消除二值图像中的小孔和细节:闭运算可以填充图像中的小孔和消除细节,从而得到更加干净的图像,通常用于去除图像中的小型噪声和细节。
- 保留对象的整体形状和尺寸:闭运算可以保留对象的整体形状和尺寸,因为它通过先进行膨胀操作来扩大对象,然后再进行腐蚀操作来减小对象,从而保持对象的整体形状和尺寸不变。
- 图像分割:闭运算可以帮助分割图像中的不同对象,因为它可以将对象之间的间隙填充,从而使它们更容易被分开。
- 物体识别和测量:闭运算可以用于物体识别和测量,因为它可以保留对象的整体形状和尺寸,使得对象更容易被识别和测量。
在OpenCV中,可以使用cv2.morphologyEx()
函数+ MORPH_CLOSE
函数来进行闭运算。
此处使用上一篇文章的主页图片进行闭运算的测试:
import cv2
import numpy as np
# 读入图像
img = cv2.imread('test.jpg')
# 定义内核
kernel = np.ones((5,5), np.uint8)
# 应用闭运算
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# 显示结果
cv2.imshow('Original', img)
cv2.imshow('Closing', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看出部分文字细节被抹除了。
5 其他形态学运算
在cv2.morphologyEx()
中,还可以进行梯度运算,顶帽运算,黑帽运算。
梯度运算、顶帽运算和黑帽运算是形态学操作中常见的三种运算,它们分别用于计算图像的梯度、寻找图像中的明显区域以及寻找图像中的暗区域。它们都是通过将输入图像与某种内核进行卷积来实现的。
5.1 梯度运算
梯度运算是一种用于计算图像梯度的形态学操作。它可以用于检测图像中边缘的位置和方向。梯度运算的原理是通过计算图像中每个像素的局部梯度,从而确定该像素是否属于边缘。在OpenCV中,可以使用 cv2.morphologyEx()
+cv2.MORPH_GRADIENT
函数来实现梯度运算。具体而言,分别对图像进行膨胀和腐蚀操作,然后计算两幅图像的差异来获得梯度图像。
5.2 顶帽运算
顶帽运算是一种用于寻找图像中明显区域的形态学操作。它可以帮助找到图像中比周围区域更亮或更暗的区域。顶帽运算的原理是通过对图像进行计算原始图像与开运算图像的差值,从而获得顶帽图像。在OpenCV中,可以使用 cv2.morphologyEx()
+cv2.MORPH_TOPHAT
函数来实现梯度运算。
5.3 黑帽运算
黑帽运算是一种用于寻找图像中暗区域的形态学操作。它可以帮助找到图像中比周围区域更暗的区域。黑帽运算的原理是通过对图像进行闭运算和开运算来计算闭运算图像与原始图像的差值,从而获得黑帽图像。在OpenCV中,可以使用 cv2.morphologyEx()
+cv2.MORPH_BLACKHAT
函数来实现梯度运算。