图像处理一
- 一、阈值处理
- 1.1 OpenCV 提供了函数` cv2.threshold()`和函数` cv2.adaptiveThreshold(),`用于实现阈值处理
- 1.1.1. cv2.threshold():
- (1)在函数`cv2.threshold()`中,参数`threshold_type`用于指定阈值处理的方式。它有以下几种可选的阈值类型:
- (2)代码
- (3)图像部分
- 1.1.2. cv2.adaptiveThreshold():
- 1.2 Otsu 处理
- 二、形态学操作
- 2.1 连通性
- 2.1.1 邻接种类
- 2.1.2 连通种类(3种)
- 2.2 腐蚀和膨胀
- 2.2.1 膨胀(Dilation):`cv2.dilate`
- (1)函数原型以及使用方式
- (2)Py中常用的3个参数
- (3) 理解膨胀的效果
- 2.2.2 腐蚀(Erosion): `cv2.erode`
- (1)函数原型以及使用方式
- (2)Py中常用的3个参数
- (3)理解腐蚀的效果
- 2.2.3 腐蚀和膨胀代码以及图片演示
- (1)普通的
- (2)三张照片
- 2.2.4 形态学梯度:膨胀与腐蚀之差
- 或者函数
- 2.3 开闭运算
- 2.3.1 开运算 opening
- 2.3.2 闭运算 closing
- 2.3.3 通用形态学函数
- (1)常用的参数:
- (2)完整的
- (3)注意事项
- 2.3.4 代码以及演示
- 2.4 礼帽和黑帽
- 2.4.1 礼帽运算 (Top-Hat Transformation)
- 2.4.2 黑帽运算 (Black-Hat Transformation)
- 2.4.3 代码以及图片演示
- 2.5 核函数
- 细微变化
一、阈值处理
阈值:指的是某一个范围内,不可逾越,不能低于的值。
例如,设定阈值为127,然后:
将图像内所有像素值大于 127 的像素点的值设为 255。
将图像内所有像素值小于或等于 127 的像素点的值设为 0。
1.1 OpenCV 提供了函数 cv2.threshold()
和函数 cv2.adaptiveThreshold(),
用于实现阈值处理
cv2.threshold() 和 cv2.adaptiveThreshold() 是 OpenCV 中用于实现阈值处理的两个函数,它们之间有以下区别:
1.1.1. cv2.threshold():
这个函数是全局阈值处理方法。它将输入图像转换为二进制图像,将像素值与用户提供的阈值进行比较,并根据比较结果将像素设置为给定的最大值或最小值。语法如下:
retval, threshold_image = cv2.threshold(src, threshold_value, max_value, threshold_type)
其中:
- retval 代表返回的阈值。
- threshold_image 代表阈值分割结果图像,与原始图像具有相同的大小和类型。
- src:输入图像,单通道灰度图像的,8 位或 32 位浮点型数值。
- threshold_value:阈值,用于将像素值与之比较。
- max_value:当像素值大于阈值时,设置的像素值。
- threshold_type:阈值类型,用于指定阈值处理的方式。
(1)在函数cv2.threshold()
中,参数threshold_type
用于指定阈值处理的方式。它有以下几种可选的阈值类型:
cv2.THRESH_BINARY
:如果像素值大于阈值,设置为最大值,否则设置为0。
在 8 位图像中,最大值是 255。因此,在对 8 位灰度图像进行二值化时,如果将阈值设定
为 127,那么:
所有大于 127 的像素点会被处理为 255。
其余值会被处理为 0。
cv2.THRESH_BINARY_INV
:与cv2.THRESH_BINARY
相反,如果像素值大于阈值,设置为0,否则设置为最大值。
反二值化阈值处理针对像素点的处理方式为:
对于灰度值大于阈值的像素点,将其值设定为 0。
对于灰度值小于或等于阈值的像素点,将其值设定为 255。
cv2.THRESH_TRUNC
:如果像素值大于阈值,设置为阈值,否则保持不变。
截断阈值化处理:
例如,阈值选取为 127,则截断阈值化处理时:
对于像素值大于 127 的像素点,其像素值将被设定为 127。
对于像素值小于或等于 127 的像素点,其像素值将保持改变。
cv2.THRESH_TOZERO
:如果像素值大于阈值,保持不变,否则设置为0。
低阈值零处理
例如,阈值选取为 127,则:
对于像素值大于 127 的像素点,其像素值将保持改变。
对于像素值小于或等于 127 的像素点,其像素值将被设定为 0。
cv2.THRESH_TOZERO_INV
:与cv2.THRESH_TOZERO
相反,如果像素值大于阈值,设置为0,否则保持不变。
超阈值零处理
例如,阈值选取为 127,则:
对于像素值大于 127 的像素点,其值将被设定为 0。
对于像素值小于或等于 127 的像素点,其值将保持改变。
这些阈值类型可以根据具体的应用需求选择。例如,如果要将图像转换为二进制图像(黑白图像),可以使用cv2.THRESH_BINARY
或cv2.THRESH_BINARY_INV
。如果只想保留图像中较亮的部分,并将其他部分设为黑色,可以使用cv2.THRESH_TRUNC
。
(2)代码
# 二值化阈值处理会将原始图像处理为仅有两个值的二值图像,
import numpy as np
import cv2 as cv
import matplotlib.pyplot as pltx=np.random.randint(0,256,size=(4,4),dtype=np.uint8)
x
ret,dst=cv.threshold(x,thresh=127,maxval=255,type=cv.THRESH_BINARY)
ret=127.0
dst
(3)图像部分
反二值
1.1.2. cv2.adaptiveThreshold():
这个函数是自适应阈值处理方法。它根据图像不同区域的统计特性自适应地选择阈值进行像素分割。语法如下:
这种方法允许在图像的不同区域使用不同的阈值,从而提高对局部变化的适应性
threshold_image = cv2.adaptiveThreshold(src, max_value, adaptive_method, threshold_type, block_size, constant)
其中:
- src:输入图像,单通道灰度图像。
- max_value:当像素值大于阈值时,设置的像素值。
- adaptive_method:自适应阈值算法,可选值包括cv2.ADAPTIVE_THRESH_MEAN_C和cv2.ADAPTIVE_THRESH_GAUSSIAN_C。
- threshold_type:阈值类型,用于指定阈值处理的方式。
- block_size:计算阈值时使用的像素领域大小。
- constant:从计算的均值或加权均值中减去的常数。
cv2.ADAPTIVE_THRESH_MEAN_C:邻域所有像素点的权重值是一致的。
cv2.ADAPTIVE_THRESH_GAUSSIAN_C:与邻域各个像素点到中心点的距离有关,通
过高斯方程得到各个点的权重值。
总结:
- cv2.threshold() 是一种全局的阈值处理方法,适用于图像中的大部分区域。它对整个图像应用相同的阈值。
- cv2.adaptiveThreshold() 是一种自适应的阈值处理方法,适用于图像中具有不同光照条件和对比度的不同区域。它根据图像的局部特性来选择阈值。
1.2 Otsu 处理
在图像处理中,阈值化是将灰度图像转换为二值图像的过程,其中根据某个阈值将像素分为两个类别:背景和前景。通常情况下,我们可以手动选择一个阈值进行二值化。但对于不同图像,选择合适的阈值可能会很困难。
Otsu处理通过最小化类别内方差和最大化类别间方差来自动确定最佳阈值。它利用图像的直方图信息,找到能够最好地区分前景和背景的阈值。这使得Otsu处理能够更好地适应不同图像的特性,并产生更准确的结果。
使用OpenCV中的cv2.THRESH_OTSU标志,可以轻松应用Otsu处理来确定图像的最佳阈值,并将图像进行二值化。
import cv2
import numpy as np
from matplotlib import pyplot as pltimg = cv2.imread('Pic/cc.jpg', 0)# 使用Otsu's方法进行阈值处理
ret, otsu_thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 使用cv2.THRESH_BINARY进行阈值处理
_, binary_thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)# 使用cv2.THRESH_TRUNC进行阈值处理
_, trunc_thresh = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC)# 使用cv2.THRESH_TOZERO进行阈值处理
_, tozero_thresh = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO)# 绘制结果图像
plt.subplot(221), plt.imshow(img, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(222), plt.imshow(binary_thresh, cmap='gray')
plt.title('cv2.THRESH_BINARY'), plt.xticks([]), plt.yticks([])
plt.subplot(223), plt.imshow(otsu_thresh, cmap='gray')
plt.title('cv2.THRESH_BINARY + cv2.THRESH_OTSU'), plt.xticks([]), plt.yticks([])
plt.subplot(224), plt.imshow(tozero_thresh, cmap='gray')
plt.title('cv2.THRESH_TOZERO'), plt.xticks([]), plt.yticks([])plt.show()
二、形态学操作
形态学(英语morphology,德语morphologie )的范畴来自希腊语morphe,歌德在自己的生物学研究中倡导得最早,歌德由于不满意自然科学中过分的理性分析倾向,才有这样的规划与设想。
【意为“形状”或“结构”。在图像处理和计算机视觉领域中,形态学通常指的是对图像中对象的形状和结构进行分析和处理的一组数学方法。】
形态学操作的目标是通过改变图像的形状和结构来提取关键信息,如去除噪声、连接对象、分离对象等。形态学操作基于图像中的集合论和拓扑学概念,其中形状和结构是通过一种称为“结构元素”的模板进行操作的。结构元素是一个小的、预定义的形状,类似于滤波器,它在图像上移动并与图像的相应部分进行比较。
形态学操作在图像处理中具有广泛的应用,尤其是在图像分割、特征提取和对象识别等任务中。腐蚀和膨胀是形态学操作的基本构建块,而开运算和闭运算则是这些基本操作的组合,用于解决更复杂的问题。还有形态学梯度(Morphological Gradient)运算、顶帽运算(礼帽运算)、黑帽运算击中击不中等不同形式的操作。这些操作对于处理具有不同形状、大小和方向的对象的图像非常有用。
形态学处理在视觉检测、文字识别、医学图像处理、图像压缩编码等领域都有非常重要的应用。
2.1 连通性
在图像处理和计算机视觉中,"连通性"是指像素之间的连接性或相互关联的性质。它涉及到图像中的区域、对象或像素集合之间的连接关系。
判断两个像素是否连通的条件:
(1)位置相邻: 两个像素必须在空间上是相邻的,即它们在图像中的位置是相邻的。
(2)灰度值相同或相似: 对于灰度图像,两个像素的灰度值通常需要相同或相似。
2.1.1 邻接种类
因为图像中,我们常说的像素是其最小的不可分割的单位。它代表了图像在某区域的信息,它所包含的信息关乎到颜色以及灰度值的大小,而正是这小方块的排列才组成了我们看到的计算机视觉上的“信息”。
-
4-邻接:
在4-邻接中,一个像素的邻接像素包括其上、下、左、右四个方向的像素。这意味着一个像素与它上下左右相邻的四个像素是邻接的。像素p(x,y)的4邻域是: (x+1,y); (x-1,y); (x,y+1); (x,y-1),用N4(p)表示像素p的4邻接
0 1 0
1 x 1 (x表示中心像素)
0 1 0
- 8-邻接:
. 在8-邻接中,一个像素的邻接像素包括其上、下、左、右四个方向的像素,以及对角线方向的四个像素。这意味着一个像素与它上下左右和对角线方向上相邻的八个像素是邻接的。
像素p(x,y)的8邻域是: 4邻域的点 +D邻域的点,用Ng(p)表示像素p的8邻域连通性是描述区域和边界的重要概念
1 1 1
1 x 1 (x表示中心像素)
1 1 1
- “D-邻接”
通常指的是对角线邻接,即在一个像素的周围,除了上、下、左、右的四个方向,还包括对角线方向上的四个方向。这与8-邻接不同,8-邻接同时考虑了上下左右和对角线方向的邻接像素,而D-邻接则专指对角线方向。
像素pix,y)的D邻域是:对角上的点(x+1,y+1); (x+1,y-1); (x-1,y+1); (x-1,y-1),用Np(p)表示像素p的D邻域
在D-邻接中,一个像素的邻接像素包括以下八个方向:
1 0 1
0 x 0 (x表示中心像素)
1 0 1
2.1.2 连通种类(3种)
-
4连通: 两个像素p和q被称为4连通,如果q在p的4邻域(上、下、左、右)中。
-
8连通: 两个像素p和q被称为8连通,如果q在p的8邻域(包括对角线方向)中。
-
m连通: m连通是一种混合联通定义。两个像素p和q被称为m连通,如果以下条件之一成立:
- q在p的4邻域中(4联通条件)。
- q在p的D邻域中,同时p的4邻域与q的4邻域没有相交(即没有共同的像素,或者说两者之间没有值V的像素)。
这种混合连通性的定义允许通过4联通和8联通的条件来判断两个像素是否相连,同时引入了一些其他限制,以确保连接是有效的。m联通性的定义在一些图像处理任务中可能更灵活,允许更大的灵活性。
2.2 腐蚀和膨胀
这两个操作可以通过以下方式来理解:
腐蚀: 就像沙滩上的海水慢慢侵蚀沙堆,使其变小。
膨胀: 就像在沙堆上添加一些沙子,使其变得更大。’
腐蚀(Erosion)和膨胀(Dilation)是形态学操作中的两个基本操作,它们常常用于图像处理中的前景和背景的调整,以及对象的形状和结构的改变。这两种操作通常与结构元素(structuring element)一起使用。
2.2.1 膨胀(Dilation):cv2.dilate
- 操作原理: 通过滑动结构元素,将图像中的高亮区域扩张,使得效果图中的高亮区域比原图更大。
- 效果: 连接相邻的高亮区域,填充小的间隙,使图像中的白色区域增加。
- 本质: 是求局部最大值的操作。
(1)函数原型以及使用方式
cv.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
cv.dilate
是 OpenCV 库中用于图像膨胀的函数之一。膨胀是形态学操作的一种,它通过移动结构元素(也称为核或内核)在图像上的所有像素上,将像素值置为其邻域内的最大值。这有助于扩大物体,连接物体的断开部分,并强调物体的边缘。
下面是 cv.dilate
函数的一般形式和参数说明:
src
: 输入图像,通常为灰度图像。kernel
: 结构元素(内核),它是在图像上移动的小矩阵。它可以是矩形、椭圆、十字形等形状。可以使用cv.getStructuringElement()
来创建不同形状和大小的结构元素。dst
: 输出图像,与输入图像具有相同的类型和大小。如果未提供,则函数会修改原始图像。anchor
: 结构元素的锚点。它指示结构元素的中心位置,通常位于结构元素的中心。默认值为 (-1, -1),表示锚点位于结构元素的中心。iterations
: 膨胀的迭代次数。默认为 1。borderType
: 图像边界处理类型。默认为cv.BORDER_CONSTANT
,表示用常数填充边界。可以使用其他选项,如cv.BORDER_REPLICATE
或cv.BORDER_REFLECT
。borderValue
: 在使用常数填充边界时所用的常数值,默认为 0。
以下是一个简单的例子:
import cv2 as cv
import numpy as np# 读取图像
image = cv.imread('example.jpg', cv.IMREAD_GRAYSCALE)# 创建一个 3x3 的矩形结构元素
kernel = np.ones((3, 3), np.uint8)# 进行膨胀操作
dilated_image = cv.dilate(image, kernel, iterations=1)# 显示原始图像和膨胀后的图像
cv.imshow('Original Image', image)
cv.imshow('Dilated Image', dilated_image)
cv.waitKey(0)
cv.destroyAllWindows()
在这个例子中,cv.dilate
函数使用了一个 3x3 的矩形结构元素,对输入图像进行了一次膨胀操作。你可以根据需要调整结构元素的大小和形状,以及迭代次数,来获得不同的效果。
(2)Py中常用的3个参数
import cv2 as cv
cv.dilate(img,kernel,iterations)
kernel - 核结构
iterations - 膨胀次数,默认为1
(3) 理解膨胀的效果
膨胀操作与腐蚀相反,它可以使物体的边界向外膨胀一定的距离,将与物体接触的背景点合并到物体中,
以此来增大目标并添补目标中的孔洞。
增大目标并添补孔洞:膨胀操作可以填充物体中的小孔洞或细小空洞。
当物体内部存在一些细小的空隙或孔洞时,膨胀操作会使物体的边界向外膨胀,将与这些孔洞相邻的背景像素合并到物体中,从而填补这些孔洞,使得目标变得更大且更完整将背景点合并到物体中:膨胀操作会扩张物体边界,使物体的边界向外延伸一定的距离。
在这个过程中,原本与物体接触的背景区域的像素会被合并到物体中。这意味着物体的边界会变得更加光滑,原本与背景接触的一些像素点会被认为是物体的一部分,从而扩大了物体的尺寸。
2.2.2 腐蚀(Erosion): cv2.erode
- 操作原理: 通过滑动结构元素,将图像中的高亮区域缩小,使得效果图中的高亮区域比原图更小。
- 效果: 消除小的对象、细小的结构和噪声,使图像中的白色区域减小。
- 本质: 是求局部最小值的操作。
(1)函数原型以及使用方式
cv.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
腐蚀是一种形态学操作,它通过移动结构元素(也称为核或内核)在图像上的所有像素上,将像素值置为其邻域内的最小值。这有助于消除图像中的小物体,平滑物体边界,并缩小或消除物体。
下面是 cv.erode
函数的一般形式和参数说明:
cv.erode(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
src
: 输入图像,通常为灰度图像。kernel
: 结构元素(内核),它是在图像上移动的小矩阵。它可以是矩形、椭圆、十字形等形状。可以使用cv.getStructuringElement()
来创建不同形状和大小的结构元素。dst
: 输出图像,与输入图像具有相同的类型和大小。如果未提供,则函数会修改原始图像。anchor
: 结构元素的锚点。它指示结构元素的中心位置,通常位于结构元素的中心。默认值为 (-1, -1),表示锚点位于结构元素的中心。iterations
: 腐蚀的迭代次数。默认为 1。borderType
: 图像边界处理类型。默认为cv.BORDER_CONSTANT
,表示用常数填充边界。可以使用其他选项,如cv.BORDER_REPLICATE
或cv.BORDER_REFLECT
。borderValue
: 在使用常数填充边界时所用的常数值,默认为 0。
import cv2 as cv
import numpy as np# 读取图像
image = cv.imread('example.jpg', cv.IMREAD_GRAYSCALE)# 创建一个 3x3 的矩形结构元素
kernel = np.ones((3, 3), np.uint8)# 进行腐蚀操作
eroded_image = cv.erode(image, kernel, iterations=1)# 显示原始图像和腐蚀后的图像
cv.imshow('Original Image', image)
cv.imshow('Eroded Image', eroded_image)
cv.waitKey(0)
cv.destroyAllWindows()
在这个例子中,cv.erode
函数使用了一个 3x3 的矩形结构元素,对输入图像进行了一次腐蚀操作。你可以根据需要调整结构元素的大小和形状,以及迭代次数,来获得不同的效果。
(2)Py中常用的3个参数
import cv2 as cv
cv.erode(img,kernel,iterations)
kernel - 核结构
iterations - 腐蚀次数,默认为1
(3)理解腐蚀的效果
消除边界点:腐蚀操作会将物体边界的像素“侵蚀”,也就是将物体边界向内部缩小一定的距离。
这会导致物体边界的像素被消除或减少,从而使物体整体变小。缩小目标:可以通过腐蚀来减小物体的大小以去除不必要的细节。消除小噪声点:小的噪声点会被消除掉,因为它们被看作是物体边界的一部分,随着边界的腐蚀而消失。
2.2.3 腐蚀和膨胀代码以及图片演示
(1)普通的
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt#1.读取图像img = cv.imread("img/test_img.jpg")
#2.Kernel 核结构
kernel = np.ones((5, 5), np.uint8)
#3.图像的腐蚀和膨胀
erpsion = cv.erode(img, kernel)
dilate = cv.dilate(img, kernel)fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("原图")axes[1].imshow(erpsion[:, :, ::-1])
axes[1].set_title("腐蚀")axes[2].imshow(dilate[:, :, ::-1])
axes[2].set_title("膨胀")plt.show()
(2)三张照片
这是三张不同的,用于对比,其中的圈住的并非OpenCV标注,是我自己为了对比,做的记号
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt#1.读取图像img = cv.imread("img/work1127.jpg")
## 腐蚀和膨胀针对于高亮区域进行的
# img = cv.imread("img/useCvOpenxx.jpg")
# img = cv.imread("img/usecvClose.jpg")
#2.Kernel 核结构
kernel = np.ones((5, 5), np.uint8)
#3.图像的腐蚀和膨胀
erpsion = cv.erode(img, kernel)
dilate = cv.dilate(img, kernel)fig, axes = plt.subplots(nrows=1, ncols=3, figsize=(10, 8), dpi=100)
axes[0].imshow(img[:, :, ::-1])
axes[0].set_title("原图")axes[1].imshow(erpsion[:, :, ::-1])
axes[1].set_title("腐蚀")axes[2].imshow(dilate[:, :, ::-1])
axes[2].set_title("膨胀")plt.show()
2.2.4 形态学梯度:膨胀与腐蚀之差
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
#1.读取图像
## 腐蚀和膨胀针对于高亮区域进行的
img = cv.imread("img/usecvClose.jpg")
#2.Kernel 核结构
kernel = np.ones((5, 5), np.uint8)
#3.图像的腐蚀和膨胀
erpsion = cv.erode(img, kernel)
dilate = cv.dilate(img, kernel)plt.imshow(dilate-erpsion)
plt.show()
或者函数
通过将函数 cv2.morphologyEx()的操作类型参数 op 设置为“cv2.MORPH_GRADIENT”,可以实现形态学梯度运算。其语法结构如下:
result = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
2.3 开闭运算
开运算和闭运算是将腐蚀和膨胀按照一定的次序进行处理。 但这两者并不是可逆的,即先开后闭并不能得到原来的图像。
2.3.1 开运算 opening
开运算是先腐蚀后膨胀。 其作用是:分离物体,消除小区域。 特点:消除噪点,去除小的干扰块,而不影响原来的图像。
开运算:先进行腐蚀,再进行膨胀。它能够消除小的噪声和干扰,分离物体,
并且不影响原始图像的结构。这种操作特别适用于去除小物体、光滑边界和减少细小细节
2.3.2 闭运算 closing
闭运算与开运算相反,是先膨胀后腐蚀,、
作用是消除“闭合”物体里面的孔洞
特点:可以填充闭合区域。
闭运算:先进行膨胀,再进行腐蚀。闭运算通常用于填充物体内部的孔洞或者连接物体之间的间断部分。
它能够关闭物体内部的小空洞,填充闭合区域,并且保持物体的整体形状
2.3.3 通用形态学函数
(1)常用的参数:
import cv2 as cv
cv.morphologyEx(src, op, kernel)
src: 要处理的图像
op: 处理方式:若进行开运算,则设为cv.MORPH_OPEN,
若进行闭运算,则设为cv.MORPH_CLOSE
Kernel: 核结构
(2)完整的
形态学操作是图像处理中的一种基础操作,它包括腐蚀、膨胀、开运算、闭运算等。在 OpenCV 中,有一个通用的形态学操作函数 cv.morphologyEx
,可以执行不同形式的形态学操作,包括腐蚀、膨胀、开运算、闭运算等。
cv.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
src
: 输入图像,通常为灰度图像。
op
: 形态学操作的类型,可以是以下之一:
cv.MORPH_ERODE
: 腐蚀cv.MORPH_DILATE
: 膨胀cv.MORPH_OPEN
: 开运算cv.MORPH_CLOSE
: 闭运算cv.MORPH_GRADIENT
: 梯度运算cv.MORPH_TOPHAT
: 顶帽运算cv.MORPH_BLACKHAT
: 黑帽运算
kernel
: 结构元素(内核),它是在图像上移动的小矩阵。可以使用cv.getStructuringElement()
来创建不同形状和大小的结构元素。
dst
: 输出图像,与输入图像具有相同的类型和大小。如果未提供,则函数会修改原始图像。
anchor
: 结构元素的锚点。它指示结构元素的中心位置,通常位于结构元素的中心。默认值为 (-1, -1),表示锚点位于结构元素的中心。
iterations
: 操作的迭代次数。默认为 1。
borderType
: 图像边界处理类型。默认为cv.BORDER_CONSTANT
,表示用常数填充边界。可以使用其他选项,如cv.BORDER_REPLICATE
或cv.BORDER_REFLECT
。
borderValue
: 在使用常数填充边界时所用的常数值,默认为 0。
以下是一个简单的例子,演示如何使用 cv.morphologyEx
函数进行开运算:
import cv2 as cv
import numpy as np# 读取图像
image = cv.imread('example.jpg', cv.IMREAD_GRAYSCALE)# 创建一个 3x3 的矩形结构元素
kernel = np.ones((3, 3), np.uint8)# 进行开运算
opened_image = cv.morphologyEx(image, cv.MORPH_OPEN, kernel)# 显示原始图像和开运算后的图像
cv.imshow('Original Image', image)
cv.imshow('Opened Image', opened_image)
cv.waitKey(0)
cv.destroyAllWindows()
通过调整操作类型和结构元素,你可以执行其他形态学操作,如膨胀、闭运算等。
(3)注意事项
在实例中,具有两次迭代的打开操作(#MORPH_OPEN)相当于apply依次为:
侵蚀->侵蚀->扩张->扩张(而不是侵蚀->扩张->侵蚀->扩张)。
2.3.4 代码以及演示
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt# 读取两张图像
imgCvOpen = cv.imread("img/useCvOpenxx.jpg")
imgCvClose = cv.imread("img/usecvClose.jpg")# 创建核结构(这里创建了一个10x10的全为1的二维数组,作为形态学运算的核结构)
kernel = np.ones((10, 10), np.uint8)# 执行开运算和闭运算
# 开运算:消除周围的噪点
cvOpen = cv.morphologyEx(imgCvOpen, cv.MORPH_OPEN, kernel)
# 闭运算:填充闭合区域的孔洞
cvClose = cv.morphologyEx(imgCvClose, cv.MORPH_CLOSE, kernel)# 使用 Matplotlib 显示图像
fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 8))# 显示原始图像和处理后的图像
axes[0, 0].imshow(imgCvOpen[:, :, ::-1])
axes[0, 0].set_title("imgCvOpen原图Img")
axes[0, 1].imshow(cvOpen[:, :, ::-1])
axes[0, 1].set_title("cvOpenImg")axes[1, 0].imshow(imgCvClose[:, :, ::-1])
axes[1, 0].set_title("imgCvClose原图Img")
axes[1, 1].imshow(cvClose[:, :, ::-1])
axes[1, 1].set_title("cvCloseImg")plt.show()
2.4 礼帽和黑帽
礼帽运算(Top Hat)和黑帽运算(Black Hat)是形态学操作的两种特殊形式,它们通常用于图像的细节增强和物体检测。
2.4.1 礼帽运算 (Top-Hat Transformation)
原图像与“开运算“的结果图之差
dst=tophat(src,element)=src-open(src,element)
礼帽运算是原始图像与开运算之差,其中开运算通常用于去除图像中的噪声。礼帽运算突出了图像中的细小亮区域,有助于强调一些细节。
礼帽运算是原始图像与开运算结果之差的操作,
数学表达为
dst = tophat(src, element) = src - open(src, element)
。
它能突出比原图周围更亮的区域,
强调了图像中边缘或细小亮度变化的区域。
在背景相对较亮,而微小物品或特定区域比较暗的情况下,使用礼帽运算能够帮助提取这些微小暗区域,
这种操作与选择的核大小相关。
2.4.2 黑帽运算 (Black-Hat Transformation)
为”闭运算“的结果图与原图像之差。
dst=blackhat(src,element)=close(src,element)-src
黑帽运算是闭运算与原始图像之差,其中闭运算通常用于填充图像中的空洞。黑帽运算突出了图像中的细小暗区域,有助于强调一些细节。
黑帽运算是闭运算结果与原始图像之差的操作,
数学表达为 dst = blackhat(src, element) = close(src, element) - src。
它能够突出比原图周围更暗的区域,强调了图像中边缘或细小暗区域的存在。
在背景相对较暗,但是存在微小暗区域或者噪声时,使用黑帽运算能够帮助分离这些暗区域,
同样,这种操作与所选择的核大小相关。
2.4.3 代码以及图片演示
import numpy as np
import cv2 as cv
import matplotlib.pyplot as pltimgOpen=cv.imread("img/useCvOpenxx.jpg")
imgClose=cv.imread("img/usecvClose.jpg")#核结构
kernel=np.ones((10,10),dtype=np.uint8)#礼帽和黑帽
cvOpen1=cv.morphologyEx(imgOpen,cv.MORPH_TOPHAT,kernel)
cvClose1=cv.morphologyEx(imgClose,cv.MORPH_BLACKHAT,kernel)# 显示
fig,axes=plt.subplots(nrows=2,ncols=3,figsize=(10,8))
axes[0,0].imshow(imgOpen)
axes[0,0].set_title("imgOpen")
axes[0, 1].imshow(cvOpen[:, :, ::-1])
axes[0, 1].set_title("cvOpenImg")
axes[0,2].imshow(cvOpen1)
axes[0,2].set_title("cvOpen1")axes[1,0].imshow(cvClose1)
axes[1,0].set_title("imgClose1")
axes[1, 1].imshow(cvClose[:, :, ::-1])
axes[1, 1].set_title("cvCloseImg")
axes[1,2].imshow(cvClose1)
axes[1,2].set_title("cvClose1")
plt.show()
2.5 核函数
在形态学操作中,核函数(也称为结构元素或内核)是一个小的矩阵,用于定义形态学操作的形状和大小。不同的核函数会产生不同的效果,因此选择适当的核函数对于获得期望的形态学效果非常重要。
在 OpenCV 中,可以使用 cv.getStructuringElement()
函数来创建不同形状和大小的核函数。这个函数返回指定形状和大小的二值矩阵,用于作为形态学操作的核函数。
下面是 cv.getStructuringElement()
函数的一般形式:
cv.getStructuringElement(shape, ksize[, anchor])
shape
: 结构元素的形状,可以是以下之一:cv.MORPH_RECT
:矩形结构元素cv.MORPH_CROSS
:十字形结构元素cv.MORPH_ELLIPSE
:椭圆形结构元素
ksize
: 结构元素的大小,通常是一个元组(rows, cols)
,指定行数和列数。anchor
: 结构元素的锚点。它指示结构元素的中心位置,通常位于结构元素的中心。默认值为(-1, -1)
,表示锚点位于结构元素的中心。
以下是一些例子,演示如何创建不同形状和大小的核函数:
import cv2 as cv
import numpy as np# 创建一个 3x3 的矩形结构元素
rect_kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))# 创建一个 5x5 的十字形结构元素
cross_kernel = cv.getStructuringElement(cv.MORPH_CROSS, (5, 5))# 创建一个 7x7 的椭圆形结构元素
ellipse_kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (7, 7))
这些核函数可以用于形态学操作,比如腐蚀、膨胀、开运算、闭运算等。例如,你可以将这些核函数传递给 cv.erode
、cv.dilate
、cv.morphologyEx
等函数中的 kernel
参数。
细微变化
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties# 读取图像
image = cv.imread('img/useCvOpenxx.jpg', cv.IMREAD_GRAYSCALE)# 创建不同形状和大小的核函数
rect_kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
cross_kernel = cv.getStructuringElement(cv.MORPH_CROSS, (5, 5))
ellipse_kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (7, 7))# 进行腐蚀操作
eroded_rect = cv.erode(image, rect_kernel)
eroded_cross = cv.erode(image, cross_kernel)
eroded_ellipse = cv.erode(image, ellipse_kernel)# 进行膨胀操作
dilated_rect = cv.dilate(image, rect_kernel)
dilated_cross = cv.dilate(image, cross_kernel)
dilated_ellipse = cv.dilate(image, ellipse_kernel)# 设置中文字体
font = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=12)# 显示原始图像和不同核函数下的腐蚀结果和膨胀结果
plt.figure(figsize=(12, 8))plt.subplot(3, 3, 1), plt.imshow(image, cmap='gray'), plt.title('原始图像', fontproperties=font)plt.subplot(3, 3, 2), plt.imshow(eroded_rect, cmap='gray'), plt.title('矩形核腐蚀', fontproperties=font)
plt.subplot(3, 3, 3), plt.imshow(dilated_rect, cmap='gray'), plt.title('矩形核膨胀', fontproperties=font)plt.subplot(3, 3, 5), plt.imshow(eroded_cross, cmap='gray'), plt.title('十字核腐蚀', fontproperties=font)
plt.subplot(3, 3, 6), plt.imshow(dilated_cross, cmap='gray'), plt.title('十字核膨胀', fontproperties=font)plt.subplot(3, 3, 8), plt.imshow(eroded_ellipse, cmap='gray'), plt.title('椭圆核腐蚀', fontproperties=font)
plt.subplot(3, 3, 9), plt.imshow(dilated_ellipse, cmap='gray'), plt.title('椭圆核膨胀', fontproperties=font)plt.show()