先腐蚀后膨胀 图像处理_图像处理 腐蚀膨胀 - CSDN
  • 腐蚀膨胀基本原理:就是用一个特定的结构元素来与待处理图像按像素做逻辑操作;可以理解成拿一个带孔的网格板(结构元素矩阵中元素为1的为孔)盖住图像的某一部分,然后按照各种不同的观察方式来确定操作类型。 ...

    背景知识

    结构元素:二维结构元素可以理解成一个二维矩阵,矩阵元素的值为0或者1;通常结构元素要小于待处理的图像。

    腐蚀与膨胀基本原理:就是用一个特定的结构元素来与待处理图像按像素做逻辑操作;可以理解成拿一个带孔的网格板(结构元素矩阵中元素为1的为孔)盖住图像的某一部分,然后按照各种不同的观察方式来确定操作类型。

    比如:腐蚀操作就是拿这个结构元素的中心位置(假设参与逻辑计算的元素对应与二维矩阵中元素为1的点,即网格板上的孔),在图像上移动时,如果透过所有的孔都能看到底下的图像,那么这个中心点处的图像就保留,否则去除。

    腐蚀

           把结构元素B平移a后得到Ba,若Ba包含于X,我们记下这个a点,所有满足上述条件的a点组成的集合称做X被B腐蚀(Erosion)的结果。用公式表示为:E(X)={a| Ba∈X}=XB。原理图如下:


           实际使用时示意图:


          说明:左边是被处理的图象X(二值图象,我们针对的是黑点),中间是结构元素B,那个标有origin的点是中心点,即当前处理元素的位置,我们在介绍模板操作时也有过类似的概念。腐蚀的方法是,拿B的中心点和X上的点一个一个地对比,如果B上的所有点都在X的范围内,则该点保留,否则将该点去掉;右边是腐蚀后的结果。可以看出,它仍在原来X的范围内,且比X包含的点要少,就象X被腐蚀掉了一层。


    膨胀

              膨胀(dilation)可以看做是腐蚀的对偶运算,其定义是:把结构元素B平移a后得到Ba,若Ba击中X,我们记下这个a点。所有满足上述条件的a点组成的集合称做XB膨胀的结果。用公式表示为:D(X)={a | BaX}=X  B,如图6.13所示。图6.13X是被处理的对象,B是结构元素,不难知道,对于任意一个在阴影部分的点aBa击中X,所以XB膨胀的结果就是那个阴影部分。阴影部分包括X的所有范围,就象X膨胀了一圈似的,这就是为什么叫膨胀的原因。原理图如下:


    实际使用时示意图:



    说明:左边是被处理的图象X(二值图象,我们针对的是黑点),中间是结构元素B。膨胀的方法是,拿B的中心点和X上的点及X周围的点一个一个地对,如果B上有一个点落在X的范围内,则该点就为黑;右边是膨胀后的结果。可以看出,它包括X的所有范围,就象X膨胀了一圈似的。


    展开全文
  • 形态学(morphology)一...其基本的运算包括:二值腐蚀膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀膨胀、灰值开闭运算、灰值形态学梯度等。


    本系列文章由@浅墨_毛星云 出品,转载请注明出处。  

    文章链接: http://blog.csdn.net/poem_qianmo/article/details/23710721

    作者:毛星云(浅墨)    邮箱: happylifemxy@163.com 

    写作当前博文时配套使用的OpenCV版本: 2.4.8



    本篇文章中,我们一起探究了图像处理中,最基本的形态学运算——膨胀与腐蚀。浅墨在文章开头友情提醒,用人物照片做腐蚀和膨胀的素材图片得到的效果会比较惊悚,毁三观的,不建议尝试。。。。。。。。。。


    OK,开始吧,依然是先放一张截图:





    一、理论与概念讲解——从现象到本质



    1.1 形态学概述

     

    形态学(morphology)一词通常表示生物学的一个分支,该分支主要研究动植物的形态和结构。而我们图像处理中指的形态学,往往表示的是数学形态学。下面一起来了解数学形态学的概念。

    数学形态学(Mathematical morphology) 是一门建立在格论和拓扑学基础之上的图像分析学科,是数学形态学图像处理的基本理论。其基本的运算包括:二值腐蚀和膨胀、二值开闭运算、骨架抽取、极限腐蚀、击中击不中变换、形态学梯度、Top-hat变换、颗粒分析、流域变换、灰值腐蚀和膨胀、灰值开闭运算、灰值形态学梯度等。

     

    简单来讲,形态学操作就是基于形状的一系列图像处理操作。OpenCV为进行图像的形态学变换提供了快捷、方便的函数。最基本的形态学操作有二种,他们是:膨胀与腐蚀(Dilation与Erosion)。

    膨胀与腐蚀能实现多种多样的功能,主要如下:

    • 消除噪声
    • 分割(isolate)出独立的图像元素,在图像中连接(join)相邻的元素。
    • 寻找图像中的明显的极大值区域或极小值区域
    • 求出图像的梯度

     


    我们在这里给出下文会用到的,用于对比膨胀与腐蚀运算的“浅墨”字样毛笔字原图:

     

    在进行腐蚀和膨胀的讲解之前,首先需要注意,腐蚀和膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领域扩张”,效果图拥有比原图更大的高亮区域。腐蚀就是原图中的高亮部分被腐蚀,“领域被蚕食”,效果图拥有比原图更小的高亮区域。

     





    1.2 膨胀

     

    其实,膨胀就是求局部最大值的操作。

    按数学方面来说,膨胀或者腐蚀操作就是将图像(或图像的一部分区域,我们称之为A)与核(我们称之为B)进行卷积。

    核可以是任何的形状和大小,它拥有一个单独定义出来的参考点,我们称其为锚点(anchorpoint)。多数情况下,核是一个小的中间带有参考点和实心正方形或者圆盘,其实,我们可以把核视为模板或者掩码。

     

    而膨胀就是求局部最大值的操作,核B与图形卷积,即计算核B覆盖的区域的像素点的最大值,并把这个最大值赋值给参考点指定的像素。这样就会使图像中的高亮区域逐渐增长。如下图所示,这就是膨胀操作的初衷。



    膨胀的数学表达式:


    膨胀效果图(毛笔字):

     

    照片膨胀效果图:


     



    1.3 腐蚀


    再来看一下腐蚀,大家应该知道,膨胀和腐蚀是一对好基友,是相反的一对操作,所以腐蚀就是求局部最小值的操作。

    我们一般都会把腐蚀和膨胀对应起来理解和学习。下文就可以看到,两者的函数原型也是基本上一样的。

     

    原理图:

     

    腐蚀的数学表达式:

     

    腐蚀效果图(毛笔字):


    照片腐蚀效果图:

     

     浅墨表示这张狗狗超可爱:D

     

     



    二、深入——OpenCV源码分析溯源

     


    直接上源码吧,在…\opencv\sources\modules\imgproc\src\ morph.cpp路径中 的第1353行开始就为erode(腐蚀)函数的源码,1361行为dilate(膨胀)函数的源码。

    //-----------------------------------【erode()函数中文注释版源代码】---------------------------- 
    //    说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码 
    //    OpenCV源代码版本:2.4.8 
    //    源码路径:…\opencv\sources\modules\imgproc\src\ morph.cpp 
    //    源文件中如下代码的起始行数:1353行 
    //    中文注释by浅墨 
    //--------------------------------------------------------------------------------------------------------  
    void cv::erode( InputArray src, OutputArraydst, InputArray kernel,
                    Point anchor, int iterations,
                    int borderType, constScalar& borderValue )
    {
    //调用morphOp函数,并设定标识符为MORPH_ERODE
       morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType,borderValue );
    }

    //-----------------------------------【dilate()函数中文注释版源代码】---------------------------- 
    //    说明:以下代码为来自于计算机开源视觉库OpenCV的官方源代码 
    //    OpenCV源代码版本:2.4.8 
    //    源码路径:…\opencv\sources\modules\imgproc\src\ morph.cpp 
    //    源文件中如下代码的起始行数:1361行 
    //    中文注释by浅墨 
    //-------------------------------------------------------------------------------------------------------- 
    void cv::dilate( InputArray src,OutputArray dst, InputArray kernel,
                     Point anchor, int iterations,
                     int borderType, constScalar& borderValue )
    {
    //调用morphOp函数,并设定标识符为MORPH_DILATE
       morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType,borderValue );
    }


    可以发现erode和dilate这两个函数内部就是调用了一下morphOp,只是他们调用morphOp时,第一个参数标识符不同,一个为MORPH_ERODE(腐蚀),一个为MORPH_DILATE(膨胀)。

    morphOp函数的源码在…\opencv\sources\modules\imgproc\src\morph.cpp中的第1286行,有兴趣的朋友们可以研究研究,这里就不费时费力花篇幅展开分析了。

     

     

     

    三、浅出——API函数快速上手

     



    3.1  形态学膨胀——dilate函数

     


    erode函数,使用像素邻域内的局部极大运算符来膨胀一张图片,从src输入,由dst输出。支持就地(in-place)操作。

    函数原型:

    C++: void dilate(
    	InputArray src,
    	OutputArray dst,
    	InputArray kernel,
    	Point anchor=Point(-1,-1),
    	int iterations=1,
    	int borderType=BORDER_CONSTANT,
    	const Scalar& borderValue=morphologyDefaultBorderValue() 
    );

    参数详解:

    • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
    • 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
    • 第三个参数,InputArray类型的kernel,膨胀操作的核。若为NULL时,表示的是使用参考点位于中心3x3的核。

    我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。

    其中,getStructuringElement函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:

      • 矩形: MORPH_RECT
      • 交叉形: MORPH_CROSS
      • 椭圆形: MORPH_ELLIPSE

    而getStructuringElement函数的第二和第三个参数分别是内核的尺寸以及锚点的位置。

    我们一般在调用erode以及dilate函数之前,先定义一个Mat类型的变量来获得getStructuringElement函数的返回值。对于锚点的位置,有默认值Point(-1,-1),表示锚点位于中心。且需要注意,十字形的element形状唯一依赖于锚点的位置。而在其他情况下,锚点只是影响了形态学运算结果的偏移。

    getStructuringElement函数相关的调用示例代码如下:

     int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸
     
    //获取自定义核
    Mat element = getStructuringElement(MORPH_RECT,
    	Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),
    	Point( g_nStructElementSize, g_nStructElementSize ));


    调用这样之后,我们便可以在接下来调用erode或dilate函数时,第三个参数填保存了getStructuringElement返回值的Mat类型变量。对应于我们上面的示例,就是填element变量。


    • 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于中心。
    • 第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1。
    • 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
    • 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。
    •  

    使用erode函数,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。

    调用范例:

           	//载入原图 
           	Mat image = imread("1.jpg");
    	//获取自定义核
           	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
           	Mat out;
           	//进行膨胀操作
           	dilate(image, out, element);

    用上面核心代码架起来的完整程序代码:

     

    //-----------------------------------【头文件包含部分】---------------------------------------
    //     描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/core/core.hpp>
    #include<opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    #include <iostream>
     
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //     描述:包含程序所使用的命名空间
    //----------------------------------------------------------------------------------------------- 
    using namespace std;
    using namespace cv;
     
    //-----------------------------------【main( )函数】--------------------------------------------
    //     描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main(  )
    {
     
           //载入原图 
           Mat image = imread("1.jpg");
     
           //创建窗口 
           namedWindow("【原图】膨胀操作");
           namedWindow("【效果图】膨胀操作");
     
           //显示原图
           imshow("【原图】膨胀操作", image);
     
    	//获取自定义核
           Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
           Mat out;
    	//进行膨胀操作
           dilate(image,out, element);
     
           //显示效果图
           imshow("【效果图】膨胀操作", out);
     
           waitKey(0);
     
           return 0;
    }

     运行截图:



     

     

     

    3.2 形态学腐蚀——erode函数



    erode函数,使用像素邻域内的局部极小运算符来腐蚀一张图片,从src输入,由dst输出。支持就地(in-place)操作。

     

    看一下函数原型:

    C++: void erode(
    	InputArray src,
    	OutputArray dst,
    	InputArray kernel,
    	Point anchor=Point(-1,-1),
    	int iterations=1,
    	int borderType=BORDER_CONSTANT,
    	const Scalar& borderValue=morphologyDefaultBorderValue()
     );

    参数详解:

    • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像通道的数量可以是任意的,但图像深度应为CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
    • 第二个参数,OutputArray类型的dst,即目标图像,需要和源图片有一样的尺寸和类型。
    • 第三个参数,InputArray类型的kernel,腐蚀操作的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数 getStructuringElement配合这个参数的使用。getStructuringElement函数会返回指定形状和尺寸的结构元素(内核矩阵)。(具体看上文中浅出部分dilate函数的第三个参数讲解部分)
    • 第四个参数,Point类型的anchor,锚的位置,其有默认值(-1,-1),表示锚位于单位(element)的中心,我们一般不用管它。
    • 第五个参数,int类型的iterations,迭代使用erode()函数的次数,默认值为1。
    • 第六个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT。
    • 第七个参数,const Scalar&类型的borderValue,当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释。

    同样的,使用erode函数,一般我们只需要填前面的三个参数,后面的四个参数都有默认值。而且往往结合getStructuringElement一起使用。

    调用范例:

           	//载入原图 
           	Mat image = imread("1.jpg");
    	//获取自定义核
           	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
           	Mat out;
           	//进行腐蚀操作
           	erode(image,out, element);

    用上面核心代码架起来的完整程序代码:

     

    //-----------------------------------【头文件包含部分】---------------------------------------
    //     描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/core/core.hpp>
    #include<opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    #include <iostream>
     
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //     描述:包含程序所使用的命名空间
    //----------------------------------------------------------------------------------------------- 
    using namespace std;
    using namespace cv;
     
    //-----------------------------------【main( )函数】--------------------------------------------
    //     描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main(  )
    {
           //载入原图 
           Matimage = imread("1.jpg");
     
            //创建窗口 
           namedWindow("【原图】腐蚀操作");
           namedWindow("【效果图】腐蚀操作");
     
           //显示原图
           imshow("【原图】腐蚀操作", image);
     
            
    //获取自定义核
           Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
           Mat out;
     
    //进行腐蚀操作
           erode(image,out, element);
     
           //显示效果图
           imshow("【效果图】腐蚀操作", out);
     
           waitKey(0);
     
           return 0;
    }


    运行结果:

     

     

     

     

    四、综合示例——在实战中熟稔

     

     

    依然是每篇文章都会配给大家的一个详细注释的博文配套示例程序,把这篇文章中介绍的知识点以代码为载体,展现给大家。

    这个示例程序中的效果图窗口有两个滚动条,顾名思义,第一个滚动条“腐蚀/膨胀”用于在腐蚀/膨胀之间进行切换;第二个滚动条”内核尺寸”用于调节形态学操作时的内核尺寸,以得到效果不同的图像,有一定的可玩性。废话不多说,上代码吧:

     
    //-----------------------------------【程序说明】----------------------------------------------
    //            程序名称::《【OpenCV入门教程之十】形态学图像处理(一):膨胀与腐蚀  》 博文配套源码
    //            开发所用IDE版本:Visual Studio 2010
    //          开发所用OpenCV版本: 2.4.8
    //            2014年4月14日 Create by 浅墨
    //            浅墨的微博:@浅墨_毛星云
    //------------------------------------------------------------------------------------------------
     
    //-----------------------------------【头文件包含部分】---------------------------------------
    //            描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    #include <iostream>
     
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //            描述:包含程序所使用的命名空间
    //-----------------------------------------------------------------------------------------------
    using namespace std;
    using namespace cv;
     
     
    //-----------------------------------【全局变量声明部分】--------------------------------------
    //            描述:全局变量声明
    //-----------------------------------------------------------------------------------------------
    Mat g_srcImage, g_dstImage;//原始图和效果图
    int g_nTrackbarNumer = 0;//0表示腐蚀erode, 1表示膨胀dilate
    int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸
     
     
    //-----------------------------------【全局函数声明部分】--------------------------------------
    //            描述:全局函数声明
    //-----------------------------------------------------------------------------------------------
    void Process();//膨胀和腐蚀的处理函数
    void on_TrackbarNumChange(int, void *);//回调函数
    void on_ElementSizeChange(int, void *);//回调函数
     
     
    //-----------------------------------【main( )函数】--------------------------------------------
    //            描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main( )
    {
           //改变console字体颜色
           system("color5E"); 
     
           //载入原图
           g_srcImage= imread("1.jpg");
           if(!g_srcImage.data ) { printf("Oh,no,读取srcImage错误~!\n"); return false; }
          
           //显示原始图
           namedWindow("【原始图】");
           imshow("【原始图】", g_srcImage);
          
           //进行初次腐蚀操作并显示效果图
           namedWindow("【效果图】");
           //获取自定义核
           Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),Point( g_nStructElementSize, g_nStructElementSize ));
           erode(g_srcImage,g_dstImage, element);
           imshow("【效果图】", g_dstImage);
     
           //创建轨迹条
           createTrackbar("腐蚀/膨胀", "【效果图】", &g_nTrackbarNumer, 1, on_TrackbarNumChange);
           createTrackbar("内核尺寸", "【效果图】",&g_nStructElementSize, 21, on_ElementSizeChange);
     
           //输出一些帮助信息
           cout<<endl<<"\t嗯。运行成功,请调整滚动条观察图像效果~\n\n"
                  <<"\t按下“q”键时,程序退出~!\n"
                  <<"\n\n\t\t\t\tby浅墨";
     
           //轮询获取按键信息,若下q键,程序退出
           while(char(waitKey(1))!= 'q') {}
     
           return 0;
    }
     
    //-----------------------------【Process( )函数】------------------------------------
    //            描述:进行自定义的腐蚀和膨胀操作
    //-----------------------------------------------------------------------------------------
    void Process()
    {
           //获取自定义核
           Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),Point( g_nStructElementSize, g_nStructElementSize ));
     
           //进行腐蚀或膨胀操作
           if(g_nTrackbarNumer== 0) {   
                  erode(g_srcImage,g_dstImage, element);
           }
           else{
                  dilate(g_srcImage,g_dstImage, element);
           }
     
           //显示效果图
           imshow("【效果图】", g_dstImage);
    }
     
     
    //-----------------------------【on_TrackbarNumChange( )函数】------------------------------------
    //            描述:腐蚀和膨胀之间切换开关的回调函数
    //-----------------------------------------------------------------------------------------------------
    void on_TrackbarNumChange(int, void *)
    {
           //腐蚀和膨胀之间效果已经切换,回调函数体内需调用一次Process函数,使改变后的效果立即生效并显示出来
           Process();
    }
     
     
    //-----------------------------【on_ElementSizeChange( )函数】-------------------------------------
    //            描述:腐蚀和膨胀操作内核改变时的回调函数
    //-----------------------------------------------------------------------------------------------------
    void on_ElementSizeChange(int, void *)
    {
           //内核尺寸已改变,回调函数体内需调用一次Process函数,使改变后的效果立即生效并显示出来
           Process();
    }


     

    放出一些效果图吧。原始图:

     


    膨胀效果图:

     






    腐蚀效果图:







    腐蚀和膨胀得到的图,都特有喜感,但千变万变,还是原图好看:



    OK,就放出这些吧,具体更多的运行效果大家就自己下载示例程序回去玩吧。


    本篇文章到这里就基本结束了,最后放出文章配套示例程序的打包下载地址。

     

    本篇文章的配套源代码请点击这里下载:


    【浅墨OpenCV入门教程之十】配套源代码下载

     


    OK,今天的内容大概就是这些,我们下篇文章见:)




    展开全文
  • 数字图像处理---通俗理解腐蚀膨胀

    千次阅读 多人点赞 2018-11-08 21:35:20
    腐蚀膨胀是数字形态学里的两个基本操作,一般用于二值图像(当然RGB图也可以用)。腐蚀的作用说白了就是让暗的区域变大,而膨胀的作用就是让亮的区域变大(可以想象成巴啦啦能量和古娜拉黑暗之神在神仙打架。。巴...

    0.腐蚀与膨胀有什么卵用?

    腐蚀与膨胀是数字形态学里的两个基本操作,一般用于二值图像(当然RGB图也可以用)。腐蚀的作用说白了就是让暗的区域变大,而膨胀的作用就是让亮的区域变大(可以想象成巴啦啦能量和古娜拉黑暗之神在神仙打架。。巴啦啦能量赢了就是膨胀,古娜拉黑暗之神赢了就是腐蚀。。。)
    在这里插入图片描述

    最典型的一个应用场景就是在你二值化后,你的目标和背景抠的不是很干净的时候可以试试两个操作,有时候效果出奇的好。就比如我要把一张验证码的图二值化后的结果更精确的话,就可以试试腐蚀与膨胀(第二幅图是膨胀+腐蚀之后的效果,可以看得出来已经把干扰点和干扰线去掉了)。
    在这里插入图片描述
    在这里插入图片描述

    1.腐蚀

    腐蚀的原料有:原图、核(腐蚀的灵魂)、结果图(这货是从原图深拷贝出来的)。下面举栗子来说明腐蚀的工作流程。
    假设现在我们想对这样一幅单通道图做腐蚀操作(被IG关爱过视力的童鞋肯定能看出图里画的是个1)
    在这里插入图片描述
    然后我们就先要把原图拷贝一份出来当结果图,现在的结果图和原图是一毛一样的。
    在这里插入图片描述
    有了原图和结果图之后,我们就需要灵魂了(设计核)。核一般有方框形的,X形的,菱形的,等等等等(当然也可以自己DIY,比如我就DIY了个十字架形的)。并且腐蚀的效果和你设计的核有很大关系,什么样的核适合什么样的图这个全靠自己的脑洞和经验。反正我喜欢多试试几种核,看看哪个核效果好就用哪个。我这里DIY的核是3行3列的矩阵,样子如下:
    在这里插入图片描述
    现在有了灵魂之后,我们就要注入灵魂了。怎么注入呢?非常简单,把我们的核扔到原图和结果图的左上角(PS:我这里没做padding,因为我懒)。
    在这里插入图片描述

    在这里插入图片描述
    扔上去之后,我们就要用到核里面的值了。我们核里面有0和1(非零值),0代表我不care,1(非零值)代表你成功的而引起了我的注意。当我们的核盖在原图上之后就表明我只关心我核是1(非零值)在原图上对应的像素,也就是只关心我红框框里中间呈十字架形的5个255,其他的4个像素我并不关心。锁定完目标后,我们只要看我这5个像素中有没有0,如果有我们就把结果图中红框中心的像素值改成0,否则我就什么都不干。我们看一哈,5个255,并没有0所以什么都不干。

    我们费了半天功夫发现什么都没干,你说气不气,所以捏,我们就把原图和结果图上的红框往右边移一步(其实不是气不气的问题啦,是腐蚀和膨胀是要遍历整个图,所以要迭代啦)。所以挪一步之后成了酱紫。
    在这里插入图片描述
    在这里插入图片描述
    新的地方,新的开始,所以我们要继续刚刚的套路,看看原图红框中十字架部分的5个像素有没有0,发现有0!。所以我们的结果图红框中心点的像素值就被改成0了。
    在这里插入图片描述
    然后继续刚刚的套路,往右挪,看关心的地方有没有0,右边挪不动了就往下挪。直到整个红框雨露均沾后,整个腐蚀算法就做完了。
    完事之后我们会发现结果图变成了酱紫。
    在这里插入图片描述
    嗯,很正常,因为腐蚀就是让黑的区域变大,所以1变胖了,而且原图的1中间有隔断,经过腐蚀之后隔断处也连了起来。

    2.膨胀

    其实理解了腐蚀之后,理解膨胀简直简单的而一批。腐蚀之所以叫腐蚀是因为他只看感兴趣区域里面有没有0,有0我就把结果赋成0,所以黑的区域能变大。而膨胀只是和腐蚀相反,它只看感兴趣区域里面有没有255,有255我就把结果赋成255,所以亮的区域能变大。
    假如原图(0可以看成是噪点)是酱紫
    在这里插入图片描述
    那结果图一开始也是酱紫
    在这里插入图片描述
    假设膨胀的灵魂也是十字架的核
    在这里插入图片描述
    那么膨胀第一步也是在原图和结果图上套个红框
    在这里插入图片描述
    在这里插入图片描述
    然后就看十字架区域有没有255,发现有我就把结果图上的对应位置的像素改成255(当然,这时的结果图对应像素本来就是255,所以相当于什么都没干)。原图和结果图上的红框都往右挪一步
    在这里插入图片描述
    在这里插入图片描述
    这个时候发现十字架区域有255,发现有我就把结果图上的对应位置的像素改成255(当然,这时的结果图对应像素本来就是255,所以相当于什么都没干)。原图和结果图上的红框都往右挪一步。
    在这里插入图片描述
    在这里插入图片描述
    这个时候十字架区域有255,所以把结果图对应的像素改成255,改完之后结果图是酱紫。
    在这里插入图片描述
    然后继续挪,挪到右下角,整个算法就停止了。膨胀做完之后,结果图是酱紫。
    在这里插入图片描述
    可以看得出来,原图的0我看成是噪点,经过膨胀之后噪点全部被擦除。

    3.结束语

    可以看得出来腐蚀和膨胀这两个算法流程非常简单,无非就是摩擦摩擦。。似魔鬼的步伐。。在图像上摩擦。。摩擦。。虽然算法简单,但如果核设计的好,使用恰当的话,能还是够得到比较满意的效果的。

    展开全文
  • 目录 1 形态学操作 2 图像腐蚀 3 图像膨胀 参考资料 1 形态学操作 ...形态学(morphology)一词通常表示生物学的一个分支,该分支主要研究动植物的形态和结构。...形态学通常使用图像腐蚀图像膨胀...

    目录

    1 形态学操作

    2 图像腐蚀

    3 图像膨胀

    参考资料


    1 形态学操作

    形态学morphology)一词通常表示生物学的一个分支,该分支主要研究动植物的形态和结构。这里,我们使用同一词语表示数学形态学的内容,将数学形态学作为工具从图像中提取表达和描绘区域形状的有用图像分量,如边界、骨架和凸壳等。

    形态学处理主要针对的是二值图像(0或1)。

    形态学通常使用图像腐蚀图像膨胀两个操作,这些操作是形态学处理的基础。


     

    2 图像腐蚀

    作为{{Z}^{2}}中的集合AB,表示为A\ominus BBA的腐蚀定义为:

                                                                                  A\ominus B=\left\{ z\left| {{(B)}_{z}}\subseteq A \right. \right\}

    上式表示图像A用卷积模板B来进行腐蚀处理,通过模板B与图像A进行卷积计算,得出B覆盖区域的像素点最小值,并用这个最小值来替代参考点的像素值。如图所示,将左边的原始图像A腐蚀处理为右边的效果图A\ominus B

     

    图像腐蚀的效果如下图所示:

     

    图像腐蚀类似于“邻域被蚕食”,将图像中的高亮区域或白色部分进行缩减细化,其运行结果图比原图的高亮区域更小。其主要包括两个输入对象:

    (1) 二值图像

    (2 )卷积核

     

    卷积核是腐蚀中的关键数组,采用numpy库可以生成。卷积核的中心点逐个像素扫描原始图像,腐蚀的过程如下图所示:

    被扫描到的原始图像中的像素点,只有当卷积核对应的元素值均为1时,其值才为1,否则其值修改为0。换句话说,遍历到的黄色点位置,其周围全部是白色,保留白色,否则变为黑色,图像腐蚀变小。如下图所示:

     

    图像腐蚀主要使用的函数为 erode(),其函数形式如下:

    dst = cv2.erode(src, kernel, iterations)

    其中,参数:

    dst 表示处理的结果;

    src 表示原图像;

    kernel 表示卷积核;

    iterations 表示迭代次数。

    注:迭代次数默认是1,表示进行一次腐蚀,也可以根据需要进行多次迭代,进行多次腐蚀。

    例如:下图表示5\times5的卷积核,可以采用函数 np.ones((5,5), np.uint8) 构建。

     

    (1)卷积核大小为5\times5 ,迭代次数为1

    代码如下所示:

    #encoding:utf-8
    import cv2
    import numpy as np
    
    #读取图片
    src = cv2.imread('test1.bmp', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((5,5), np.uint8)
    
    #图像腐蚀处理
    erosion = cv2.erode(src, kernel)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", erosion)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()

     

    运行结果如下图所示:

     

     

    (2)卷积核大小为5\times5,迭代次数为9

    代码如下所示:

    #encoding:utf-8
    import cv2
    import numpy as np
    
    #读取图片
    src = cv2.imread('test1.bmp', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((5,5), np.uint8)
    
    #图像腐蚀处理
    erosion = cv2.erode(src, kernel,iterations=10)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", erosion)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()

     

    运行结果如下图所示:

     

    (2)卷积核大小为39\times39,迭代次数为1

    代码如下所示:

    #encoding:utf-8
    import cv2
    import numpy as np
    
    #读取图片
    src = cv2.imread('test1.bmp', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((39,39), np.uint8)
    
    #图像腐蚀处理
    erosion = cv2.erode(src, kernel)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", erosion)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()

     

    运行结果如下图所示:

     


    3 图像膨胀

    作为{{Z}^{2}}中的集合AB,表示为A\oplus BBA膨胀定义为:

                                                                            A\oplus B=\left\{ z\left| {{(\widehat{B})}_{z}}\bigcap{A\ne \varnothing } \right. \right\}

    图像膨胀是腐蚀操作的逆操作,类似于“领域扩张”,将图像中的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更大,线条变粗了,主要用于去噪。

    (1) 图像被腐蚀后,去除了噪声,但是会压缩图像。

    (2) 对腐蚀过的图像,进行膨胀处理,可以去除噪声,并且保持原有形状。

    它也包括两个输入对象:

    (1)二值图像或原始图像

    (2)卷积核

    图像膨胀的效果如下图所示:

     

    卷积核是腐蚀中的关键数组,采用numpy库可以生成。卷积核的中心点逐个像素扫描原始图像,如下图所示:

     

     

    被扫描到的原始图像中的像素点,当卷积核对应的元素值只要有一个为1时,其值就为1,否则为0

     

    图像膨胀主要使用的函数为 dilate(),其函数用法如下所示:

    dst = cv2.dilate(src, kernel, iterations)

    其中,参数:

    dst 表示处理的结果;

    src 表示原始图像;

    kernel 表示卷积核;

    iterations 表示迭代次数。

    注:迭代次数默认是1,表示进行一次膨胀,也可根据需要进行多次迭代,进行多次膨胀。通常进行1次膨胀即可。

    例如,下图表示5\times5的卷积核,可以采用函数 np.ones((5,5), np.uint8) 构建。

     

    (1)卷积核大小为3\times3 ,迭代次数为1

    代码如下所示:

    #encoding:utf-8
    import cv2
    import numpy as np
    
    #读取图片
    src = cv2.imread('test2.bmp', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((3,3), np.uint8)
    
    #图像膨胀处理
    erosion = cv2.dilate(src, kernel)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", erosion)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()

     

    运行结果如下图所示:

     

    (1)卷积核大小为5\times5 ,迭代次数为1

    代码如下所示:

    #encoding:utf-8
    import cv2
    import numpy as np
    
    #读取图片
    src = cv2.imread('test2.bmp', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((5,5), np.uint8)
    
    #图像膨胀处理
    erosion = cv2.dilate(src, kernel)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", erosion)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()

     

    运行结果如下图所示:

     


     

    参考资料

    [1] https://blog.csdn.net/Eastmount/article/details/83581277

    [2] Python+OpenCV图像处理

    展开全文
  • 图像腐蚀图像膨胀Matlab代码

    热门讨论 2020-07-29 14:21:49
    然后,经过先腐蚀(Erosion)处理后膨胀(Dilation)处理得到了Opening Image;又经过先膨胀(Dilation)处理后腐蚀(Erosion)处理得到了Closing Image。 程序执行能够得到原始图像膨胀后图像腐蚀后图像、Opening...
  • [Python图像处理] 八.图像腐蚀与图像膨胀

    万次阅读 多人点赞 2020-08-20 12:48:51
    图像膨胀(Dilation)和腐蚀(Erosion)是两种基本的形态学运算,主要用来寻找图像中的极大区域和极小区域。其中膨胀类似于“领域扩张”,将图像中的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更...
  • Ubuntu16.04系统,数字图像处理腐蚀膨胀操作,完整工作空间文件夹,C++文件运行,含注释,以及具有直方图输出,便于比较直观显示,还含有代码运行示意图
  • 参考:【数字图像处理学习笔记之四】图像腐蚀膨胀:https://blog.csdn.net/zhougynui/article/details/51834725 1 背景知识 结构元素:二维结构元素可以理解成一个二维矩阵,矩阵元素的值为0或者1;通常结构元素...
  • 图像的腐蚀膨胀 作者:Cabin_V 作为学习图像处理的学生,需要不断学习相关知识,我在课余时间将一些分析总结和学习的笔记写成博客来记录自己的学习过程...文章目录图像的腐蚀膨胀图像腐蚀与膨胀区别作用API说明get...
  • 图像处理腐蚀膨胀的原理

    千次阅读 2018-10-30 15:56:28
    假设原图像中有一个前景物体,那么我们用一个结构元素去腐蚀原图的过程是这样的:遍历原图像的每一个像素,然后用结构元素的中心点对准当前正在遍历的这个像素,然后取当前结构元素所覆盖下的原图对应区域内的所有...
  • 图像腐蚀图像膨胀(Python篇)

    万次阅读 2018-11-17 11:45:07
    在大学期间积累过一定的图像处理经验,OCR技术在我的日常工作中偶尔会用到,还是比较重要的。本文介绍图像的膨胀腐蚀的基本概念及其各自的代码实现。  1.膨胀腐蚀的基本概念  图像的膨胀(Dilation)和腐蚀...
  • OpenCV-图像处理(10、膨胀腐蚀

    千次阅读 2019-01-09 20:22:10
    形态学操作(morphology operators)-膨胀腐蚀(Dilation与...膨胀腐蚀图像处理中最常用的形态学操作手段 腐蚀膨胀是对白色部分(高亮部分)而言的,不是黑色部分。膨胀就是图像中的高亮部分进行膨胀,“领...
  • 图像处理技术中,有一些的操作会对图像的形态发生改变,这些操作一般称之为形态学操作(phology)。数学形态学是基于集合论的图像处理方法,最早出现在生物学的形态与结构中,图像处理中的形态学操作用于图像与...
  • 图像膨胀(Dilation)和腐蚀(Erosion)是两种基本的形态学运算,主要用来寻找图像中的极大区域和极小区域。其中膨胀类似于“领域扩张”,将图像中的高亮区域或白色部分进行扩张,其运行结果图比原图的高亮区域更...
  • 二值图像形态学运算时图像形态学运算的基础。二值图像形态学运算的过程就是在图像...二值图像的形态学处理的基本运算有腐蚀膨胀、开运算、闭运算,击中与击不中、骨架抽取等。注意,本文所有例子都是24位真彩色图...
  • 腐蚀膨胀是最基本的处理方法,其它方法都是腐蚀膨胀方法相互组合产生的。 一、腐蚀膨胀 1.腐蚀 图像腐蚀操作类似于中值平滑,首先要取每个位置的一个邻域内的最小值(中值平滑是取中间值),将其作为该位置...
  • 图像腐蚀膨胀图像大小保存处理 import numpy as np import cv2 as cv import matplotlib.pyplot as plt # 1 读取图像 ime = "D:/OK.1651.bmp" nume = "E:/磁环/OK.1651.png" img = cv.imread(ime) # 2 创建核...
  • OpenCV图像处理篇之腐蚀膨胀

    万次阅读 2014-09-19 22:18:35
    腐蚀膨胀的应用非常广泛,而且效果还很好:腐蚀可以分割(isolate)独立的图像元素,膨胀用于连接(join)相邻的元素,这也是腐蚀膨胀后图像最直观的展现去噪:通过低尺寸结构元素的腐蚀操作很容易去掉分散
  • 图像处理入门C源码分析 图像腐蚀膨胀和细化
1 2 3 4 5 ... 20
收藏数 5,846
精华内容 2,338
关键字:

先腐蚀后膨胀 图像处理