我的OpenCV学习笔记(16):利用工具条调用基本的形态学操作

我的OpenCV学习笔记(16):利用工具条调用基本的形态学操作

http://blog.csdn.net/thefutureisour/article/details/7565726?locationNum=1&fps=1

标签: 工具image图像处理测试
 分类:

这次主要介绍两方面的内容,一部分是形态学操作,另一部分是工具条。

先说形态学操作。这里只介绍4种简单的:腐蚀、膨胀、开、闭。最基本的形态学操作是腐蚀和膨胀。其他的操作可以通过腐蚀和膨胀推导出来。

用集合论的观点介绍他们非常麻烦。这里换一种思路:我们先做一定的假设:对于一幅图像:前景(我们感兴趣的部分)是白色的;背景(不感兴趣的部分)是黑色的。然后就可以望文生义一下了:腐蚀操作会使得前景变小,而膨胀会使得前景变大。这主要是当结构元(用来对图像处理的基本模版)作用于图像的边沿时,两种操作的定义引起的。腐蚀操作时只有当整个结构元都在图像边沿内时,锚点(结构元与图像中每个像素对齐的点,通常取作结构元的几何中心)对准的像素才会被保留,判为前景;否则这个点判为背景。膨胀操作则是只要结构元与图像有交集时,锚点对准的像素就会被保留,判为前景。腐蚀可以用来消除一些小的误检测的前景;而膨胀则可以填充一些小洞。

注意到,用3*3的模板腐蚀3次与用7*7的模板腐蚀一次效果是相同的。膨胀的结果可以类推。

有了这两个运算的基本定义,我们就可以定义开运算和闭运算了:开运算就是腐蚀以后再膨胀,而闭运算是膨胀以后再腐蚀。闭运算使得小洞被填上,临近的目标连接到了一起(任何结构元容纳不下的小洞或者缝隙都会被填充)。而开运算则会除去一些小的斑点。

对一幅图像多次使用开运算而闭运算是没有意义的。这与腐蚀和膨胀不同。

在OpenCV中,使用erode和dilate实现腐蚀与膨胀。要实现开运算或者闭运算,当然可以通过腐蚀完以后膨胀之类的方法完成,但是OpenCV通过了一个函数morphologyEx,通过改变函数中的参数来实现不同的形态学运算。下面的代码对这4种运算进行了简单的说明:

[cpp] view plain copy
 
  1. #include <opencv2/core/core.hpp>  
  2. #include <opencv2/highgui/highgui.hpp>  
  3. #include <opencv2/imgproc/imgproc.hpp>  
  4.   
  5. using namespace cv;  
  6. int main( void )  
  7. {  
  8.     Mat image = imread("D:/picture/images/binary.bmp");  
  9.     if(!image.data)  
  10.         return -1;    
  11.     imshow("源图像",image);  
  12.   
  13.     //腐蚀操作  
  14.     Mat eroded;  
  15.     //默认情况下,结构元为3*3  
  16.     erode(image,eroded,Mat());  
  17.     erode(eroded,eroded,Mat());  
  18.     erode(eroded,eroded,Mat());  
  19.     imshow("腐蚀结果",eroded);  
  20.   
  21.     //使用自定义的结构元  
  22.     Mat element(7,7,CV_8U,Scalar(1));  
  23.     erode(image,eroded,element);  
  24.     imshow("7*7结构元腐蚀结果",eroded);  
  25.       
  26.     //使用默认的结构元重复操作也能得到相同的结果  
  27.     erode(image,eroded,Mat(),Point(-1,-1),3);  
  28.     imshow("使用默认结构元重复3次",eroded);  
  29.   
  30.     //膨胀操作  
  31.     Mat dilated;  
  32.     dilate(image,dilated,Mat());  
  33.     imshow("膨胀结果",dilated);  
  34.   
  35.     //使用闭运算  
  36.     Mat element5(5,5,CV_8U,Scalar(1));  
  37.     Mat closed;  
  38.     morphologyEx(image,closed,cv::MORPH_CLOSE,element5);  
  39.     imshow("5*5结构元闭运算",closed);  
  40.   
  41.     //通过先膨胀再腐蚀的方法得到闭运算  
  42.     Mat result;  
  43.     dilate(image,result,element5);  
  44.     erode(result,result,element5);  
  45.     imshow("先膨胀,再腐蚀等于闭运算",result);  
  46.   
  47.     //使用开运算  
  48.     Mat opened;  
  49.     morphologyEx(image,opened,cv::MORPH_OPEN,element5);  
  50.     imshow("5*5结构元开运算",opened);  
  51.   
  52.     //先闭运算再开运算  
  53.     morphologyEx(image,result,cv::MORPH_CLOSE,element5);  
  54.     morphologyEx(result,result,cv::MORPH_OPEN,element5);  
  55.     imshow("先闭运算,在开运算",result);  
  56.       
  57.     waitKey(0);  
  58.     return 0;  
  59. }  


 

