【图像处理】OpenCV+Python图像处理入门教程(七)图像形态学操作

       图像形态学主要从图像内提取分量信息,该分量信息通常对表达图像的特征具有重要意义。例如,在车牌号码识别中,能够使用形态学计算其重要特征信息,在进行识别时,只需对这些特征信息运算即可。图像形态学在目标视觉检测、医学图像处理、信息压缩提取等领域都有重要的应用。接下来,这篇随笔介绍使用OpenCV进行图像处理的第七章 图像形态学操作。

7  图像形态学操作

       形态学操作主要包括:腐蚀、膨胀、开运算、闭运算、形态学梯度运算、顶帽运算(礼帽运算)、黑帽运算等操作。其中,腐蚀和膨胀是形态学中最基本的运算,其他方法都是基于这两种运算组合而成的。

7.1  腐蚀

腐蚀是最基本的形态学操作之一,能够消除图像中的边界,使图像沿边界向内收缩。

腐蚀时,有一个结构元逐个像素扫描原图像,根据结构元中心与原图像的关系来进行腐蚀。该结构元也被成为核。

核能够自定义生成,也可以使用函数cv2.getStructuringElement()构造不同结构的核,该核函数的shape参数有多种,能够生成不同的核,但相比于自定义核就稍有局限,所以本章内容全部默认基于自定义核,当然朋友们也可以尝试使用cv2.getStructuringElement()核函数来构造特定结构的核。

在OpenCV中,使用cv2.erode()函数进行腐蚀操作,举例程序如下:

 1 #使用函数cv.erode()完成图像腐蚀
 2 import cv2
 3 import numpy as np
 4 o=cv2.imread('E:\python_opencv/fushi.jpg',cv2.IMREAD_UNCHANGED)
 5 kernel=np.ones((5,5),np.uint8)   #核大小为5×5
 6 erosion=cv2.erode(o,kernel)      #使用kernel对原图像腐蚀
 7 cv2.imshow('orriginal',o)
 8 cv2.imshow('erosion',erosion)
 9 cv2.waitKey()
10 cv2.destroyAllWindows()

在上面程序中,读取图片后先生成kernel结构元,是一个5×5大小且元素均为1的矩阵,再使用cv2.erode()函数进行腐蚀操作,运行结果如图所示:

左图是原始图像,右图是腐蚀图像。可以看到,腐蚀操作能将图片中的毛刺等腐蚀消掉。下面我们调节cv2.erode()函数的迭代次数,观察不同kernel核对图像的腐蚀效果。程序如下所示:

 1 #调节函数cv2.erode()的参数,观察不同参数控制下的图像腐蚀效果
 2 import cv2
 3 import numpy as np
 4 o=cv2.imread('E:\python_opencv/fushi.jpg',cv2.IMREAD_UNCHANGED)
 5 kernel=np.ones((9,9),np.uint8)    #核大小为9×9
 6 #参数iteration等于5,是对cv2.erode()的迭代次数进行控制,让其迭代5次
 7 erosion=cv2.erode(o,kernel,iterations=5)  
 8 cv2.imshow('orriginal',o)
 9 cv2.imshow('erosion',erosion)
10 cv2.waitKey()
11 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为迭代5次后的腐蚀处理结果,图像已明显向内收缩。

在这段代码中,使用了更大的核、更多的迭代次数,所以图像被腐蚀的更严重了。

 

7.2  膨胀

膨胀操作是腐蚀的逆运算,能对图像从边界处向外扩张。如果图片中的两个目标相距较近,膨胀后两个目标可能会连通。膨胀操作经常应用在图像分割后的填充任务中。

图像膨胀也是使用一个kernel核,逐一对原图像素进行扫描,判断它们的位置关系来实现的。

在OpenCV中,使用cv2.dilate()函数进行膨胀操作,举例程序如下:

 1 #使用函数cv2.dilate()完成图像膨胀操作
 2 import cv2
 3 import numpy as np
 4 o=cv2.imread('E:\python_opencv/pengzhang.jpg',cv2.IMREAD_UNCHANGED)
 5 kernel=np.ones((9,9),np.uint8)   #核大小为9×9
 6 dilation=cv2.dilate(o,kernel)    #使用kernel对原图像膨胀
 7 cv2.imshow('orriginal',o)
 8 cv2.imshow('dilation',dilation)
 9 cv2.waitKey()
10 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为图像膨胀处理结果,图像已由边界处向外扩张。

下面我们调节cv2.dilate()函数的迭代次数,观察不同kernel核对图像的腐蚀效果。代码如下:

 1 #调节函数cv2.dilate()的参数,观察不同参数控制下的图像膨胀效果
 2 import cv2
 3 import numpy as np
 4 o=cv2.imread('E:\python_opencv/pengzhang.jpg',cv2.IMREAD_UNCHANGED)
 5 kernel=np.ones((5,5),np.uint8)    #核大小为5×5
 6 #参数iteration等于9,是对cv2.dilate()的迭代次数进行控制,迭代9次
 7 dilation=cv2.dilate(o,kernel,iterations=9)
 8 cv2.imshow('orriginal',o)
 9 cv2.imshow('dilation',dilation)
