最近很多东西都是在不断的去温习与补充,对于形态学这一块确实没咋了解,昨天花了点时间看看一些牛人的博客,还是从原理,目的,例子以及源码这一套流程来分析。

主要参考博客链接: http://blog.csdn.net/dcrmg/article/details/52265949

以及浅墨:http://blog.csdn.net/poem_qianmo/article/details/23710721

还有:http://blog.csdn.net/fred_yang2013/article/details/12029899

形态学算子,一般情况下形态学处理的都是二值图像。这样效果才明显。

常用的图像形态学操作包括膨胀、腐蚀、闭运算、开运算。
膨胀操作会扩大(粗化)图像中物体的轮廓,可以用来弥补(填充)物体间的孔洞,强化离散点,代价是导致物体的面积比原来的面积要大。
腐蚀操作会收缩(细化)图像中物体的轮廓,可以用来断开(分离)物体间的连接,消除离散点,代价是导致物体的面积比原来的面积要小。
闭运算是使用同一结构元对图像进行先膨胀后腐蚀的操作,可以用来弥合较窄的间断和细长的沟壑,消除物体间小的孔洞,填补轮廓线中的断裂。
开运算是使用同一结构元对图像进行先腐蚀后膨胀的操作,可以用来平滑物体的轮廓,断开物体间较窄的连接,消除物体边沿尖锐的突出部分。

下面Samples要用到的图片

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

这些形态学操作都涉及到一个关键的因子——结构元。结构元基本的形态是矩形、十字形或椭圆形(圆形)。

结构元素就相当于我们在滤波中所涉及到的模板,也就是说它是一个给定像素的矩阵,这个矩阵可以是任意形状的,但是一般情况下都是正方形,圆形或者菱形的但是在结构元素中有一个中心点(也叫做anchor point)。和模板中心一样,处理后的结果赋值给和这个中心点对齐的像素点。处理的过程也是基本相同。
结构元素和卷积模板的区别在于,

膨胀是以集合运算为基础的,卷积是以算数运算为基础的。

膨胀:膨胀就是求局部最大值的操作。
1. 用结构元素,扫描图像的每一个像素
2. 用结构元素与其覆盖的二值图像做“与”操作
3. 如果都为0,结果图像的该像素为0。否则为1
也就是在结构元素覆盖范围下,只要有一个像素符和结构元素像素相同,那么中心点对应点就为1,否则为0

腐蚀:腐蚀就是求局部最小值的操作
1. 用结构元素,扫描图像的每一个像素
2. 用结构元素与其覆盖的二值图像做“与”操作
3. 如果都为1,结果图像的该像素为1。否则为0
也就是查找被处理图像中能不能找到和结构元素相同的矩阵。如果存在那么中心点所对应的点就为1,否则为0.

原文作者还用矩阵输出演示了一张图,十分形象,大家可以去看看

