计算机视觉(一)——形态学操作:腐蚀、膨胀、开闭运算、形态学梯度、顶帽与黑帽

  • Post author:
  • Post category:其他


形态学:即数学形态学,图像处理过程中一个非常重要的研究方法。


形态学主要从图像内部提取分量信息,该分量信息通常对于表达和描绘图像的特征具有重要意义

,通常是图像理解时所使用的

最本质的形状特征

形态学处理在

视觉检测、文字识别、医学图形处理、图像压缩编码

领域都有非常重要的作用。

形态学操作主要包含:

腐蚀、膨胀、开运算、闭运算、形态学梯度运算、顶帽运算、黑帽运算

。本文将对这些算法展开详细介绍。

(其中,膨胀和腐蚀是图像处理中最基本的形态学操作手段,常常被组合起来实现一些复杂的图像形态学操作)





一、腐蚀和膨胀



1.腐蚀

顾名思义,腐蚀操作是将物体的边缘加以腐蚀。具体的操作方法是拿一个宽m,高n的矩形作为模板,对图像中的每一个像素x做如下处理:像素x至于模板的中心,根据模版的大小,遍历所有被模板覆盖的其他像素,修改像素x的值为所有像素中最小的值。这样操作的结果是会将图像外围的突出点加以腐蚀。如下图的操作过程:

腐蚀原理


腐蚀的原理

简单说就是,在背景为黑(0),前景为白(1)的图像中,核(1)与其覆盖的图像部分做“与”操作,如果全为1,则该像素点为1,否则为0;也就是1不容易得到,白色部分更少了,白色部分被腐蚀了。



2.膨胀

膨胀操作与腐蚀操作相反,是将图像的轮廓加以膨胀。操作方法与腐蚀操作类似,也是拿一个矩形模板,对图像的每个像素做遍历处理。不同之处在于修改像素的值不是所有像素中最小的值,而是最大的值。这样操作的结果会将图像外围的突出点连接并向外延伸。如下图的操作过程:

膨胀的原理


膨胀的原理

简单说就是,在背景为黑(0),前景为白(1)的图像中,核(1)与其覆盖的图像部分做“与”操作,如果全为0,则该像素点为0,否则为1;也就是1容易得到,图像更多的地方变白了,白色部分膨胀了。



3.代码实现(python)

引入库

import cv2
import numpy as np
import matplotlib
import matplotlib.pyplot as plt #最后两个库为了画子图使用

腐蚀操作由cv2自带的函数erode实现,其输入参数为原始矩阵以及核。膨胀操作由cv2自带函数dilate实现,输入参数同理于erode。


对于新手,强烈建议自己写代码实现erode和dilate这两个函数,因为函数本身原理简单,并不难实现,而且效果明显,成就感强,能进一步激发计算机视觉的学习兴趣。

img = cv2.imread('psma.PNG') #读取图片

kernel = np.ones((25, 25), np.uint8)    # 矩形结构

erosion = cv2.erode(img, kernel)   # 腐蚀
dilation = cv2.dilate(img, kernel) # 膨胀

titles = ['Original', 'Erosion', 'Dilation']
images = [img, erosion, dilation]
plt.figure(dpi=200) #指定输出像素大小
for i in range(3):
    plt.subplot(1,3, i + 1)
    plt.imshow(images[i])
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

在上述代码中对于kernel的定义还有其他形式,这个核也叫结构元素,因为形态学操作其实也是应用卷积来实现的。结构元素可以是矩形、椭圆、十字形,可以用 cv2.getStructuringElement() 来生成不同形状的结构元素,比如:

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))  # 矩形结构
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))  # 椭圆结构
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (5, 5))  # 十字形结构

不同的核结构

在本文举例中,不同的核实验结果差别不大。

腐蚀与膨胀的最终效果为:

腐蚀与膨胀



二、开运算和闭运算



1.开运算

先腐蚀后膨胀,用来

消除小物体、在纤细点处分离物体、平滑较大物体的边界

的同时并不明显改变其面积,消除物体表面的突起。示例如下:

开运算



2.闭运算

