【拜小白opencv】43-形态学滤波——综合示例【腐蚀、膨胀、开运算、闭运算、顶帽、黑帽 形态学梯度、内部梯度、外部梯度、X方向梯度、Y方向梯度】

来源:互联网 发布:金星舞蹈水平 知乎 编辑:程序博客网 时间:2024/05/29 18:48

常言道“温故而知新”,写此文章就是对自己目前学习内容的小小的总结与记录。

本文力求用最简洁的语言,详细的代码将此部分内容讲解清楚,但由于博主同样是刚刚接触OpenCV,或许表达上有些瑕疵,还望读者能够指教探讨,大家共同进步。

博主机器配置为:VS2013+opencv2.4.13+Win-64bit。

若本文能给读者带来一点点启示与帮助,我就很开心了。

====================分割线====================


本次,将前几篇关于形态学滤波的一些操作,综合了一下,编写了一个程序,可以操作这几种方法。 

一共实现了11种操作:腐蚀、膨胀、开运算、闭运算、顶帽、黑帽、形态学梯度(又为基本梯度)、内部梯度、外部梯度、X方向梯度、Y方向梯度

放一张思维导图,看不清的话,右键进行保存。




首先,还是先介绍每个操作是什么。 为方便,请直接点击链接,进行相关的查看。

腐蚀】—— 【拜小白opencv】36-形态学滤波1——腐蚀

膨胀】—— 【拜小白opencv】37-形态学滤波2——膨胀

开运算】—— 【拜小白opencv】38-形态学滤波3——开运算

闭运算】—— 【拜小白opencv】39-形态学滤波4——闭运算

顶帽】—— 【拜小白opencv】41-形态学滤波6——顶帽运算(OR礼帽运算、高帽运算)

黑帽】—— 【拜小白opencv】42-形态学滤波7——黑帽运算

形态学滤波】 以及内部梯度、外部梯度、X方向梯度、Y方向梯度都在这篇文章中——【拜小白opencv】40-形态学滤波5——形态学梯度(基本梯度、内部梯度、外部梯度、方向梯度)

=====================分割线===================

1-代码演示