然后彩色图像的处理,以及局部最大值最小值的理解,大家直接去看浅墨的博客;(链接都在文章开头

但是对于这个膨胀示意过程的图片,我只想说一句,A表示的高亮区域,不是整张图,搞得我还疑惑了一阵子,腐蚀也是类似。

其他的就没什么好说的

代码我对浅墨的稍微改动了一下:增加了对迭代次数的控制

先看看OpenCV的dilate(膨胀参数详解吧!    (erode)腐蚀类似

C++: void dilate(InputArray src,OutputArray dst,InputArray kernel,Point anchor=Point(-1, 1),int iteration=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的核.我们一般使用函数getStructuringElemnet配合这个参数的使用。getStructuringElement函数会返回指定形状
和尺寸的结构元素(内核矩阵)。其中,getStructuringElemnet函数的第一个参数表示内核的形状,我们可以选择如下三种形状之一:矩形: 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 ));/*第四个参数, Point类型的anchor,锚的位置,其由默认值(-1, -1),表示锚位于中心。第五个参数, int类型的iterations, 迭代使用erode()函数的次数,默认值为1。第六个参数, int类型的borderType, 用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT.第七个参数, const Scale &类型的borderValue, 当边界为常数时的边界值,有默认值morphologyDefaultBorderValue(),一般我们不用去管他。需要用到它时,可以看官方文档中的createMorphologyFilter()函数得到更详细的解释.*/

示例的图片我是从牧野(链接我已给出)那里截图的,很好的比较了不同结构元的优缺点,这张图具有代表性,结论我也验证了,效果可能有点偏差

但是不影响。

结论先Copy如下:

从三个不同结构元的膨胀效果分析:
1.  从膨胀和弥合的有效性看,矩形结构元为优。
     可以从第三排中间的闪电形状的孔洞填补上对比出来,其他两个结构元还有孔洞,矩形结构元已经填补完成。 
     也就是说使用相同尺寸的结构元,相比其他两个结构元,矩形结构元能够执行最少次数的膨胀操作达到膨胀和弥合的目的。
2.  从膨胀之后的外形轮廓上分析:
     矩形结构元倾向于使轮廓的拐点处具有水平或垂直分割的特征,上下左右四个方向的边界都是直的。
     十字结构元倾向于使轮廓的拐点处具有四分之一十字结构元形状的锯齿。
     椭圆结构元倾向于使轮廓的拐点处具有更为平滑和圆润的弧线。
     可以简单概括为结构元的形状是什么,就使得膨胀之后的轮廓的拐点处像什么。
3.  从应用场合看,三者各有所长:
      矩形结构元膨胀适用于对外形是规则形状、边沿处无太多尖锐突起的物体,这样可以最大程度保持物体原本的轮廓形状。
      十字结构元膨胀适用于对外形不规则、边沿处有较多尖锐突起的物体,这样可以最大程度保持物体原本的轮廓形状。
      椭圆结构元膨胀适用于要求对物体的轮廓进行平滑圆润处理的物体。

从三个不同结构元的腐蚀效果分析:
1. 从腐蚀的有效性看,矩形结构元为优。
进过同样尺寸同样此时腐蚀后,矩形结构元只剩下部分拐点处的散点没有腐蚀掉,其他两个结构元操作后物体的整 个轮廓仍较为清晰。
2. 从腐蚀之后的外形轮廓上分析:
矩形结构元腐蚀后只剩下部分拐点处的像素点,主要的是非直角的拐点。
十字结构元腐蚀的能力最弱,对所有拐点处都比较敏感。
椭圆结构元也是对所有拐点比较敏感。
3. 从应用场合看,除了矩形结构元所需腐蚀次数较少之外,好像并无其他明显区别。

Samples:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
//#include <Windows.h>using namespace std;
using namespace cv;Mat g_srcImage, g_dstImage;   //原始图和效果图
int g_nTrackbarNumer = 0;  //0表示腐蚀erode, 1表示膨胀dilate
int g_nStructElementSize = 3; //结构元素(内核矩阵)的尺寸
int iteratorNumber = 3;         //迭代次数void Process();  //膨胀和腐蚀的处理函数
void on_TrackbarNumChange( int, void *); //回调函数
void on_ElementSizeChange( int, void *); //回调函数
void on_IteratorNumChange( int, void *); //回调函数char *SourceImage = "【原始图】";
char *DstImage = "【效果图】";int main()
{system("color 5E");g_srcImage = imread("source.jpg");if(g_srcImage.empty()) { cout<< "Where is your picture"<<endl;}namedWindow(SourceImage);imshow(SourceImage,g_srcImage);Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1));erode( g_srcImage,g_dstImage,element);imshow(DstImage,g_dstImage);createTrackbar("腐蚀/膨胀",DstImage,&g_nTrackbarNumer,1,on_TrackbarNumChange);createTrackbar("内核尺寸",DstImage,&g_nStructElementSize, 21, on_ElementSizeChange);createTrackbar("迭代次数",DstImage,&iteratorNumber, 10, on_IteratorNumChange);cout<<endl<<"\t嗯。运行成功,请调整滚动条观察图像效果~\n\n"<<"\t按下“q”键时,程序退出~!\n"<<"\n\n\t\t\t\tby浅墨";while(char(waitKey(1))!= 'q'){}return 0;
}void Process()
{//获取自定义核Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1));//进行腐蚀或膨胀操作if(g_nTrackbarNumer == 0){erode( g_srcImage, g_dstImage, element,Point( g_nStructElementSize,g_nStructElementSize ),iteratorNumber);}else{dilate(g_srcImage,g_dstImage, element,Point( g_nStructElementSize,g_nStructElementSize ),iteratorNumber);}//显示效果图imshow(DstImage,g_dstImage);
}void on_TrackbarNumChange(int, void *)
{Process();
}void on_ElementSizeChange(int, void *)
{Process();
}void on_IteratorNumChange( int, void *)
{Process();
}