闭操作就是对图像先膨胀,再腐蚀。闭操作的结果一般是可以将许多靠近的图块相连称为一个无突起的连通域。原图首先经过膨胀操作,将两个分开的图块结合起来(注意我用偏白的灰色图块表示由于膨胀操作而产生的新的白色)。接着通过腐蚀操作,将连通域的边缘和突起进行削平(注意我用偏黑的灰色图块表示由于腐蚀被侵蚀成黑色图块)。最后得到的是一个无突起的连通域(纯白的部分)。

在这里插入图片描述



3.代码实现(python)

引入库

import cv2
import numpy as np
import matplotlib
import matplotlib.pyplot as plt #最后两个库为了画子图使用


cv2.morphologyEx(src, op, kernel)

可以进行各类形态学的变化


参数说明:

src传入的图片
op进行变化的方式
kernel表示核

这其中不同的op对应不同的操作:

————MORPH_OPEN – 开运算(Opening operation)

————MORPH_CLOSE – 闭运算(Closing operation)

————MORPH_GRADIENT -形态学梯度(Morphological gradient)

————MORPH_TOPHAT – “顶帽”(“Top hat”)

————MORPH_BLACKHAT – “黑帽”(“Black hat“)

后三个参数“形态学梯度”、“顶帽”、“黑帽”的使用将在第三部分进行讲述。

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))  # 定义结构元素

img1 = cv2.imread('j_noise_out.bmp') #开运算原始图像
img2 = cv2.imread('j_noise_in.bmp')  #闭运算原始图像

opening = cv2.morphologyEx(img1, cv2.MORPH_OPEN, kernel)  # 开运算
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)  # 闭运算

titles = ['Original_OP','Opening','Original_CL','Closing']
images = [img1, opening, img2, closing]
plt.figure(dpi=150) #指定输出像素大小
for i in range(4):
    plt.subplot(1, 4, i + 1)
    plt.imshow(images[i])
    plt.title(titles[i], fontsize=10)
    plt.xticks([]), plt.yticks([])
plt.show()

最后输出图像结果为:

在这里插入图片描述



三、形态学梯度、顶帽运算、黑帽运算



1.形态学梯度

形态学梯度(Morphological Gradient)为

膨胀图与腐蚀图之差

,对二值图像进行这一操作可以将团块的边缘突出出来。我们可以用形态学梯度来

保留物体的边缘轮廓

#形态学梯度:膨胀图减去腐蚀图,dilation - erosion,这样会得到物体的轮廓
img = cv2.imread('psma.PNG')
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
titles = ['img', 'gradient']
images = [img, gradient]
plt.figure(dpi=200) #指定输出像素大小
for i in range(2):
    plt.subplot(1, 2, i + 1)
    plt.imshow(images[i])
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述



2.顶帽运算

顶帽运算(Top Hat)又常常被译为”礼帽“运算。为

原图像与上文刚刚介绍的“开运算“的结果图之差



因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。

顶帽运算的作用是可以

提取噪声,突出原图像中比周围亮的部分

。(因为开运算本身可以去除一些孤立点,细微连接,毛刺等细节,所以这些细节就可以通过顶帽操作来提取出来)

#顶帽:原图减去开运算后的图:src - opening
img = cv2.imread('psma_noise_out.PNG')
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20,20))# 定义结构元素
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
titles = ['img', 'tophat']
images = [img, tophat]
plt.figure(dpi=150) #指定输出像素大小
for i in range(2):
    plt.subplot(1, 2, i + 1)
    plt.imshow(images[i])
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述



3.黑帽运算

黑帽(Black Hat)运算为

“闭运算”的结果图与原图像之差

。黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。

黑帽操作的作用是

突出原图像中比周围暗的区域。

(比如闭运算本身可以填补物体内部的一些黑洞,这些黑洞就可以通过黑帽运算来凸显)。

#黑帽:闭运算后的图减去原图:closing - src
img = cv2.imread('psma_noise_in.png')
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (60,60))
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
titles = ['img', 'blackhat']
images = [img, blackhat]
plt.figure(dpi=180) #指定输出像素大小
for i in range(2):
    plt.subplot(1, 2, i + 1)
    plt.imshow(images[i])
    plt.title(titles[i], fontsize=8)
    plt.xticks([]), plt.yticks([])
plt.show()

在这里插入图片描述



版权声明:本文为qq_41433002原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。