opencv 图像的腐蚀(erode)和膨胀(dilate) 开运算以及闭运算


原文链接: opencv 图像的腐蚀(erode)和膨胀(dilate) 开运算以及闭运算

OpenCV---开闭操作 - 山上有风景 - 博客园
腐蚀 :
腐蚀操作会把前景物体的边缘腐蚀掉。原理是卷积核沿着图像滑动,如果与卷积核对应的原图像像素值都是1,那么中心元素保持原值,否则为0.
效果,靠近前景的像素被腐蚀为0,前景物体变小,图像白色区域减少,对于去除白噪声很有用,可以断开两个连接在一起的物体

膨胀 :
与腐蚀相反,卷积核当中只要有一个值是1,中心元素值就是1。此操作会增加前景中的白色区域,一般在去噪声的时候都是先腐蚀再膨胀,腐蚀的过程会使得前景变小,使用膨胀操作使前景变换回来。膨胀也可以使相互分离的物体连接

1.)检测边缘

结构元素可以是矩形/椭圆/十字形,可以用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)) # 十字形结构

img = cv2.imread('j.bmp', 0)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel) # 腐蚀 iterations为迭代运算次数

膨胀与腐蚀相反,取的是局部最大值,效果是把图片"变胖":

dilation = cv2.dilate(img, kernel) # 膨胀

#!/usr/bin/env python  
# encoding: utf-8  
 
import cv2  
import numpy as np  
 
image = cv2.imread("2.jpg",0);  
#构造一个3×3的结构元素   
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))  
dilate = cv2.dilate(image, element)  
erode = cv2.erode(image, element)  
  
#将两幅图像相减获得边,第一个参数是膨胀后的图像,第二个参数是腐蚀后的图像  
result = cv2.absdiff(dilate,erode);  
  
#上面得到的结果是灰度图,将其二值化以便更清楚的观察结果  
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY);   
#反色,即对二值图每个像素取反  
result = cv2.bitwise_not(result);   
#显示图像  
cv2.imshow("result",result);   
cv2.waitKey(0)  
cv2.destroyAllWindows()

腐蚀和膨胀是数学形态学上的名词,如果用于图像处理上则就称为图像二值形态学。

形态学主要是为了获取物体的拓扑和结构信息,通过物体和结构元素相互作用的某些运算,得到物体更本质的形态。当形态学运用到图像处理中,它的主要作用是利用形态学的基本运算,如腐蚀和膨胀运算,对图像进行观察和处理,从而达到改善图像质量的目地;描述和定义图像的各种几何参数和特征。

二值图像的腐蚀和膨胀操作具体如下:

图像的腐蚀(erode)

腐蚀的具体操作:用一个结构元素(也可以说成操作数矩阵)一般为3×3大小的,也可以看成一个卷积模板它们的区别就在于卷积模板是以算术运算为基础的,而结构元素是以集合运算为基础的,扫描图像中的每一个像素(关于图像边缘的处理见下面详细分析),用操作数矩阵扫描图像中的每一个像素,操作数矩阵中每一个像素与覆盖的像素做“与”操作,如果全部为1,则图像中的该像素为1,反之为0,
而膨胀(dilate)操作正好相反,全部为0时,则图像素中的该像素为0,反之为1。

腐蚀的作用是消除物体的边界点,使目标缩小,这个根据操作的过程可以显然的想到,物体的边界处像素值肯定是有0和1,腐蚀操作后这些紧邻着为1的像素点都会变成0,所以腐蚀操作会消除那些小的且无意义的物体,使边界向内部收缩的过程。
相反,膨胀(dilate)的作用当然是使目标增大,填充物体内细小的空洞,并且平滑物体的边界,边界向外部扩张的作用。

开运算是先腐蚀(erode)后膨胀(dilate)的过程,可以消除图像上细小的噪声,并平滑物体的边界

闭运算是先膨胀(dilate)后腐蚀(erode)的过程,可以填充物体内细小的空洞,并平滑物体边界

通常,由于噪声的影响,图象在阈值化后所得到边界往往是很不平滑的,物体区域具有一些噪声孔,背景区域上散布着一些小的噪声物体。连续的开和闭运算可以有效地改善这种情况。有时需要经过多次腐蚀之后再加上相同次数的膨胀,才可以产生比较好的效果。

腐蚀操作会去掉物体的边缘点,细小物体所有的点都会被认为是边缘点,因此会整个被删去。再做膨胀时,留下来的大物体会变回原来的大小,而被删除的小物体则永远消失了。