下面我们着重看如何使用工具条。

在OpenCV中,使用createTrackbar函数来创建工具条。第一个参数是工具条的名字,第二个参数是工具条要放到哪个窗口上(说来惭愧,我以前一直觉得namedWindow这句话很多余,直接在imshow的时候填上窗口名就行了,干嘛非要namedWindow呢?现在才发现了它的作用),第三个参数是工具条改变的是哪个值(顺带设定了初始位置也是这个值),第四个参数是改变的值的最大值。第五个参数是这个值是作用于哪个函数的。第六个值是用户传给回调函数的数据。不过因为我这里使用的是全局变量,所以没有使用最后一个参数。

下面看看程序:

[cpp] view plain copy
 
  1. #include <opencv2/core/core.hpp>  
  2. #include <opencv2/highgui/highgui.hpp>  
  3. #include <opencv2/imgproc/imgproc.hpp>  
  4. #include <iostream>  
  5.   
  6. using namespace cv;  
  7. using namespace std;  
  8.   
  9. //定义全局变量:  
  10. Mat image;  
  11. Mat eroded;  
  12. Mat dilated;  
  13. Mat opened;  
  14. Mat closed;  
  15.   
  16. //测试的形态学运算:腐蚀、膨胀、开、闭  
  17. //为每个形态学运算创建一个控件  
  18. //控件需要的参数:  
  19. //每种形态学操作需要单独确定的参数:  
  20. //结构元的种类:  
  21. int erosion_element = 0;  
  22. int dilation_element = 0;  
  23. int open_element = 0;  
  24. int close_element = 0;  
  25. //结构元的大小  
  26. int erosion_size = 0;  
  27. int dilation_size = 0;  
  28. int open_size = 0;  
  29. int close_size = 0;  
  30.   
  31. //四种形态学操作共用的参数  
  32. //结构元种类的最大值:一个3种:正方形、十字、椭圆  
  33. int const max_elements = 2;  
  34.   
  35. //结构元的最大值(四种共用一个)  
  36. int const max_kernel_size = 5;  
  37.   
  38.   
  39. //工具条的回调函数  
  40. void Erosion(int,void*);  
  41. void Dilation(int,void*);  
  42. void Open(int, void*);  
  43. void Close(int,void*);  
  44.   
  45. int main()  
  46. {  
  47.     cout<<"结构元类型:0-矩形,1-十字,2-椭圆"<<endl;  
  48.     cout<<"结构元大小:2*n+1"<<endl;  
  49.     image = imread("D:/picture/images/binary.bmp");  
  50.     if(!image.data)  
  51.         return -1;    
  52.     imshow("源图像",image);  
  53.   
  54.     eroded.create(image.rows,image.cols,image.type());  
  55.     dilated.create(image.rows,image.cols,image.type());  
  56.   
  57.     namedWindow("腐蚀");  
  58.     namedWindow("膨胀");  
  59.     namedWindow("开运算");  
  60.     namedWindow("闭运算");  
  61.   
  62.     //创建工具条  
  63.     //腐蚀操作:  
  64.     createTrackbar("核函数类型","腐蚀",&erosion_element,max_elements,Erosion);  
  65.     createTrackbar("核函数大小","腐蚀",&erosion_size,max_kernel_size,Erosion);  
  66.     //调用腐蚀函数  
  67.     Erosion(0,0);  
  68.   
  69.     //膨胀操作  
  70.     createTrackbar("结构元类型","膨胀",&dilation_element,max_elements,Dilation);  
  71.     createTrackbar("结构元大小","膨胀",&dilation_size,max_kernel_size,Dilation);  
  72.     Dilation(0,0);  
  73.   
  74.     //开操作  
  75.     createTrackbar("结构元类型","开运算",&open_element,max_elements,Open);  
  76.     createTrackbar("核函数大小","开运算",&open_size,max_kernel_size,Open);  
  77.     Open(0,0);  
  78.   
  79.     //闭操作  
  80.     createTrackbar("结构元类型","闭运算",&close_element,max_elements,Close);  
  81.     createTrackbar("核函数大小","闭运算",&close_size,max_kernel_size,Close);  
  82.     Close(0,0);  
  83.     waitKey(0);  
  84.     return 0;  
  85. }  
  86.   
  87. //回调函数:  
  88. //腐蚀函数:不需要输入参数  
  89. void Erosion(int,void*)  
  90. {  
  91.     int erosion_type;  
  92.     if(erosion_element == 0)  
  93.     {  
  94.         erosion_type = MORPH_RECT;  
  95.     }  
  96.     else if(erosion_element == 1)  
  97.     {  
  98.         erosion_type = MORPH_CROSS;  
  99.     }  
  100.     else if(erosion_element == 2)  
  101.     {  
  102.         erosion_type = MORPH_ELLIPSE;  
  103.     }  
  104.     //获取腐蚀元素:参数为:类型、大小、锚点  
  105.     Mat element = getStructuringElement(erosion_type,Size(2*erosion_size+1,2*erosion_size+1),Point(-1,-1));  
  106.     //进行腐蚀运算:参数为:原图像、结果、腐蚀元素  
  107.     erode(image,eroded,element);  
  108.     //显示腐蚀结果  
  109.     imshow("腐蚀",eroded);  
  110. }  
  111.   
  112. //膨胀回调函数  
  113. void Dilation(int,void*)  
  114. {  
  115.     int dilation_type;  
  116.     if(dilation_element == 0)  
  117.     {  
  118.         dilation_type = MORPH_RECT;  
  119.     }  
  120.     else if(dilation_element == 1)  
  121.     {  
  122.         dilation_type = MORPH_CROSS;  
  123.     }  
  124.     else if(dilation_element == 2)  
  125.     {  
  126.         dilation_type = MORPH_ELLIPSE;  
  127.     }  
  128.     //获取腐蚀元素:参数为:类型、大小、锚点  
  129.     Mat element = getStructuringElement(dilation_type,Size(2*dilation_size+1,2*dilation_size+1),Point(-1,-1));  
  130.     //进行腐蚀运算:参数为:原图像、结果、腐蚀元素  
  131.     dilate(image,dilated,element);  
  132.     //显示腐蚀结果  
  133.     imshow("膨胀",dilated);  
  134. }  
  135. void Open(int, void*)  
  136. {  
  137.     int open_type;  
  138.     if(open_element == 0)  
  139.     {  
  140.         open_type = MORPH_RECT;  
  141.     }  
  142.     else if(open_element == 1)  
  143.     {  
  144.         open_type = MORPH_CROSS;  
  145.     }  
  146.     else if(open_element == 2)  
  147.     {  
  148.         open_type = MORPH_ELLIPSE;  
  149.     }  
  150.     //获取腐蚀元素:参数为:类型、大小、锚点  
  151.     Mat element = getStructuringElement(open_type,Size(2*open_size+1,2*open_size+1),Point(-1,-1));  
  152.     //进行开运算  
  153.     morphologyEx(image,opened,cv::MORPH_OPEN,element);  
  154.     imshow("开运算",opened);  
  155. }  
  156.   
  157. //闭操作  
  158. void Close(int,void*)  
  159. {  
  160.     int close_type;  
  161.     if(close_element == 0)  
  162.     {  
  163.         close_type = MORPH_RECT;  
  164.     }  
  165.     else if(close_element == 1)  
  166.     {  
  167.         close_type = MORPH_CROSS;  
  168.     }  
  169.     else if(close_element == 2)  
  170.     {  
  171.         close_type = MORPH_ELLIPSE;  
  172.     }  
  173.     //获取腐蚀元素:参数为:类型、大小、锚点  
  174.     Mat element = getStructuringElement(close_type,Size(2*close_size+1,2*close_size+1),Point(-1,-1));  
  175.     //进行开运算  
  176.     morphologyEx(image,closed,cv::MORPH_CLOSE,element);  
  177.     imshow("闭运算",closed);  
  178. }  


美中不足的是,为了改变形态学操作的结构元种类和大小,我定义了许多的全局变量。

如果想知道形态学操作的更多内容,还是看冈萨雷斯的那本经典的《数字图像处理》吧!

posted @ 2017-05-07 23:07  sky20080101  阅读(128)  评论(0)    收藏  举报