形态学操作
图像形态学操作(Mathematical Morphological Operation)是一种基于集合论和数学形态学理论的图像处理方法,主要用于分析和处理图像中物体的形状、结构以及空间关系。 它通常作用于二值图像或灰度图像,通过定义一个称为结构元素(Structuring Element)的小型模板,并利用该模板与图像之间的相互作用,对图像中的目标区域进行膨胀、腐蚀、开运算、闭运算等操作。
形态学操作的核心思想是利用结构元素探测图像中的局部特征,从而实现目标区域的扩张、收缩、噪声去除、边缘提取、孔洞填充以及形状分析等功能。在数字图像处理中,形态学方法具有计算简单、对几何结构敏感等特点,因此广泛应用于图像分割、目标检测、医学图像分析以及计算机视觉任务中。
连通性
在数字图像处理中,连通性(Connectivity)是描述图像中像素之间空间关系的重要概念,主要用于判断哪些像素属于同一个区域或同一个目标。由于数字图像是由离散像素组成的,因此需要定义像素之间"相邻"的规则。通常情况下,只有像素之间存在某种邻接关系,并且像素具有相同或相近的灰度值时,才能认为它们属于同一个连通区域。连通性的概念是后续形态学处理、区域分割、目标检测、边缘分析以及连通区域标记(Connected Component Labeling)的基础。
在二维数字图像中,常见的连通方式主要包括4-连通(4-connectivity)、8-连通(8-connectivity)和m-连通(mixed connectivity)。
4-连通认为一个像素只与上下左右四个方向的像素相邻,例如像素坐标为 (x,y),其邻域为 (x−1,y)、(x+1,y)、(x,y−1)、(x,y+1);8-连通则进一步考虑对角方向,因此包括周围八个像素。8-连通比4-连通能够连接更多区域,但容易产生一些本不应该连接的情况,因此引入了m-连通来避免歧义。简单来说,连通性就是通过定义像素之间的邻接规则,判断图像中的像素是否属于同一个物体。例如在二值图像中,一个白色目标区域内部的所有白色像素如果满足连通条件,就可以被认为是同一个连通区域,这也是图像分割后统计目标数量、面积和形状的重要依据。
图像的膨胀与腐蚀
膨胀
图像膨胀是数学形态学中的一种基本操作,主要作用是使图像中的目标区域扩大、边界向外扩展。它通常应用于二值图像,其中前景目标一般表示为白色像素(值为1),背景表示为黑色像素(值为0)。膨胀操作通过一个称为结构元素(Structuring Element,SE)的模板在图像上移动,当结构元素覆盖区域内存在前景像素时,就会将该位置设置为前景像素,从而使目标区域逐渐扩大。
从数学角度来看,膨胀可以表示为集合的 Minkowski 和(集合加法):

膨胀的主要作用:
(1)连接断开的目标区域
在实际图像中,由于噪声、光照变化或者采集误差,一个完整目标可能出现断裂。例如文字识别中,字符笔画之间可能存在间断,通过膨胀可以填补这些小间隙,使字符重新连接。
(2)填补目标内部的小孔洞
如果目标内部存在一些小的黑色区域,膨胀可以扩大周围白色区域,使这些孔洞逐渐消失。
(3)增强目标边缘
膨胀会使目标尺寸增加,因此可以突出目标轮廓,常用于目标检测前的预处理。
在医学图像处理中,膨胀主要用于连接断裂区域、填补边界缺失以及恢复目标结构完整性。例如,在血管分割中,由于血管细小且灰度变化明显,分割结果可能出现血管断裂,膨胀后可以重新连接断开的血管区域。
在医学图像分割网络(例如U-Net)输出的结果中,预测掩膜(Mask)通常也存在边界缺失的问题。例如模型预测的肿瘤区域可能比真实区域略小,膨胀可以适当扩展预测区域,使目标轮廓更加完整。
腐蚀
腐蚀与膨胀作用相反,它的作用是缩小目标区域,使目标边界向内收缩。腐蚀同样依赖结构元素,但判断条件与膨胀相反:只有当结构元素完全覆盖的位置全部属于目标区域时,该位置才保留为目标像素,否则被设置为背景。数学表达为:

其中,A表示输入图像,B表示结构元素。这个公式表示:当结构元素移动到某个位置后,如果结构元素覆盖区域完全包含在目标区域A内部,那么中心位置才会保留下来。
腐蚀的主要作用:
(1)去除小噪声
在二值图像中,如果存在孤立的小白点,腐蚀会因为结构元素无法完全覆盖该区域,使这些小区域消失。因此腐蚀常用于去除前景噪声。
(2)分离粘连目标
例如两个物体距离很近,经过二值化后可能连接在一起。腐蚀可以收缩目标边界,使两个目标分离,方便后续目标检测。
(3)提取目标骨架或边界
通过不断腐蚀,可以逐渐减少目标区域,从而分析目标的结构特征。
在医学图像处理中,腐蚀最常用于去除小尺寸噪声和分离粘连区域。例如,在医学图像二值化过程中,由于噪声影响,可能会产生一些孤立的小白点,这些区域通常不是有效的组织结构,通过腐蚀可以将这些小区域删除。另外,在细胞分割或者血管分割中,多个目标可能因为距离过近而连接在一起,腐蚀可以收缩目标边界,使相互连接的区域产生间隔,从而方便后续的连通区域分析。
基于opencv,以二值图像为例,一段简单的代码示例如下所示:
python
import cv2
import numpy as np
# 读取灰度图
img = cv2.imread("binary.png", cv2.IMREAD_GRAYSCALE)
# 创建结构元素
kernel = np.ones((3,3), np.uint8)
# 膨胀操作
dilation = cv2.dilate(
img,
kernel,
iterations=1
)
# 腐蚀操作
erosion = cv2.erode(
img,
kernel,
iterations=1
)
# 显示结果
cv2.imshow("Original", img)
cv2.imshow("Dilation", dilation)
cv2.imshow("Erosion", erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
开闭运算
开运算
开运算(Opening Operation)是由形态学中的**腐蚀(Erosion)后进行膨胀(Dilation)**组成的一种复合操作,即先利用结构元素对图像进行腐蚀,使目标区域缩小并去除一些较小的前景区域,然后再进行膨胀,使剩余目标恢复到接近原来的大小。
开运算的核心原理是利用腐蚀操作筛选出能够完全容纳结构元素的目标区域,再通过膨胀恢复其整体形状,因此它不会简单地恢复被删除的小区域。对于二值图像而言,开运算主要用于去除小尺寸噪声、断开细小连接、平滑目标边界 。例如,在字符识别或目标分割中,如果前景区域中存在一些孤立的小白点噪声,腐蚀阶段会将这些无法满足结构元素要求的小区域删除,而后续膨胀只会恢复较大的主体目标,因此可以在保持主要目标形状的同时有效去除噪声。此外,开运算还具有消除突出部分的作用,可以使目标轮廓更加平滑。
开运算 = 先腐蚀,后膨胀 → 去除小目标、小噪声("先破坏,再恢复")
在医学图像分割中,开运算通常用于分割前的图像预处理或者分割后的噪声清理阶段。例如,在医学图像二值化后,目标区域可能包含很多孤立的小噪声。这些小点可能来自扫描噪声或者阈值分割误差。开运算首先通过腐蚀删除这些无法满足结构元素要求的小区域,然后通过膨胀恢复主要目标,因此能够去除孤立噪声、平滑目标边缘、删除细小突起结构。
典型应用包括:MRI脑部图像中去除非脑组织噪声、细胞图像中去除背景杂点、 CT骨骼分割中去除错误检测区域。
闭运算
闭运算(Closing Operation)与开运算相反,它由**膨胀(Dilation)后进行腐蚀(Erosion)**组成,即先利用结构元素扩大目标区域,使目标边界向外扩展并填补小孔洞、连接断裂区域,然后再通过腐蚀将目标尺寸恢复到接近原始大小。
闭运算的核心原理是利用膨胀阶段填充目标内部的小间隙和连接相邻区域,再通过腐蚀去除多余扩展部分,因此能够保留目标整体结构。闭运算主要用于填补目标内部的小孔洞、连接相邻但断开的区域、平滑目标内部边界。例如,在二值化后的文字图像中,由于光照不均或噪声影响,字符笔画可能出现断裂,闭运算可以通过膨胀先连接这些断裂部分,再腐蚀恢复字符大小,使文字结构更加完整。
闭运算 = 先膨胀,后腐蚀 → 填补空洞、连接断裂("先连接,再修复")
它主要用于填补目标内部空洞以及连接断裂区域,因此在医学分割中非常常见。例如,在肿瘤分割中,由于肿瘤内部灰度不均:模型可能认为中间区域不是肿瘤。闭运算可以先膨胀填补内部空洞:然后腐蚀恢复边界,使目标区域更加完整。
闭运算常用于:肿瘤区域填充、血管连续性增强、细胞区域完整化、分割Mask孔洞修复。
二者的区别与联系
从形态学角度看,开运算更关注删除不满足结构元素的小区域,而闭运算更关注保留目标并填补内部缺陷。在实际图像处理中,两者经常用于二值分割后的后处理,例如医学图像中去除细小噪点、填补血管或细胞区域中的空洞,以及深度学习语义分割结果中的边界优化。
基于opencv的简单代码示例:
python
import cv2
import numpy as np
# 读取二值图像
img = cv2.imread("binary.png", cv2.IMREAD_GRAYSCALE)
# 创建结构元素(3×3矩形)
kernel = np.ones((3, 3), np.uint8)
# 开运算:先腐蚀,再膨胀
opening = cv2.morphologyEx(
img,
cv2.MORPH_OPEN,
kernel,
iterations=1
)
# 闭运算:先膨胀,再腐蚀
closing = cv2.morphologyEx(
img,
cv2.MORPH_CLOSE,
kernel,
iterations=1
)
# 显示结果
cv2.imshow("Original", img)
cv2.imshow("Opening", opening)
cv2.imshow("Closing", closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
黑帽与礼帽变换
黑帽变换
黑帽变换(Black-hat)主要用于提取图像中的暗区域信息。黑帽变换的计算方式是:

其中:
f∙b表示闭运算;
f表示原始图像。
闭运算的过程是"先膨胀,再腐蚀",它会填补目标内部的小孔洞,并连接一些断裂区域,因此闭运算后的图像通常会保留背景和较大的结构,同时消除小尺寸暗区域。
黑帽变换通过计算闭运算结果−原始图像,得到那些被闭运算填补的暗区域。简单理解,黑帽变换关注的是寻找比周围背景更暗、但是尺寸较小的目标区域。
例如,一张灰度图像背景为200,而其中存在灰度值为50的小黑点,闭运算会将这些小暗区域填充,使图像更加均匀,而黑帽变换通过差值就可以把这些暗区域提取出来。
黑帽变换主要作用包括:
(1)检测暗色缺陷
例如工业检测中,金属表面的划痕、裂纹、凹陷通常表现为暗区域,可以使用黑帽增强。
(2)文字和字符增强
在扫描文本处理中,文字通常比背景暗,通过黑帽变换可以增强文字区域,提高后续OCR识别效果。
(3)突出局部暗区域
例如医学图像中某些组织结构、血管区域可能表现为暗区域,黑帽可以增强这些细节,使其与背景产生更明显的灰度差异,提高分割或检测效果。
礼帽变换
礼帽变换(Top-hat)是数学形态学中的一种图像增强操作 ,它本质上是利用原始图像与开运算结果之间的差值来提取图像中的亮细节信息。其数学表达式为:

其中,f表示原始图像,b表示结构元素,f∘b表示对图像进行开运算的结果。由于开运算的过程是"先腐蚀,再膨胀",它会去除比结构元素小的亮区域,因此开运算后的图像通常保留了图像中的主要背景和较大目标,而一些细小的亮区域会被消除。礼帽变换通过计算原图减去开运算结果,就能够得到那些被开运算删除的亮区域,因此礼帽变换也称为白顶帽(White Top-hat)。简单理解,礼帽变换关注的是寻找比周围背景更亮、但是尺寸较小的目标区域。
例如,在一张灰度图像中,如果背景灰度为100,而某些小目标区域灰度为200,那么开运算会认为这些小亮区域属于噪声或细节并将其去除,而礼帽变换会通过差值重新提取出来 。因此,礼帽变换常用于增强图像中的小亮目标。
礼帽变换的主要作用包括:
(1)突出小尺寸亮目标
例如工业检测中的金属表面缺陷、PCB焊点检测、医学图像中的小血管结构等,这些目标通常表现为局部亮区域,礼帽变换可以将它们从复杂背景中提取出来。
(2)消除不均匀背景影响
在实际拍摄过程中,光照可能不均匀,例如显微镜图像或者工业相机采集的图像,背景亮度可能从左到右逐渐变化。礼帽变换可以去除缓慢变化的背景,使局部亮区域更加明显。
(3)增强局部对比度
由于礼帽结果只保留亮区域与背景之间的差异,因此可以增强细小目标和背景之间的灰度差异。
在医学图像处理中,礼帽变换主要用于提取比周围区域更亮的小目标。医学图像中很多重要结构具有局部高亮特点,例如:显微镜下的细胞核、血管中的亮区域、X光中的微小钙化点。
二者的区别与联系
礼帽变换和黑帽变换都是基于形态学运算的图像细节增强方法,二者本质上都是通过原始图像与形态学处理结果之间的差值来提取局部特征。二者的主要区别在于提取目标不同:
礼帽变换通过"原图减去开运算结果"得到比周围区域更亮的小尺寸目标,主要用于增强亮区域细节。
黑帽变换通过"闭运算结果减去原图"得到比周围区域更暗的小尺寸目标,主要用于突出暗区域细节。
二者的联系在于都依赖结构元素(Structuring Element)的选择,并利用开运算和闭运算对不同尺度的图像结构进行筛选,因此结构元素的大小和形状会直接影响检测结果。在实际应用中,礼帽常用于提取亮点、光斑、焊点等局部高灰度目标,而黑帽常用于检测裂纹、文字、凹陷等低灰度区域,它们共同构成了形态学处理中针对局部亮暗变化的重要工具。
基于opencv的简单代码示例:
python
import cv2
import numpy as np
# 读取灰度图像
img = cv2.imread(
"image.png",
cv2.IMREAD_GRAYSCALE
)
# 创建结构元素
kernel = cv2.getStructuringElement(
cv2.MORPH_RECT,
(15,15)
)
# 礼帽变换
tophat = cv2.morphologyEx(
img,
cv2.MORPH_TOPHAT,
kernel
)
# 黑帽变换
blackhat = cv2.morphologyEx(
img,
cv2.MORPH_BLACKHAT,
kernel
)
# 显示结果
cv2.imshow(
"Original",
img
)
cv2.imshow(
"Top Hat",
tophat
)
cv2.imshow(
"Black Hat",
blackhat
)
cv2.waitKey(0)
cv2.destroyAllWindows()