膨胀操作会使物体的边界向外扩张,如果物体内部存在小空洞的话,经过膨胀操作这些洞将被补上,因而不再是边界了。再进行腐蚀操作时,外部边界将变回原来的样子,而这些内部空洞则永远消失了。

对上面腐蚀和膨胀操作更细致的分析(主要谈论涉及图像边缘的腐蚀和膨胀运算)

注:结构元素在扫描图像中的每个像素时,结构元素的邻域有部分会在图像外面。比如当结构元素扫描图像上方第一行像素值(这里默认结构元素为3×3),结构元素会有部分在图像的外面,此时,为了有效处理边界像素,进行形态学运算的函数通常都会给出超出图像、未指定数值的像素指定一个数值,这样就类似于函数给图像填充了额外的行和列。对于膨胀和腐蚀操作,它们对像素进行填充的值是不同的。规则如下:

腐蚀和膨胀填充图像规则表

规 则

腐蚀 超出图像边界的像素值定义为该数据类型允许的最大值,对于二进制图像,这些像素值设置为1;对于灰度图像,unit8类型的最小值也为255。
膨胀 超出图像边界的像素值定义为该数据类型允许的最小值,对于二进制图像,这些像素值设置为0;对于灰度图像,unit8类型的最小值也为0。
通过对膨胀操作使用最小值填充和对腐蚀操作使用最大值填充,可以有效地消除边界效应(输出图像靠近边界处的区域与图像其它部分不连续)。否则,如果腐蚀操作使用最小值进行填充,则进行腐蚀操作后,输出图像会围绕着一个黑色边框。(此处根据腐蚀和膨胀的具体操作过程应该不难理解,因为当图像边缘都是白色时也就是像素值全为1,此时如果图像边缘外面的像素值填充为最小值,如果二值图像的话则像素值为0,根据腐蚀操作,相与后肯定为0,这时图像边缘处便会成为黑色)
结构元素:膨胀和腐蚀操作的最基本组成部分,用于测试输出图像,通常要比待处理的图像小的多。二维平面结构元素由一个数值为0或1的矩阵组成。结构元素的原点指定了图像中需要处理的像素范围,结构元素中数值为1的点决定结构元素的邻域像素在进行膨胀或腐蚀操作时是否需要参与计算。三维或非平面的结构元素使用0,1定义结构元素在x和y平面上的范围,第三维z定义高度。

开操作(先腐蚀后膨胀)

特点:会消除一些为1的白色噪点 ,消除噪点,去除小的干扰块,而不影响原来的图像

def open_demo(image):
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    for i in range(1000):  #为灰度图像加一些噪点
        h = np.random.random_integers(0,gray.shape[0]-1)
        w = np.random.random_integers(0, gray.shape[1]-1)
        val = np.random.random_integers(0, 255)
        gray[h,w] = camp(gray[h,w],val)

    ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)  #生成二值化图像
    cv.imshow("binary",binary)
    kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,3))
    binary = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)  #开操作,先腐蚀后膨胀,会消除一些为1的白色噪点
    

三:利用开操作完成的任务
(一)提取水平垂直线

def open_demo(image):
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV|cv.THRESH_OTSU)
    cv.imshow("binary",binary)

    kernel = cv.getStructuringElement(cv.MORPH_RECT,(1,15))  #修改内核为(15,1)可以提起横线
    binary = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)
    cv.imshow("open_demo",binary)

(二)消除干扰线

def open_demo(image):
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV|cv.THRESH_OTSU)

    kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,3))  #因为干扰线很细,小于我们想要的字母,先腐蚀后膨胀对字母无影响,但是对于细线在腐蚀的时候就处理掉了
    binary = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)

(三)提取满足要求的形状
getStructuringElement我们设置的内核形状为矩形,是可以设置其他形状
矩形:MORPH_RECT;
十字形结构:MORPH_CORSS;
椭圆形:MORPH_ELLIPSE;

def open_demo(image):
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
    cv.imshow("binary",binary)
    kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
    binary = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)
    cv.imshow("open_demo",binary)

二:闭操作(先膨胀后腐蚀)

特点:可以填充闭合区域

def close_demo(image):
    gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU)
    cv.imshow("binary",binary)
    kernel = cv.getStructuringElement(cv.MORPH_RECT,(15,15))
    binary = cv.morphologyEx(binary,cv.MORPH_CLOSE,kernel)
    cv.imshow("close_demo",binary)

————————————————
版权声明:本文为CSDN博主「jsjliuyun」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/computer_liuyun/article/details/21819099

`