/*功能:综合示例——形态学滤波一共包含11中操作:腐蚀、膨胀、开运算、闭运算、顶帽、黑帽形态学梯度(又为基本梯度)、内部梯度、外部梯度、X方向梯度、Y方向梯度*/#include <opencv2/core/core.hpp>                  #include <opencv2/highgui/highgui.hpp>                  #include <opencv2/imgproc/imgproc.hpp>                 #include <iostream> using namespace cv;using namespace std;#define WINDOWNAME "【形态学滤波-效果图】"//-------------------【全局变量声明部分】------------------------Mat g_srcImage; //源图像Mat g_dstImage; //得到的效果图int g_nElementShape = MORPH_RECT;//元素结构的形状int g_nStructElementSize = 3;//结构元素(内核矩阵)的尺寸int g_nMaxNum = 21; //内核最大值int g_nTypeChoice = 0; //形态学操作类型选择//-------------------【全局函数声明部分】------------------------void on_TrackbarNumChange(int, void*); //类型选择-回调函数void on_ElementSizeChange(int, void*); //内核大小变换-回调函数void ShowHelpText();//帮助文字显示void Process();//对应的形态学操作void ErodeProcess();//腐蚀操作void DilateProcess();//膨胀操作void OpenProcess();//开运算操作void CloseProcess();//闭运算操作void TopHatProcess();//顶帽操作void BlackHatProcess();//黑帽操作void GradienteProcess();//形态学梯度操作-即基本梯度void InternalGradientProcess();//内部梯度操作void ExternalGradientProcess();//外部操作void xDirectGradientProcess();//X方向梯度操作void yDirectGradientProcess();//Y方向梯度操作//--------------------------------【主函数】------------------------------int main(){//载入图像g_srcImage = imread("D:\\OutPutResult\\ImageTest\\ju.jpg");if (!g_srcImage.data){cout << "读取图片错误,请重新输入正确路径!\n";system("pause");return -1;}namedWindow("【原始图】", WINDOW_AUTOSIZE);namedWindow(WINDOWNAME, WINDOW_AUTOSIZE);imshow("【原始图】", g_srcImage);//显示原始图ShowHelpText();//创建轨迹条createTrackbar("类型选择", WINDOWNAME, &g_nTypeChoice, 10, on_TrackbarNumChange);createTrackbar("内核", WINDOWNAME, &g_nStructElementSize, g_nMaxNum, on_ElementSizeChange);//轮询获取按键信息while (1){//执行回调函数on_TrackbarNumChange(g_nTypeChoice, 0);on_ElementSizeChange(g_nStructElementSize, 0);//获取按键int c;c = waitKey(0);//按下键盘Q键或者ESC,程序退出if ((char)c == 'q' || (char)c == 27 || (char)c == 'Q')break;//按下键盘按键1,使用矩形(Rectangle)结构元素MORPH_RECT   if ((char)c == 49)//键盘按键1的ASII码为49g_nElementShape = MORPH_RECT;//按下键盘按键2,使用十字形(Cross)结构元素MORPH_CROSS  else if ((char)c == 50)//键盘按键2的ASII码为50g_nElementShape = MORPH_CROSS;//按下键盘按键3,使用椭圆(Elliptic)结构元素MORPH_ELLIPSEelse if ((char)c == 51)//键盘按键3的ASII码为51g_nElementShape = MORPH_ELLIPSE;}return 0;}//------------【on_TrackbarNumChange()函数】-------------void on_TrackbarNumChange(int, void*){//类型之间效果已经切换,回调函数体内需调用一次对应的操作函数,使改变后的效果立即生效并显示出来Process();}//------------【on_ElementSizeChange()函数】--------------void on_ElementSizeChange(int, void*){//内核尺寸已改变,回调函数体内需调用一次Process函数,使改变后的效果立即生效并显示出来Process();}//------------【进行对应的形态学操作】--------------void Process(){switch (g_nTypeChoice){case 0:ErodeProcess(); break;case 1:DilateProcess(); break;case 2:OpenProcess(); break;case 3:CloseProcess(); break;case 4:TopHatProcess(); break;case 5:BlackHatProcess(); break;case 6:GradienteProcess(); break;case 7:InternalGradientProcess(); break;case 8:ExternalGradientProcess(); break;case 9:xDirectGradientProcess(); break;case 10:yDirectGradientProcess(); break;}}//-----------【描述:进行腐蚀操作】-----------void ErodeProcess(){Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核erode(g_srcImage, g_dstImage, element);//进行腐蚀或膨胀操作imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行膨胀操作】-----------void DilateProcess(){Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核dilate(g_srcImage, g_dstImage, element);//进行膨胀操作imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行开运算操作】-----------void OpenProcess(){Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核morphologyEx(g_srcImage, g_dstImage, MORPH_OPEN, element);//进行开运算操作:先腐蚀后膨胀imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行闭运算操作】-----------void CloseProcess(){Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核morphologyEx(g_srcImage, g_dstImage, MORPH_CLOSE, element);//进行闭运算操作:先膨胀再腐蚀imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行顶帽操作】-----------void TopHatProcess(){Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);//进行顶帽操作:原图像与开运算结果图之差imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行黑帽操作】-----------void BlackHatProcess(){Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);//进行黑帽操作:闭运算结果图与原图像之差imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行形态学梯度操作】-----------void GradienteProcess(){Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核morphologyEx(g_srcImage, g_dstImage, MORPH_GRADIENT, element);//进行形态学梯度操作:膨胀图像与腐蚀图像的之差imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行内部梯度操作】-----------void InternalGradientProcess(){Mat erode_ouput;Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核morphologyEx(g_srcImage, erode_ouput, MORPH_ERODE, element);//进行腐蚀操作subtract(g_srcImage, erode_ouput, g_dstImage, Mat());//计算内部梯度:原图像减去腐蚀之后的图像imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行外部梯度操作】-----------void ExternalGradientProcess(){Mat dilate_output;Mat element = getStructuringElement(g_nElementShape, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1));//获取自定义核morphologyEx(g_srcImage, dilate_output, MORPH_DILATE, element);//进行膨胀操作subtract(dilate_output, g_srcImage, g_dstImage, Mat());//计算外部梯度:膨胀后的图像减去原图像imshow(WINDOWNAME, g_dstImage);//显示效果图}//-----------【描述:进行X方向梯度操作】-----------void xDirectGradientProcess(){if (g_nStructElementSize == 0){imshow(WINDOWNAME, g_srcImage);//显示原图}else{Mat hse = getStructuringElement(g_nElementShape, Size(g_srcImage.cols / g_nStructElementSize, 1));Mat erode_direct, dilate_direct;erode(g_srcImage, erode_direct, hse);dilate(g_srcImage, dilate_direct, hse);subtract(dilate_direct, erode_direct, g_dstImage, Mat()); // X 方向梯度:膨胀与腐蚀之后得到图像求差值  imshow(WINDOWNAME, g_dstImage);//显示效果图}}//-----------【描述:进行Y方向梯度操作】-----------void yDirectGradientProcess(){if (g_nStructElementSize == 0){imshow(WINDOWNAME, g_srcImage);//显示原图}else{Mat vse = getStructuringElement(g_nElementShape, Size(1, g_srcImage.rows / g_nStructElementSize));Mat erode_direct, dilate_direct;erode(g_srcImage, erode_direct, vse);dilate(g_srcImage, dilate_direct, vse);subtract(dilate_direct, erode_direct, g_dstImage, Mat()); // Y 方向梯度:膨胀与腐蚀之后得到图像求差值  imshow(WINDOWNAME, g_dstImage);//显示效果图}}//------------------【程序一些提示操作信息】-----------------void ShowHelpText(){cout << "-----------------------------------------------------------" << endl;cout << "\t请调整滚动条观察效果\n" << endl;cout << "\t按键操作说明:" << endl;cout << "\t\t键盘按键【Esc】或者【Q】-退出程序" << endl;cout << "\t\t键盘按键【1】--使用矩形<Rectangle>结构内核" << endl;cout << "\t\t键盘按键【2】--使用十字形<Cross-shaped>结构内核" << endl;cout << "\t\t键盘按键【3】--使用椭圆<Elliptic>结构内核" << endl;cout << "-----------------------------------------------------------" << endl;cout << "\t类型选择说明:" << endl;cout << "\t\t0——腐蚀" << endl;cout << "\t\t1——膨胀" << endl;cout << "\t\t2——开运算" << endl;cout << "\t\t3——闭运算" << endl;cout << "\t\t4——顶帽操作" << endl;cout << "\t\t5——黑帽操作" << endl;cout << "\t\t6——形态学梯度(基本梯度)" << endl;cout << "\t\t7——内部梯度" << endl;cout << "\t\t8——外部梯度" << endl;cout << "\t\t9——X方向梯度" << endl;cout << "\t\t10——Y方向梯度" << endl;}

=====================分割线====================

2-显示结果

【原图像】


【0-腐蚀结果-见下图】


【1-膨胀结果-见下图】


【2-开运算结果-见下图】


【3-闭运算结果-见下图】


【4-顶帽结果-见下图】


【5-黑帽结果-见下图】


【6-形态学梯度结果-见下图】


【7-内部梯度结果-见下图】


【8-外部结果-见下图】


【9-X方向梯度结果-见下图】


【10-Y方向梯度结果-见下图】


======================分割线====================

3-程序解释

1)窗口【形态学滤波-效果图】中写的内核,并不是真正内核的大小,而应该是Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1)。显示是仅是g_nStructElementSize 的值,要注意区分。

2)可以在窗口【形态学滤波-效果图】上,通过按数字【1】、【2】、【3】来改变内核的形状,有三种,矩形、十字形、椭圆形。

=====================END=======================

阅读全文
1 0
原创粉丝点击