在进行形态学填充之前必须了解一点:当我们的边界是4连通边界时,我们使用的结构元素为8连通;当我们的连通边界为8连通时,我们需要用4连通的结构元素。
算法:
初始化:Bo=种子点(这里采用opencv鼠标操作来手动选取种子点)
循环:
(用3X3十字结构元素对对种子点进行膨胀,然后不断的用图像的补集对膨胀的结果进行约束)
结束条件:膨胀结果不发生变化
- #include<opencv2\opencv.hpp>
- #include<iostream>
- using namespace std;
- using namespace cv;
-
- Point ptStart;
-
-
- /***************************************************
- 功能:以ptStart为起点对图像进行填充
- 参数:src-边界图像
- ptStart-种子点的坐标
- ****************************************************/
- void BoundarySeedFill(Mat &src, Point ptStart)
- {
- Mat dst = Mat::zeros(src.size(), src.type());
- int se[3][3] = { { -1, 1, -1 }, { 1, 1, 1 }, { -1, 1, -1 } };//十字形结构元素
- Mat tempImg = Mat::ones(src.size(), src.type())*255;
- Mat revImg =tempImg - src;//原图像的补集
- dst.at<uchar>(ptStart.y, ptStart.x) = 255;//绘制种子点
- while (true)//循环膨胀图像直到图像不在产生变化
- {
- Mat temp;
- dst.copyTo(temp);
- dilate(dst, dst, se); //用十字结构元素膨胀
- dst = dst&revImg; //限制膨胀不会超过原始边界
- if (equalImg(dst, temp)) //不在变化时停止
- {
- break;
- }
- }
- src = dst;
-
- }
- void on_MouseHandle(int event, int x, int y, int flag, void* param)
- {
- Mat& image = *(cv::Mat*)param;
- switch (event)
- {
- case EVENT_LBUTTONDOWN:
- ptStart.x = x;
- ptStart.y = y;
- break;
- case EVENT_LBUTTONUP:
- BoundarySeedFill(image, ptStart);
- imshow(“边界图像”, image);
- break;
- }
- }
-
- int main()
- {
- //读取二值图像(此步可以忽略)
- Mat src = imread(“test1.jpg”, 0);
- imshow(“原始图像”, src);
-
- //创建模板
- int se[3][3] = { { -1, 1, -1 }, { 1, 1, 1 }, { 1, 1, 1 } };
-
- //区域填充
- setMouseCallback(“边界图像”, on_MouseHandle, (void*)&src);
- waitKey(0);
- return 0;
- }
原始图像:
填充结果:
</div>