效果图如下:可以三个随意控制,然后进行多方位比较

源码我放出来,感兴趣可以研究:

void cv::erode( InputArray src, OutputArray dst, InputArray kernel,Point anchor, int iterations,int borderType, const Scalar& borderValue )
{morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,Point anchor, int iterations,int borderType, const Scalar& borderValue )
{morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}
static void morphOp( int op, InputArray _src, OutputArray _dst,InputArray _kernel,Point anchor, int iterations,int borderType, const Scalar& borderValue )
{Mat src = _src.getMat(), kernel = _kernel.getMat();Size ksize = kernel.data ? kernel.size() : Size(3,3);anchor = normalizeAnchor(anchor, ksize);CV_Assert( anchor.inside(Rect(0, 0, ksize.width, ksize.height)) );_dst.create( src.size(), src.type() );Mat dst = _dst.getMat();if( iterations == 0 || kernel.rows*kernel.cols == 1 ){src.copyTo(dst);return;}if( !kernel.data ){kernel = getStructuringElement(MORPH_RECT, Size(1+iterations*2,1+iterations*2));anchor = Point(iterations, iterations);iterations = 1;}else if( iterations > 1 && countNonZero(kernel) == kernel.rows*kernel.cols ){anchor = Point(anchor.x*iterations, anchor.y*iterations);kernel = getStructuringElement(MORPH_RECT,Size(ksize.width + (iterations-1)*(ksize.width-1),ksize.height + (iterations-1)*(ksize.height-1)),anchor);iterations = 1;}int nStripes = 1;
#if defined HAVE_TBB && defined HAVE_TEGRA_OPTIMIZATIONif (src.data != dst.data && iterations == 1 &&  //NOTE: threads are not used for inplace processing(borderType & BORDER_ISOLATED) == 0 && //TODO: check border typessrc.rows >= 64 ) //NOTE: just heuristicsnStripes = 4;
#endifparallel_for(BlockedRange(0, nStripes),MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue));//Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(),//                                             kernel, anchor, borderType, borderType, borderValue );//f->apply( src, dst );//for( int i = 1; i < iterations; i++ )//    f->apply( dst, dst );
}


当然也可以拿人物彩色图像进行腐蚀,只是有点恐怖片的效果罢了!

