Mythsman


乐极生悲,苦尽甘来。


二值形态学之腐蚀与膨胀

数学形态学(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}$

OpenCV调用

本来想用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()

图样

binary
erosion

二值膨胀

简述

晓得了二值腐蚀,那么二值膨胀也就很好理解了。他的作用和腐蚀恰好相反,他能够用来填补一些小洞洞,将两个物体连接起来。

最终效果就是扩展边界,使得图像变得膨胀。对于膨胀,其实可以用腐蚀来理解。对图像的膨胀其实也就是对背景的腐蚀。

当然也可以用类似腐蚀的方法来描述,我们需要用一个定义了原点的模板核,这个核是一个二值矩阵。然后对于待处理图像的每一个值为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调用

同之前一样,调用下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()

图样

binary
dilation