数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。
这是我们在进行图像处理时十分常见的算法工具,在实际中有着非常广泛的应用。
下面就先介绍下二值形态学中的两个重要操作--腐蚀与膨胀。
所谓二值腐蚀,就是对一个二值图进行腐蚀操作。我们对一个二值图像进行腐蚀操作首先需要一个模板核。模板核由一个二值矩阵组成,当中还定义了一个原点,表示核的核心。
接下来,对于二值图像的每一个像素点(无论0还是1),我们将他与模板核的核心对齐,查看模板核中所有值为1的格点组成的图像是否被完全包含在那个二值图像中。如果是,则将该像素点更新为1,否则,更新为0。
通俗的讲,其实就是用我们的模板来对图像进行检测,以便找出图像内部可以放得下该基元的区域。
这个过程的效果是消除边界点,使得边界向内部收缩。
集合A被B腐蚀,表示为A\Theta B={c|B+c\subset A }
其中A为待腐蚀的图像,B为模板向量。
比如二值图像:
S=\begin{bmatrix}0&1&0&1&0\\0&1&1&0&1\\0&1&1&1&0\end{bmatrix}
以及模板:
E=\begin{bmatrix}1&0\\1&1_\triangle\end{bmatrix}
其中\ _\triangle表示模板的原点。
那么E对S腐蚀的结果就为:
S\Theta E=\begin{bmatrix}0&0&0&0&0\\0&0&1&0&0\\0&0&1&1&0\end{bmatrix}
本来想用pil实现下的,然而突然想通了,既然OpenCV有实现好的函数,为何还要用pil折腾呢?于是就用OpenCV的python接口体验下效果:(python接口的安装只需直接apt-get install python-opencv即可)
#coding:utf-8
import numpy as np
import cv2
im=cv2.imread('test.jpg',cv2.IMREAD_GRAYSCALE)#读取图像
thresh,im=cv2.threshold(im,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)#用OTSU自动获取阈值并进行二值化,第一个参数表示图像,第二个表示设置阈值(由于我们用OTSU自动设置,所以这里必须填0),第三个参数表示将超过正常范围的像素设置的值,最后一个传入控制参数。
cv2.imshow('binary',im)
cv2.imwrite('binary.png',im)
kernel=np.ones((6,6),np.uint8)#生成一个6x6的核
erosion=cv2.erode(im,kernel,iterations=1)#调用腐蚀算法
cv2.imshow('erosion',erosion)
cv2.imwrite('erosion.png',erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
晓得了二值腐蚀,那么二值膨胀也就很好理解了。他的作用和腐蚀恰好相反,他能够用来填补一些小洞洞,将两个物体连接起来。
最终效果就是扩展边界,使得图像变得膨胀。对于膨胀,其实可以用腐蚀来理解。对图像的膨胀其实也就是对背景的腐蚀。
当然也可以用类似腐蚀的方法来描述,我们需要用一个定义了原点的模板核,这个核是一个二值矩阵。然后对于待处理图像的每一个值为1的像素点,将他与模板核的原点对其,然后对于模板核中值为1的点在图像中对应的像素更新为1。
通俗的讲,就是将每一个像素点用模板核来代替,并将所得到的所有图像求一个并操作。
集合A被模板B膨胀,表示为A\bigoplus B=[A^c\Theta (-B)]^c
其中A^c表示A的补集,-B表示将B旋转180°。
以上是用腐蚀进行的定义,还可以直接定义:
A\bigoplus B=\cup{A+b|b\in B}
这个式子也被称作明夫斯基和形式。
同之前一样,调用下OpenCV的接口体验下效果:
#coding:utf-8
import numpy as np
import cv2
im=cv2.imread('test.jpg',cv2.IMREAD_GRAYSCALE)#读取图像
thresh,im=cv2.threshold(im,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)#用OTSU自动获取阈值并进行二值化,第一个参数表示图像,第二个表示设置阈值(由于我们用OTSU自动设置,所以这里必须填0),第三个参数表示将超过正常范围的像素设置的值,最后一个传入控制参数。
cv2.imshow('binary',im)
cv2.imwrite('binary.png',im)
kernel=np.ones((6,6),np.uint8)#生成一个6x6的核
dilation=cv2.dilate(im,kernel,iterations=1)#调用膨胀算法
cv2.imshow('dilation',dilation)
cv2.imwrite('dilation.png',dilation)
cv2.waitKey(0)
cv2.destroyAllWindows()