opencv形态学应用之区域填充

在进行形态学填充之前必须了解一点:当我们的边界是4连通边界时,我们使用的结构元素为8连通;当我们的连通边界为8连通时,我们需要用4连通的结构元素。


算法:

初始化:Bo=种子点(这里采用opencv鼠标操作来手动选取种子点)

循环:

(用3X3十字结构元素对对种子点进行膨胀,然后不断的用图像的补集对膨胀的结果进行约束)

结束条件:膨胀结果不发生变化


    
    
  1. #include<opencv2\opencv.hpp>
  2. #include<iostream>
  3. using namespace std;
  4. using namespace cv;
  5. Point ptStart;
  6. /***************************************************
  7. 功能:以ptStart为起点对图像进行填充
  8. 参数:src-边界图像
  9. ptStart-种子点的坐标
  10. ****************************************************/
  11. void BoundarySeedFill(Mat &src, Point ptStart)
  12. {
  13. Mat dst = Mat::zeros(src.size(), src.type());
  14. int se[ 3][ 3] = { { -1, 1, -1 }, { 1, 1, 1 }, { -1, 1, -1 } }; //十字形结构元素
  15. Mat tempImg = Mat::ones(src.size(), src.type())* 255;
  16. Mat revImg =tempImg - src; //原图像的补集
  17. dst.at<uchar>(ptStart.y, ptStart.x) = 255; //绘制种子点
  18. while ( true) //循环膨胀图像直到图像不在产生变化
  19. {
  20. Mat temp;
  21. dst.copyTo(temp);
  22. dilate(dst, dst, se); //用十字结构元素膨胀
  23. dst = dst&revImg; //限制膨胀不会超过原始边界
  24. if (equalImg(dst, temp)) //不在变化时停止
  25. {
  26. break;
  27. }
  28. }
  29. src = dst;
  30. }
  31. void on_MouseHandle(int event, int x, int y, int flag, void* param)
  32. {
  33. Mat& image = *(cv::Mat*)param;
  34. switch (event)
  35. {
  36. case EVENT_LBUTTONDOWN:
  37. ptStart.x = x;
  38. ptStart.y = y;
  39. break;
  40. case EVENT_LBUTTONUP:
  41. BoundarySeedFill(image, ptStart);
  42. imshow( “边界图像”, image);
  43. break;
  44. }
  45. }
  46. int main()
  47. {
  48. //读取二值图像(此步可以忽略)
  49. Mat src = imread( “test1.jpg”, 0);
  50. imshow( “原始图像”, src);
  51. //创建模板
  52. int se[ 3][ 3] = { { -1, 1, -1 }, { 1, 1, 1 }, { 1, 1, 1 } };
  53. //区域填充
  54. setMouseCallback( “边界图像”, on_MouseHandle, ( void*)&src);
  55. waitKey( 0);
  56. return 0;
  57. }

原始图像:


填充结果:


            </div>

在进行形态学填充之前必须了解一点:当我们的边界是4连通边界时,我们使用的结构元素为8连通;当我们的连通边界为8连通时,我们需要用4连通的结构元素。


算法:

初始化:Bo=种子点(这里采用opencv鼠标操作来手动选取种子点)

循环:

(用3X3十字结构元素对对种子点进行膨胀,然后不断的用图像的补集对膨胀的结果进行约束)

结束条件:膨胀结果不发生变化


  
  
  1. #include<opencv2\opencv.hpp>
  2. #include<iostream>
  3. using namespace std;
  4. using namespace cv;
  5. Point ptStart;
  6. /***************************************************
  7. 功能:以ptStart为起点对图像进行填充
  8. 参数:src-边界图像
  9. ptStart-种子点的坐标
  10. ****************************************************/
  11. void BoundarySeedFill(Mat &src, Point ptStart)
  12. {
  13. Mat dst = Mat::zeros(src.size(), src.type());
  14. int se[ 3][ 3] = { { -1, 1, -1 }, { 1, 1, 1 }, { -1, 1, -1 } }; //十字形结构元素
  15. Mat tempImg = Mat::ones(src.size(), src.type())* 255;
  16. Mat revImg =tempImg - src; //原图像的补集
  17. dst.at<uchar>(ptStart.y, ptStart.x) = 255; //绘制种子点
  18. while ( true) //循环膨胀图像直到图像不在产生变化
  19. {
  20. Mat temp;
  21. dst.copyTo(temp);
  22. dilate(dst, dst, se); //用十字结构元素膨胀
  23. dst = dst&revImg; //限制膨胀不会超过原始边界
  24. if (equalImg(dst, temp)) //不在变化时停止
  25. {
  26. break;
  27. }
  28. }
  29. src = dst;
  30. }
  31. void on_MouseHandle(int event, int x, int y, int flag, void* param)
  32. {
  33. Mat& image = *(cv::Mat*)param;
  34. switch (event)
  35. {
  36. case EVENT_LBUTTONDOWN:
  37. ptStart.x = x;
  38. ptStart.y = y;
  39. break;
  40. case EVENT_LBUTTONUP:
  41. BoundarySeedFill(image, ptStart);
  42. imshow( “边界图像”, image);
  43. break;
  44. }
  45. }
  46. int main()
  47. {
  48. //读取二值图像(此步可以忽略)
  49. Mat src = imread( “test1.jpg”, 0);
  50. imshow( “原始图像”, src);
  51. //创建模板
  52. int se[ 3][ 3] = { { -1, 1, -1 }, { 1, 1, 1 }, { 1, 1, 1 } };
  53. //区域填充
  54. setMouseCallback( “边界图像”, on_MouseHandle, ( void*)&src);
  55. waitKey( 0);
  56. return 0;
  57. }

原始图像:


填充结果:


            </div>

猜你喜欢

转载自blog.csdn.net/monk1992/article/details/81670826