10 cv2.waitKey()
11 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为迭代9次后的膨胀处理结果,图像已明显由边界处向外扩张。

 

7.3  开运算

开运算是先将图像腐蚀,再对腐蚀后的结果进行膨胀。开运算常应用于图像去噪等。

OpenCV提供了形态学函数cv2.morphologyEx()来实现各种形态学运算,内部op参数如下:

所以,使用函数cv2.morphologyEx()实现开运算举例代码如下:

 1 #使用函数cv2.morphologyEx()实现开运算
 2 import cv2
 3 import numpy as np
 4 img=cv2.imread('E:\python_opencv/kaiyunsuan.jpg')
 5 kernel=np.ones((20,20),np.uint8)  
 6 #cv2.morphologyEx()函数的op参数设置为cv2.MORPH_OPEN
 7 rst=cv2.morphologyEx(img,cv2.MORPH_OPEN,kernel)
 8 cv2.imshow('img',img)
 9 cv2.imshow('rst',rst)
10 cv2.waitKey() 
11 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为开运算处理结果,图像两个目标已断开连接。

  

 

7.4  闭运算

闭运算是先将图像膨胀,再对膨胀后的结果进行腐蚀。闭运算常应用于去除图像上的小黑点、或者连接图中多个相距较近的目标等。

使用函数cv2.morphologyEx()实现闭运算,举例代码如下:

 1 #使用函数cv2.morphologyEx()实现闭运算
 2 import cv2
 3 import numpy as np
 4 img=cv2.imread('E:\python_opencv/biyunsuan.jpg')
 5 kernel=np.ones((10,10),np.uint8)
 6 #cv2.morphologyEx()函数的op参数设置为cv2.MORPH_CLOSE
 7 rst=cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel,iterations=3)
 8 cv2.imshow('img',img)
 9 cv2.imshow('rst',rst)
10 cv2.waitKey() 
11 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为闭运算处理结果,图像两个目标经过运算后连接在一起。

 

7.5  形态学梯度运算

形态学梯度运算是用图像的膨胀图像减去腐蚀图像的操作。形态学梯度运算经常用于获取前景图像的边缘信息。

使用函数cv2.morphologyEx()实现形态学梯度运算,举例代码如下:

 1 #使用函数cv2.morphologyEx()实现形态学梯度运算
 2 import cv2
 3 import numpy as np
 4 img=cv2.imread('E:\python_opencv/biyunsuan.jpg',cv2.IMREAD_UNCHANGED)
 5 kernel=np.ones((5,5),np.uint8)
 6 #cv2.morphologyEx()函数的op参数设置为cv2.MORPH_GRADIENT
 7 rst=cv2.morphologyEx(img,cv2.MORPH_GRADIENT,kernel)
 8 cv2.imshow('img',img)
 9 cv2.imshow('rst',rst)
10 cv2.waitKey() 
11 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为形态学梯度运算处理结果,获得了前景图像的边缘轮廓。

 

7.6  礼帽运算

礼帽运算是用原始图像减去其开运算图像的操作。礼帽运算经常用于获取图像的噪声信息和比原图像更亮的局部边缘信息。

使用函数cv2.morphologyEx()实现礼帽运算,举例代码如下:

 1 #使用函数cv2.morphologyEx()实现礼帽运算
 2 import cv2
 3 import numpy as np
 4 img=cv2.imread('E:\python_opencv/lena.jpg',cv2.IMREAD_UNCHANGED)
 5 kernel=np.ones((5,5),np.uint8)
 6 #cv2.morphologyEx()函数的op参数设置为cv2.MORPH_TOPHAT
 7 rst=cv2.morphologyEx(img,cv2.MORPH_TOPHAT,kernel)
 8 cv2.imshow('img',img)
 9 cv2.imshow('rst',rst)
10 cv2.waitKey() 
11 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为礼帽运算处理结果。

 

7.7  黑帽运算

黑帽运算是用闭运算图像减去原始图像的操作。黑帽运算能够获取图像内部的小黑点或小孔,得到比原图像更暗的边缘信息。

使用函数cv2.morphologyEx()实现黑帽运算,举例代码如下:

 1 #使用函数cv2.morphologyEx()实现黑帽运算
 2 import cv2
 3 import numpy as np
 4 img=cv2.imread('E:\python_opencv/lena.jpg',cv2.IMREAD_UNCHANGED)
 5 kernel=np.ones((5,5),np.uint8)
 6 #cv2.morphologyEx()函数的op参数设置为cv2.MORPH_BLACKHAT
 7 rst=cv2.morphologyEx(img,cv2.MORPH_BLACKHAT,kernel)
 8 cv2.imshow('img',img)
 9 cv2.imshow('rst',rst)
10 cv2.waitKey() 
11 cv2.destroyAllWindows()

运行结果如下图,左为原图像,右为黑帽运算处理结果。

可以看到,黑帽运算得到了比礼帽运算更暗的边缘信息。

 

这次内容就分享到这里了,下次继续更新第8章 图像梯度与Canny边缘检测,希望与各位老师和小伙伴们交流学习~