膨胀与腐蚀的彻底击破相关推荐

  1. OpenCV(六)形态学操作1--基础:膨胀与腐蚀(回调函数)

    目录 形态学通用API:morphologyEx 一.基础理论 1.邻接关系 (1)四邻接: (2)D邻接: (3) 八邻接: 2.连通性 (1)四连通: (2)八连通: (3)m连通: 3.形态学基 ...

  2. OpenCV——膨胀与腐蚀

    膨胀与腐蚀的主要功能: 1.消除噪声: 2.分割出独立像素,在图像中连接相邻元素: 3.寻找图像中明显的极大值区域和极小值区域: 4.求图像梯度: 膨胀是求局部最大值的操作: 膨胀和腐蚀操作都是将图像 ...

  3. 形态学处理:膨胀、腐蚀、开运算、闭运算、形态学梯度、顶帽、黑帽

    形态学处理 一 膨胀 二 腐蚀 三 开运算 四 闭运算 五 形态学梯度 六 顶帽 七 黑帽 形态学处理 一 膨胀  代码: #include <opencv2/core/core.hpp> ...

  4. matlab腐蚀膨胀代码_(三十二)形态学----膨胀和腐蚀

    时间为友,记录点滴. 我们在<初始滤波之均值滤波>中有聊过滤波的本质,以及介绍了其中一种线性滤波(均值滤波).对于常见的非线性滤波"中值滤波"也在<视频的读取和处 ...

  5. OpenCvSharp 形态学操作(膨胀、腐蚀)

    什么是形态学操作 用数学形态学(也称图像代数)表示以形态为基础对图像进行分析的数学工具.基本思想是用具有一定形态的结构元素去度量和提取图像中的对应形状以达到对图像分析和识别的目的. 形态学图像处理的数 ...

  6. python基于水色图像的水质评价_基于Python和遥感图像的膨胀与腐蚀操作

    引言 膨胀与腐蚀是图像形态学中的基本操作,本文将从两个角度实现python的膨胀与腐蚀算法,分别是特征提取与分割后处理.目前,在RGB图像领域,这两种形态学算法经常用于分割结果的处理,例如连通区处理. ...

  7. java 图像膨胀与腐蚀程序_膨胀和腐蚀 - 解决图像缺陷问题

    腐蚀 故名思义就是将图片向内进行收缩. 图1 腐蚀示意图 设经过背景减后的图像为 B,经过腐蚀运算处理后的图像为 P,用 S 表示所用 3R圆(为进化计算可由采用3x3的矩形来代替) 的结构元素,计算 ...

  8. halcon区域腐蚀膨胀算子_OpenCV 图像处理之膨胀与腐蚀

    1.什么是膨胀与腐蚀 膨胀与腐蚀属于形态学范围,具体的含义根据字面意思来理解即可.但是更形象的话就是"增肥"与"减肥". 它们的用途就是用来处理图形问题上.总结 ...

  9. 图像的膨胀与腐蚀、细化

    转自:http://www.opencvchina.com/forum.php?mod=viewthread&tid=1124 原理:在特殊领域运算形式--结构元素(Sturcture Ele ...

最新文章

  1. C++Primer学习——函数
  2. mysql proxies_priv_Mysql5.7.18利用MySQLproxies_priv实现类似用户组管理实例分享
  3. OP07高级电路图-摘自:Reza Moghim
  4. 研发团队平稳度过“从小到大”并非易事
  5. VS Code编译Python
  6. C语言字符串、字符数组
  7. 【Flink】Flink RecordWriterOutput pushToRecordWriter InterruptedException
  8. 【luogu1018】 乘积最大 [区间dp+高精][noip2000]
  9. 【翻译】CryEngine3下的Hair Shader
  10. 权限管理Ranger
  11. Linux 下设置java环境和tomcat安装
  12. vscode配置c++11
  13. python 窗口更新_pythontkinter更新文本窗口
  14. SQLExpress免费版配置本地数据库实例
  15. 省市区三级联动插件(v-distpicker)
  16. 银行考试计算机也需要考金融知识吗,银行招聘考试科技岗考试科目及考试内容...
  17. 通用国籍,民族,亲属关系,证件类型,常见银行数组,可用于选择框,下拉框等
  18. Python 类的知识点
  19. 如何对镶嵌数据集进行色彩平衡
  20. 【设计模式】工厂模式的作用?工厂模式有什么优点?

热门文章

  1. 网易游戏面试经验(三)
  2. Matlab 矩阵分析(一) 矩阵的秩,极大线性无关组和基
  3. php至mysql乱码,PHP彻底解决mysql中文乱码
  4. 海马玩模拟器卸载后怎么恢复Virtualbox
  5. 北大青鸟昌平校区:高中学历可以学UI吗?
  6. java 判断是不是奇数_很火的Java题——判断一个整数是否是奇数
  7. 神经科学领域重大突破,港大科学家揭海马体新功能
  8. SLAM专题(10)- 最小化重投影误差与Bundle Adjustment (BA)
  9. JS中map和foreach的区别以及some和every的用法
  10. 北漂生活第二十一弹-北漂小记、