文章目录
引言
形态学一词通常表示生物学的一个分支,该分支主要研究植物的形态和结构。我们使用同一词语表示形态学的内容,将数学形态学作为工具从图像中提取表达和描绘区域。
9.1预备知识
这里的形态学并非指生物学的那一个分支,而是数学形态学的内容,将数学形态学作为工具从图像中提取表达和描绘区域形状的有用图像分量,如边界、骨架和凸壳等。这一章学习将从输入输出均为图像的图像处理转为输入是图像输出是这些图像中提取属性的处理。类似形态学及与其相关概念这样的工具数学基础的基石,用于提取图像中的内涵。
9.2腐蚀和膨胀
我们通过研究腐蚀和膨胀这两个操作来开始讨论形态学。这些操作是形态学处理的基础。事实上,本章中讨论的许多形态学算法都是以这两种原始操作为基础的。
9.2.1腐蚀
集合A和B都在Z中,B对A的腐蚀,定义为:
该式指出了B对A的腐蚀是一个用z平移的B包含在A中的所有的点z的集合。我们假设B是一个结构元,从上面对结构元的描述我们知道了B不与A共享公共元素。由此可以将公式等价为:
9.2.2膨胀
集合A和B都在Z中,B对A的膨胀,定义为:
这个公式是以B关于它的原点的映像,并且以z对映像进行平移为基础的,与腐蚀相反,B对A的膨胀是所有位移z的集合,因此(B)和A至少是有一个元素是重叠的,上式也可以等价为:
下面用代码部分实现腐蚀和膨胀的功能:
# 图像腐蚀
def etch(img):
h=img.shape[0]
w=img.shape[1]
img1=np.zeros((h,w),np.uint8)
for i in range (1,h-1):
for j in range (1,w-1):
min=img[i,j]
for k in range (i-1,i+2):
for l in range (j-1,j+2):
if k<0|k>=h-1|l<0|l>=w-1:
continue
if img[k,l]<min:
min=img[k,l]
img1[i,j]=min
return img1
# 图像膨胀
def expand(img):
h=img.shape[0]
w=img.shape[1]
img1=np.zeros((h,w),np.uint8)
for i in range (1,h-1):
for j in range (1,w-1):
max=img[i,j]
for k in range (i-1,i+2):
for l in range (j-1,j+2):
if k<0|k>=h-1|l<0|l>=w-1:
continue
if img[k,l]>max:
max=img[k,l]
img1[i,j]=max
return img1
image = cv.imread("") # 输入图像,根据实际情况而改变路径
caijianimage=caijian(image) # 裁剪图像大小
grayimage = rgb2gray(caijianimage) # 转灰
otsuimage = otsu(grayimage) # 二值化
etchimage=etch(otsuimage) # 腐蚀
expandimage=expand(otsuimage) # 膨胀
cv.imshow("caijianimage",caijianimage) # 输出裁剪图像相当于原图
cv.imshow("grayimage",grayimage) # 输出灰度图
cv.imshow("otsuimage",otsuimage) # 输出二值化图像
cv.imshow("etchimage",etchimage) # 输出腐蚀图像
cv.imshow("expandimage",expandimage) # 输出膨胀图像
cv.waitKey(0)
cv.destroyAllWindows()
可以观察实验结果如下,来进行分析
实验分析,腐蚀缩小或细化了二值图像中的物体,我们可以将腐蚀看成是形态学滤波操作,这种操作将小于结构元的图像细节从图像中去除了。与腐蚀不同,腐蚀是一种收缩或细化操作,膨胀则会增长或粗化二值图像中的物体。
9.3开操作和闭操作
正如看到的那样,膨胀会扩大一幅图像的组成部分,而腐蚀会缩小一幅图像的组成部分。在这里我们将讨论另外两个重要的形态学操作,开操作与闭操作。开操作一般会平滑物体的轮廓、断开较窄的并且消除细的突出物。闭操作也是会平滑轮廓的一部分,但是与开操作相反。
9.3.1开操作
结构元B对集合A的开操作可以表示为:
因此B对A的开操作就是B对A的腐蚀,紧接着用B对结果进行膨胀。
9.3.2闭操作
结构元B对集合A的闭操作,定义为:
则B对集合A的闭操作就是B对A膨胀,接着对结果进行腐蚀。
下面用代码部分来是实现图像的开操作与闭操作,观察实验结果来进行分析。
# 图像的开闭操作
def open_image(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
cv.imshow("binaryzation", binary)
kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
binary = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel)
cv.imshow("open", binary)
def close_image(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
kernel = cv.getStructuringElement(cv.MORPH_RECT, (5, 5))
binary = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernel)
cv.imshow("close", binary)
src = cv.imread("")
cv.imshow("original", src)
open_image(src)
close_image(src)
cv.waitKey(0)
cv.destroyAllWindows()
实验结果如下
分析:正如理论知识一样开操作会平滑物体的轮廓,并且消除突出物,闭操作通常会拟合间断和沟壑,消除小的孔洞。
9.4一些基本的形态学算法
9.4.1边界提取
集合A的边界可以通过先用B对A的腐蚀,然后求A和腐蚀结果至今的集合差得到:
9.4.2孔洞填充
孔洞可以被定义为由前景像素相连接的边界所包围的一个背景区域。令A表示一个集合,其元素是8连通的边界,每个边界包围一个背景区域,当给定每个孔洞一个点后,目的就是用1填充所有的孔洞。除了在每一个孔洞中对应于X中的位置给定的点外,这一点已经被置1了,从形成一个由0组成的阵列X开始,用如下过程使得1填充所有的孔洞。
如果上一个和现个相等,则算法在迭代的第k步结束。Xk 和A的并集包含被填充的集合和它的边界。
9.4.3连通量的提取
在前面的章节里有学习过连通性和连通分量,从二值图像中提取连通分量是许多自动图像分析应用的核心,令A是包含一个或多个连通分量的集合,并形成一个阵列,除了对应于A中每个连通分量中的一个点的已知的每一个位置处我们已经置1外,该阵列的所有其他元素均为0,可由下面的迭代过程达到这个目的:
如果上一个和现个相等,迭代过程结束,X包含输入图像中的所有的连通分量。
9.4.4凸壳
集合A内连接任意两个点的直线段都在A的内部,则称集合A的凸形的。任意集合S的凸壳H是包含于S的最小凸集。集合差H-S称为S的凸缺。
执行过程为:
9.4.5细化
结构元对于集合A的细化,由击中或击不中变换来定义时:
定义结构元素序列为
旋转后的形式。为此可以将细化公式重新定义为:
9.4.6粗化
粗化和细化在形态学上是对偶过程,定义为
与细化一样粗化也可以定义为一个系列操作: