• 常用的形态学处理的方法包括腐蚀,膨胀,开运算闭运算,顶帽运算,底帽运算。腐蚀和膨胀是最基本的处理方法,其它方法都是腐蚀和膨胀方法相互组合产生的。 一、腐蚀和膨胀 1.腐蚀 图像的腐蚀操作类似于中值平滑...

    前言:

    常用的形态学处理的方法包括腐蚀,膨胀,开运算,闭运算,顶帽运算,底帽运算。腐蚀和膨胀是最基本的处理方法,其它方法都是腐蚀和膨胀方法相互组合产生的。

    一、腐蚀和膨胀

    1.腐蚀

    图像的腐蚀操作类似于中值平滑,首先要取每个位置的一个邻域内的最小值(中值平滑是取中间值),将其作为该位置的输出像素值。这里的邻域不局限于矩形结构,还包括椭圆形结构和十字交叉形结构。它的具体定义为结构元,作用类似于平滑操作中的卷积核。

    腐蚀的处理特点:因为取每个位置邻域内的最小值,所以腐蚀后的图像整体会变暗,图像中比较亮的区域的面积会变小甚至消失,而比较暗的区域会增大一些。图像元I和结构元S的腐蚀操作记为:E=I\ominus S

    代码实现:结构元的定义,OpenCV提供了函数getStructureElement();

    Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));

     分别为结构元的形状,结构元的大小,以及锚点位置。

    而腐蚀操作,OpenCV也提供了erode函数(),

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

    第三个参数即为结构元,第四个参数为锚点,第五个参数为腐蚀操作的迭代次数,后两个分别为边界的扩充类型与边界扩充值。

    	Mat img = imread("Res/duck.jpg",CV_LOAD_IMAGE_GRAYSCALE);
    	imshow("img",img);
    	
    	Mat s = getStructuringElement(MORPH_RECT,Size(3,3));
    	Mat imgO;
    	erode(img,imgO,s,Point(0,0),2);
    	imshow("imgO", imgO);
    	waitKey(0);
    	return 0;

     效果图如下:

    2.膨胀

    膨胀和腐蚀操作原理相似,膨胀是选取每个位置邻域内的最大值作为输出灰度值。膨胀后的图像的整体亮度会有提高,图形中较亮物体的尺寸变大,而较暗物体的尺寸会减小甚至消失。图像I和结构元的膨胀操作记为:D=I\oplus S

    代码实现与腐蚀操作类似,只不过膨胀操作的函数为dilate()。

    二、开运算和闭运算

    1.先腐蚀后膨胀的运算称为开运算,如下:

    I\circ S=(I\ominus S)\oplus S

    功能特点:它具有消除亮度较高的细小区域,在纤细点分离物体,对于较大物体,可以在不明显改变其面积的情况下平滑其边界等作用。

    2.先膨胀后腐蚀的运算称为闭运算,如下:

    I\bullet S=(I\oplus S)\ominus S

    功能特点:它具有填充白色物体内细小黑色区域、连接临近物体的作用,也可以在不明显改变其面积的情况下平滑边界。

    代码实现:由于开运算和闭运算是腐蚀和膨胀的组合,所以完全可以利用函数erode和dilate的组合来实现,而OpenCV则提供了函数morphologyEx(),

    void morphologyEx( InputArray src, OutputArray dst,
                                    int op, InputArray kernel,
                                    Point anchor = Point(-1,-1), int iterations = 1,
                                    int borderType = BORDER_CONSTANT,
                                    const Scalar& borderValue = morphologyDefaultBorderValue() );
    
    enum MorphTypes{
        MORPH_ERODE    = 0, MORPH_DILATE  = 1,MORPH_OPEN  = 2, MORPH_CLOSE  = 3,
        MORPH_GRADIENT = 4, MORPH_TOPHAT   = 5,MORPH_BLACKHAT = 6
    };

    其中第三个参数,代表处理操作的类型,除了已经介绍到的腐蚀,膨胀,开运算和闭运算,还有顶帽运算,底帽运算以及形态梯度,其余参数均可参照erode和dilate函数的参数即可。

    开闭运算相比较腐蚀和膨胀,它能够在不明显改变物体的形态大小的情况下进行腐蚀和膨胀操作。

    三、顶帽运算和底帽运算以及形态学梯度

    顶帽运算和底帽运算分别以开运算和闭运算为基础。

    1.顶帽运算的定义是图像减去开运算结果:T_{hat}(I)=I-I\circ S

    开运算可以消除暗背景下的较亮区域,所以用原图减去开运算结果就可以得到原图中灰度较亮的区域,原图中暗背景下的较亮区域处理后被消除,相减之后可以得到这部分被消除的亮色。所以又称白顶帽变换,它还有一个重要作用就是校正不均匀光照。

    2.底帽运算定义为闭运算结果减去原图像:B_{hat}(I)=I\bullet S-I

    闭运算可以填充亮度较高背景下的较暗区域,原来的较亮背景中的较暗区域会被填充为亮色,如果用闭运算的结果减去原图,得到的就是原图中灰度较暗的区域。

    3.形态学梯度

    定义:G=I\oplus S-I\ominus S

    即膨胀结果减去腐蚀结果,因为膨胀是取邻域内的最大值,从而增大亮度高的区域的面积。而腐蚀是取邻域内的最小值,从而增加较暗区域的面积,所以两者相减得到的就是图像中物体的边界。

    具体地代码实现就是使用上面已经介绍过的函数即可。

     

    展开全文
  • 开运算 = 先腐蚀运算,再膨胀运算(看上去把细微连在一起的两块目标分开了) 开运算的效果图如下图所示: 开运算总结: (1)开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不便。 (2)开运算是一...

    (如果不了解腐蚀与膨胀原理的同学那请看我前一期博客哦!)

    • 1.开运算
      开运算 = 先腐蚀运算,再膨胀运算(看上去把细微连在一起的两块目标分开了)
      开运算的效果图如下图所示:
      这里写图片描述
    • 开运算总结:
      (1)开运算能够除去孤立的小点,毛刺和小桥,而总的位置和形状不便。
      (2)开运算是一个基于几何运算的滤波器。
      (3)结构元素大小的不同将导致滤波效果的不同。
      (4)不同的结构元素的选择导致了不同的分割,即提取出不同的特征。

    • 2.闭运算
      闭运算 = 先膨胀运算,再腐蚀运算(看上去将两个细微连接的图块封闭在一起)
      闭运算的效果图如下图所示:

    这里写图片描述
    - 闭运算总结:
    (1)闭运算能够填平小湖(即小孔),弥合小裂缝,而总的位置和形状不变。
    (2)闭运算是通过填充图像的凹角来滤波图像的。
    (3)结构元素大小的不同将导致滤波效果的不同。
    (4)不同结构元素的选择导致了不同的分割。


    我们可以使用opencv自带函数进行调试哦!
    openCV里有一个很好的函数getStructuringElement,我们只要往这个函数传相应的处理参数,就可以进行相应的操作了,使用起来非常方便。下面我简单列举一下相应的操作宏定义:

    标识符 含义
    MORPH_OPEN 开运算
    MORPH_CLOSE 闭运算
    MORPH_ERODE 腐蚀
    MORPH_DILATE 膨胀

    我就简单举个例子:

    #include<opencv2\opencv.hpp>   
    #include<opencv2\highgui\highgui.hpp>
    
    using namespace std;
    using namespace cv;
    
    int main()
    {
        Mat img = imread("寒山不冷.jpg");
        namedWindow("原始图", WINDOW_NORMAL);
        imshow("原始图", img);
        Mat out;
        //获取自定义核 第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的
        Mat element = getStructuringElement(MORPH_RECT, Size(18, 18)); 
    
    
        //具体要选择哪种操作,就修改第三个参数就可以了。这里演示的是形态学开运算处理
        morphologyEx(img, out, MORPH_OPEN, element);
        namedWindow("形态学处理操作", WINDOW_NORMAL);
        imshow("形态学处理操作", out);
        waitKey(0);
    
    }
    展开全文
  • 该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解...本篇文章主要讲解Python调用OpenCV实现图像形态学转化,包括图像开运算、图像闭运算和梯度运算,基础性知识希望对您有所帮助,如果有不足之处,还请海涵~

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。希望文章对您有所帮助,如果有不足之处,还请海涵~

    该系列在github所有源代码:https://github.com/eastmountyxz/ImageProcessing-Python
    PS:请求帮忙点个Star,哈哈,第一次使用Github,以后会分享更多代码,一起加油。

    同时推荐作者的C++图像系列知识:
    [数字图像处理] 一.MFC详解显示BMP格式图片
    [数字图像处理] 二.MFC单文档分割窗口显示图片
    [数字图像处理] 三.MFC实现图像灰度、采样和量化功能详解
    [数字图像处理] 四.MFC对话框绘制灰度直方图
    [数字图像处理] 五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理详解
    [数字图像处理] 六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解
    [数字图像处理] 七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解

    前文参考:
    [Python图像处理] 一.图像处理基础知识及OpenCV入门函数
    [Python图像处理] 二.OpenCV+Numpy库读取与修改像素
    [Python图像处理] 三.获取图像属性、兴趣ROI区域及通道处理
    [Python图像处理] 四.图像平滑之均值滤波、方框滤波、高斯滤波及中值滤波
    [Python图像处理] 五.图像融合、加法运算及图像类型转换
    [Python图像处理] 六.图像缩放、图像旋转、图像翻转与图像平移
    [Python图像处理] 七.图像阈值化处理及算法对比
    [Python图像处理] 八.图像腐蚀与图像膨胀

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

    本篇文章主要讲解Python调用OpenCV实现图像形态学转化,包括图像开运算、图像闭运算和梯度运算,基础性知识希望对您有所帮助。
    1.图像开运算
    2.图像闭运算
    3.图像梯度运算

    PS:文章参考自己以前系列图像处理文章及OpenCV库函数,同时部分参考网易云lilizong老师的视频,推荐大家去学习。同时,本篇文章涉及到《计算机图形学》基础知识,请大家下来补充。

    PSS:2019年1~2月作者参加了CSDN2018年博客评选,希望您能投出宝贵的一票。我是59号,Eastmount,杨秀璋。投票地址:https://bss.csdn.net/m/topic/blog_star2018/index

    五年来写了314篇博客,12个专栏,是真的热爱分享,热爱CSDN这个平台,也想帮助更多的人,专栏包括Python、数据挖掘、网络爬虫、图像处理、C#、Android等。现在也当了两年老师,更是觉得有义务教好每一个学生,让贵州学子好好写点代码,学点技术,"师者,传到授业解惑也",提前祝大家新年快乐。2019我们携手共进,为爱而生。

    一. 图像开运算

    1.基本原理
    图像开运算是图像依次经过腐蚀、膨胀处理后的过程。图像被腐蚀后,去除了噪声,但是也压缩了图像;接着对腐蚀过的图像进行膨胀处理,可以去除噪声,并保留原有图像。如下图所示:

    开运算(img) = 膨胀( 腐蚀(img) )
    下图是hanshanbuleng博主提供的开运算效果图,推荐大家学习他的文章。

    https://blog.csdn.net/hanshanbuleng/article/details/80657148

    2.函数原型
    图像开运算主要使用的函数morphologyEx,它是形态学扩展的一组函数,其参数cv2.MORPH_OPEN对应开运算。其原型如下:
    dst = cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)

    参数dst表示处理的结果,src表示原图像,cv2.MORPH_OPEN表示开运算,kernel表示卷积核。下图表示5*5的卷积核,可以采用函数 np.ones((5,5), np.uint8) 构建。

    运行结果如下图所示:

    3.代码实现
    完整代码如下所示:

    #encoding:utf-8
    import cv2  
    import numpy as np  
    
    #读取图片
    src = cv2.imread('test01.png', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((5,5), np.uint8)
    
    #图像开运算
    result = cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", result)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    输出结果如下图所示,可以看到噪声已经被去除了。

    但是结果result中仍然有部分噪声,如果想去除更彻底将卷积设置为10*10的。 kernel = np.ones((10,10), np.uint8) result = cv2.morphologyEx(src, cv2.MORPH_OPEN, kernel)


    二. 图像闭运算

    1.基本原理
    图像闭运算是图像依次经过膨胀、腐蚀处理后的过程。图像先膨胀,后腐蚀,它有助于关闭前景物体内部的小孔,或物体上的小黑点。如下图所示:

    闭运算(img) = 腐蚀( 膨胀(img) )
    下图是hanshanbuleng博主提供的开运算效果图,推荐大家学习他的文章。

    https://blog.csdn.net/hanshanbuleng/article/details/80657148

    2.函数原型
    图像闭运算主要使用的函数morphologyEx,其原型如下:
    dst = cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)

    参数dst表示处理的结果,src表示原图像, cv2.MORPH_CLOSE表示闭运算,kernel表示卷积核。下图表示5*5的卷积核,可以采用函数 np.ones((5,5), np.uint8) 构建。

    运行结果如下图所示:

    3.代码实现
    完整代码如下所示:

    #encoding:utf-8
    import cv2  
    import numpy as np  
    
    #读取图片
    src = cv2.imread('test03.png', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((10,10), np.uint8)
    
    #图像闭运算
    result = cv2.morphologyEx(src, cv2.MORPH_CLOSE, kernel)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", result)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    输出结果如下图所示,可以看到中间的噪声去掉。



    三. 图像梯度运算

    1.基本原理
    图像梯度运算是膨胀图像减去腐蚀图像的结果,得到图像的轮廓,其中二值图像1表示白色点,0表示黑色点。如下图所示:

    梯度运算(img) = 膨胀(img) - 腐蚀(img)

    2.函数原型
    图像梯度运算主要使用的函数morphologyEx,参数为cv2.MORPH_GRADIENT。其原型如下:
    dst = cv2.morphologyEx(src, cv2.MORPH_GRADIENT, kernel)

    参数dst表示处理的结果,src表示原图像, cv2.MORPH_GRADIENT表示梯度运算,kernel表示卷积核。5*5的卷积核可以采用函数 np.ones((5,5), np.uint8) 构建。
    运行结果如下图所示:

    3.代码实现
    完整代码如下所示:

    #encoding:utf-8
    import cv2  
    import numpy as np  
    
    #读取图片
    src = cv2.imread('test04.png', cv2.IMREAD_UNCHANGED)
    
    #设置卷积核
    kernel = np.ones((10,10), np.uint8)
    
    #图像闭运算
    result = cv2.morphologyEx(src, cv2.MORPH_GRADIENT, kernel)
    
    #显示图像
    cv2.imshow("src", src)
    cv2.imshow("result", result)
    
    #等待显示
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    

    输出结果如下图所示,可以看到中间的噪声去掉。

    希望文章对大家有所帮助,如果有错误或不足之处,还请海涵。最近经历的事情太多,有喜有悲,关闭了朋友圈,希望通过不断学习和写文章来忘记烦劳,将忧郁转换为动力,每周学习都记录下来,加油!!!
    (By:Eastmount 2018-11-02 中午12点 https://blog.csdn.net/Eastmount/)

    展开全文
  • matlab图像处理形态学滤波之开运算闭运算(1)  刚入门的朋友估计对开闭运算还不太了解,首先先了解几个名词: 腐蚀: 是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的物体。   ...
    matlab图像处理形态学滤波之开运算闭运算(1)

           刚入门的朋友估计对开闭运算还不太了解,首先先了解几个名词:

    腐蚀:  是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的物体。
     
    膨胀:  是将与物体接触的所有背景点合并到该物体中,使边界向外部扩张的过程。可以用来填补物体中的空洞。 


    开运算:  先腐蚀后膨胀的过程开运算。用来消除小物体、在纤细点处分离物体、平滑较大物 体的边界的同时并不明显改变其面积。开运算通常是在需要去除小颗粒噪声,以及断开目标物之间粘连时使用。其主要作用与腐蚀相似,与腐蚀操作相比,具有可以基本保持目标原有大小不变的优点。 


    闭运算:  先膨胀后腐蚀的过程称为闭运算。用来填充物体内细小空洞、连接邻近物体、平滑 其边界的同时并不明显改变其面积。

           对一个图像先进行腐蚀运算然后再膨胀的操作过程称为开运算,它可以消除细小的物体、在纤细点处分离物体、平滑较大物体的边界时不明显的改变其面积。如果对一个图像先膨胀然后再收缩,我们称之为闭运算,它具有填充物体内细小的空洞、连接邻近物体、在不明显改变物体面积的情况下平滑其边界的作用。通常情况下,当有噪声的图像用阈值二值化后,所得到的边界是很不平滑的,物体区域具有一些错判的孔洞,背景区域散布着一些小的噪声物体,连续的开和闭运算可以显著的改善这种情况,这时候需要在连接几次腐蚀迭代之后,再加上相同次数的膨胀,才可以产生所期望的效果。

           所以,换一种说法,图像的开闭运算实质上是数学形态的非线性滤波去噪的一个过程。

           知道以上名词了我们就可以把我们的想法与之匹配,通过开闭运算来实现我们的目的。

           matlab程序如下:
    i=imread('image.jpg');
    i1=rgb2gray(i); %转灰度图像
    i2=im2bw(i1);    %二值化搜索
    i3 = bwmorph(i2,'close');  %闭运算
    imshow(i3)
    i4 = bwmorph(i2,'open');  %开运算
    figure, imshow(i4)
    %bwmorph还支持类似bothat tophat thin等操作个体看下help参数
    %说明:前提条件是传入的图像应该是二值后的
    
    

    更强大的有关腐蚀膨胀以及开闭运算的matlab程序参考链接:

    http://blog.csdn.net/zhangyibo123456789/article/details/60957376


    展开全文
  • 1、开运算 开运算(Opening Operation),其实就是先腐蚀后膨胀的过程。其数学表达式如下: 开运算可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。 //------------------...

    一、案例分析

    1、开运算

    开运算(Opening Operation),其实就是先腐蚀后膨胀的过程。其数学表达式如下:


    开运算可以用来消除小物体、在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。

    //-----------------------------------【头文件包含部分】---------------------------------------
    //            描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/opencv.hpp>
    #include<opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //            描述:包含程序所使用的命名空间
    //-----------------------------------------------------------------------------------------------
    using namespace cv;
    //-----------------------------------【main( )函数】--------------------------------------------
    //            描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main()
    {
    	//载入原始图  
    	Mat image = imread("../jz.jpg");  //工程目录下应该有一张名为1.jpg的素材图
    								  //创建窗口  
    	namedWindow("【原始图】开运算");
    	namedWindow("【效果图】开运算");
    	//显示原始图 
    	imshow("【原始图】开运算", image);
    	//定义核
    	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
    	//进行形态学操作
    	morphologyEx(image, image, MORPH_OPEN, element);
    	//显示效果图 
    	imshow("【效果图】开运算", image);
    
    	waitKey(0);
    
    	return 0;
    }

    2、闭运算

    先膨胀后腐蚀的过程称为闭运算(Closing Operation),其数学表达式如下:

     

    闭运算能够排除小型黑洞(黑色区域)。

    //-----------------------------------【头文件包含部分】---------------------------------------
    //            描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //            描述:包含程序所使用的命名空间
    //-----------------------------------------------------------------------------------------------
    using namespace cv;
    //-----------------------------------【main( )函数】--------------------------------------------
    //            描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main()
    {
    	//载入原始图  
    	Mat image = imread("../jz.jpg");  //工程目录下应该有一张名为1.jpg的素材图
    								  //创建窗口  
    	namedWindow("【原始图】闭运算");
    	namedWindow("【效果图】闭运算");
    	//显示原始图 
    	imshow("【原始图】闭运算", image);
    	//定义核
    	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
    	//进行形态学操作
    	morphologyEx(image, image, MORPH_CLOSE, element);
    	//显示效果图 
    	imshow("【效果图】闭运算", image);
    
    	waitKey(0);
    
    	return 0;
    }

    3、形态学梯度

    形态学梯度(Morphological Gradient)为膨胀图与腐蚀图之差,数学表达式如下:

    对二值图像进行这一操作可以将团块(blob)的边缘突出出来。
    //-----------------------------------【头文件包含部分】---------------------------------------
    //            描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/opencv.hpp>
    #include<opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //            描述:包含程序所使用的命名空间
    //-----------------------------------------------------------------------------------------------
    using namespace cv;
    //-----------------------------------【main( )函数】--------------------------------------------
    //            描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main()
    {
    	//载入原始图  
    	Mat image = imread("../jz.jpg");  //工程目录下应该有一张名为1.jpg的素材图
    								  //创建窗口  
    	namedWindow("【原始图】形态学梯度");
    	namedWindow("【效果图】形态学梯度");
    	//显示原始图 
    	imshow("【原始图】形态学梯度", image);
    	//定义核
    	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
    	//进行形态学操作
    	morphologyEx(image, image, MORPH_GRADIENT, element);
    	//显示效果图 
    	imshow("【效果图】形态学梯度", image);
    
    	waitKey(0);
    
    	return 0;
    }

    4、顶帽

    顶帽运算(Top Hat)又常常被译为”礼帽“运算。为原图像与上文刚刚介绍的“开运算“的结果图之差,数学表达式如下:

    因为开运算带来的结果是放大了裂缝或者局部低亮度的区域,因此,从原图中减去开运算后的图,得到的效果图突出了比原图轮廓周围的区域更明亮的区域,且这一操作和选择的核的大小相关。

    顶帽运算往往用来分离比邻近点亮一些的斑块。当一幅图像具有大幅的背景的时候,而微小物品比较有规律的情况下,可以使用顶帽运算进行背景提取。

    //-----------------------------------【头文件包含部分】---------------------------------------
    //            描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/opencv.hpp>
    #include<opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //            描述:包含程序所使用的命名空间
    //-----------------------------------------------------------------------------------------------
    using namespace cv;
    //-----------------------------------【main( )函数】--------------------------------------------
    //            描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main()
    {
    	//载入原始图  
    	Mat image = imread("../jz.jpg");  //工程目录下应该有一张名为1.jpg的素材图
    								  //创建窗口  
    	namedWindow("【原始图】顶帽运算");
    	namedWindow("【效果图】顶帽运算");
    	//显示原始图 
    	imshow("【原始图】顶帽运算", image);
    	//定义核
    	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
    	//进行形态学操作
    	morphologyEx(image, image, MORPH_TOPHAT, element);
    	//显示效果图 
    	imshow("【效果图】顶帽运算", image);
    
    	waitKey(0);
    
    	return 0;
    }

    5、黑帽

    黑帽(Black Hat)运算为”闭运算“的结果图与原图像之差。数学表达式为:


    黑帽运算后的效果图突出了比原图轮廓周围的区域更暗的区域,且这一操作和选择的核的大小相关。

    所以,黑帽运算用来分离比邻近点暗一些的斑块。

    //-----------------------------------【头文件包含部分】---------------------------------------
    //            描述:包含程序所依赖的头文件
    //----------------------------------------------------------------------------------------------
    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include<opencv2/imgproc/imgproc.hpp>
    
    //-----------------------------------【命名空间声明部分】---------------------------------------
    //            描述:包含程序所使用的命名空间
    //-----------------------------------------------------------------------------------------------
    using namespace cv;
    //-----------------------------------【main( )函数】--------------------------------------------
    //            描述:控制台应用程序的入口函数,我们的程序从这里开始
    //-----------------------------------------------------------------------------------------------
    int main()
    {
    	//载入原始图  
    	Mat image = imread("../jz.jpg");  //工程目录下应该有一张名为1.jpg的素材图
    								  //创建窗口  
    	namedWindow("【原始图】黑帽运算");
    	namedWindow("【效果图】黑帽运算");
    	//显示原始图 
    	imshow("【原始图】黑帽运算", image);
    	//定义核
    	Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
    	//进行形态学操作
    	morphologyEx(image, image, MORPH_BLACKHAT, element);
    	//显示效果图 
    	imshow("【效果图】黑帽运算", image);
    
    	waitKey(0);
    
    	return 0;
    }

    二、原理分析

    为什么我们在后面几个案例中使用了morphologyEx函数呢?事实上,本文的主角是OpenCV中的morphologyEx函数,它利用基本的膨胀和腐蚀技术,来执行更加高级的形态学变换,如开闭运算,形态学梯度,“顶帽”、“黑帽”等等。这一节我们来一起看一下morphologyEx函数的源代码。

    //-----------------------------------【erode()函数中文注释版源代码】----------------------------   
    void cv::morphologyEx( InputArray _src,OutputArray _dst, int op,InputArray kernel, Pointanchor, int iterations,
                           int borderType, constScalar& borderValue )
    {
    //拷贝Mat数据到临时变量
       Mat src = _src.getMat(), temp;
       _dst.create(src.size(), src.type());
       Mat dst = _dst.getMat();
     
    //一个大switch,根据不同的标识符取不同的操作
       switch( op )
        {
       case MORPH_ERODE:
           erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
           break;
       case MORPH_DILATE:
           dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
           break;
       case MORPH_OPEN:
           erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
           dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue );
           break;
       case CV_MOP_CLOSE:
           dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
           erode( dst, dst, kernel, anchor, iterations, borderType, borderValue );
           break;
       case CV_MOP_GRADIENT:
           erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
           dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
           dst -= temp;
           break;
       case CV_MOP_TOPHAT:
           if( src.data != dst.data )
               temp = dst;
           erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
            dilate( temp, temp, kernel, anchor,iterations, borderType, borderValue );
           dst = src - temp;
           break;
       case CV_MOP_BLACKHAT:
           if( src.data != dst.data )
               temp = dst;
           dilate( src, temp, kernel, anchor, iterations, borderType, borderValue);
           erode( temp, temp, kernel, anchor, iterations, borderType, borderValue);
           dst = temp - src;
           break;
       default:
           CV_Error( CV_StsBadArg, "unknown morphological operation" );
        }
    }
    看上面的源码可以发现,其实morphologyEx函数其实就是内部一个大switch而已。根据不同的标识符取不同的操作。比如开运算MORPH_OPEN,按我们上文中讲解的数学表达式,就是先腐蚀后膨胀,即依次调用erode和dilate函数,为非常简明干净的代码。

    三、函数参数介绍

    C++: void morphologyEx(InputArray src,OutputArray dst,int op,InputArraykernel,Pointanchor=Point(-1,-1),
    intiterations=1,intborderType=BORDER_CONSTANT,constScalar& borderValue=morphologyDefaultBorderValue() );

    • 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。图像位深应该为以下五种之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
    • 第二个参数,OutputArray类型的dst,即目标图像,函数的输出参数,需要和源图片有一样的尺寸和类型。
    • 第三个参数,int类型的op,表示形态学运算的类型,可以是如下之一的标识符:
      • MORPH_OPEN – 开运算(Opening operation)
      • MORPH_CLOSE – 闭运算(Closing operation)
      • MORPH_GRADIENT -形态学梯度(Morphological gradient)
      • MORPH_TOPHAT - “顶帽”(“Top hat”)
      • MORPH_BLACKHAT - “黑帽”(“Black hat“)

    另有CV版本的标识符也可选择,如CV_MOP_CLOSE,CV_MOP_GRADIENT,CV_MOP_TOPHAT,CV_MOP_BLACKHAT,这应该是OpenCV1.0系列版本遗留下来的标识符,和上面的“MORPH_OPEN”一样的效果。

     

    • 第四个参数,InputArray类型的kernel,形态学运算的内核。若为NULL时,表示的是使用参考点位于中心3x3的核。我们一般使用函数 getStructuringElement配合这个参数的使用。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或morphologyEx函数时,kernel参数填保存getStructuringElement返回值的Mat类型变量。对应于我们上面的示例,就是填element变量。

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

        其中的这些操作都可以进行就地(in-place)操作。且对于多通道图像,每一个通道都是单独进行操作。




    展开全文
  • 在 简单的图像处理——1. 图像的形态学操作:膨胀与腐蚀 中,我们介绍了图像基本的形态学操作——膨胀与腐蚀,同时也利用了Python进行了实现。在这里我们将接着上次的内容,接着描述其它的一些图像形态学操作方法,...
  • 2 图像闭运算(先膨胀,后腐蚀) 2.1 基本原理 2.2 代码示例 3 图像梯度运算(膨胀—腐蚀) 3.1 基本原理 3.2 代码示例 参考资料 前面介绍了 形态学处理——图像腐蚀与图像膨胀,图像膨胀会扩大一幅图像的组成...
  • 图像处理】-021 开运算闭运算   上一篇中说到了图像的形态学操作,介绍了腐蚀和膨胀。由于腐蚀和膨胀都会对目标的面积产生较大的影响(依据操作元素的大小),影响图像中正常目标的判断。在形态学操作中,还有...
  • 二值图像形态学运算图像形态学运算的基础。二值图像形态学运算的过程就是在图像...二值图像的形态学处理的基本运算有腐蚀、膨胀、开运算闭运算,击中与击不中、骨架抽取等。注意,本文所有例子都是24位真彩色图...
  • (数字图像处理)腐蚀/膨胀/开运算/闭运算 腐蚀:是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的物体。 膨胀:是将与物体接触的所有背景点合并到该物体中,使边界向外部扩张的过程。可以...
  • 所以,本文的主角是OpenCV中的morphologyEx函数,它利用基本的膨胀和腐蚀技术,来执行更加高级的形态学变换,如开闭运算、形态学梯度、“顶帽”、“黑帽”等等。 先上几张示例程序的截图吧: 有没有很熟悉这张图?...
  • 二值图像处理闭运算

    2017-05-30 21:53:04
    应用背景:在二值形态学图像处理中,除了腐蚀和膨胀这两种一次运算外,还有二次运算操作,比如前一篇讲到的开运算,这里介绍的闭运算也是一种二次运算操作。
  • 二值图像处理开运算

    2017-06-28 11:23:04
    应用背景:在二值形态学图像处理中,除了腐蚀和膨胀这两种一次运算外,还有二次运算操作,开运算就是其中一种。
  • 图像开闭运算

    2017-11-30 20:50:48
    matlab图像处理形态学滤波之开运算闭运算(1)  刚入门的朋友估计对开闭运算还不太了解,首先先了解几个名词: 腐蚀: 是一种消除边界点,使边界向内部收缩的过程。可以用来消除小且无意义的物体...
  • 能对灰度图像进行基本的形态学处理,包括图像的腐蚀、膨胀、开运算闭运算
  • python 图像开闭运算

    2017-11-07 21:55:15
    开运算闭运算就是将腐蚀和膨胀按照一定的次序进行处理。但这两者并不是可逆的,即先并不能得到原先的图像闭运算用来连接被误分为许多小块的对象,而开运算用于移除由图像噪音形成的斑点。 闭运算操作...
  • 前面介绍了 形态学处理——图像开运算图像闭运算,其中: 图像开运算:先腐蚀,后膨胀。一般会平滑物体的轮廓、断开较窄的狭颈并消除细的突出物。 图像闭运算:先膨胀,后腐蚀。同样也会平滑轮廓的一部分。但与...
  • 图像处理技术中,有一些的操作会对图像的形态发生改变,这些操作一般称之为形态学操作(phology)。数学形态学是基于集合论的图像处理方法,最早出现在生物学的形态与结构中,图像处理中的形态学操作用于图像与...
  • 1.开运算 形态学开运算操作能去除噪声及平滑目标边界等功能,其定义为: (先腐蚀后膨胀) 其主要作用是消除图像中小于结构元素的细节部分,物体的局部形状不变。物体较背景明亮时能够消除小区域物体,消除高于...
  • %开运算闭运算的作用 f=imread('fingerprint.tif'); subplot(3,2,1),imshow(f),title('原图像') se=strel('square',3);%结构元素 fo=imopen(f,se);%开运算 subplot(3,2,2),imshow(fo),title('开运算后的图像') ...
1 2 3 4 5 ... 20
收藏数 103,717
精华内容 41,486