一、连通域

需要了解连通域和两遍扫描法的可以看连通域分析之两遍扫描法(Two-Pass)这篇博文。我在里面已经介绍过了连通域的两种定义,这里就不再介绍。在此文中仍以4-邻域为例。

二、种子填充(区域填充)

1、遍历二值化后待测连通域的图像,当当前访问的像素不为零,将该像素入栈(栈中保存像素点的坐标);
2、访问栈顶元素对应的像素,退栈;
3、访问2中得到的栈顶像素的四个邻域像素点,若像素值不为零,则将对应像素入栈;
4、继续访问栈顶元素,直至栈为空;
5、继续遍历图像,直至完成遍历。
以上就是种子填充法的一个基本步骤,在访问像素的同时,我们可以根据需求做出操作。

三、算法代码

int myBoundaryFill(Mat &src, Mat &dst)
{if (src.empty() || src.type() != CV_8UC1)return 0;stack<Point2i> pts;int label = 1;//标注初始为1int row = src.rows;int col = src.cols;dst.release();dst = cv::Mat::zeros(row, col, CV_32S);for (int i = 0;i < row ;i++){for (int j = 0;j < col ;j++){int curPixel = (int)src.at<uchar>(i,j);int curLabel = (int)dst.at<int>(i, j);if (curPixel != 0 && curLabel == 0){dst.at<int>(i,j)= label;   pts.push(Point2i(j, i));while (!pts.empty()){Point2i curPt = pts.top();int x = curPt.x;int y = curPt.y;pts.pop();if (y > 0){//upPixelif (src.at<uchar>(y-1, x) != 0 && dst.at<int>(y-1, x) == 0){dst.at<int>(y - 1, x) = label;pts.push(Point2i(x, y-1));}}if (y < row - 1){//downPixelif ((int)src.at<uchar>(y + 1, x) != 0 && dst.at<int>(y + 1, x) == 0){dst.at<int>(y + 1, x) = label;pts.push(Point2i(x, y+1));}}if (x > 0){//leftPixelif ((int)src.at<uchar>(y, x-1) != 0 && dst.at<int>(y, x-1) == 0){dst.at<int>(y, x-1) = label;pts.push(Point2i(x-1, y));}}if (x < col - 1){//rightPixelif (src.at<uchar>(y, x + 1) != 0 && dst.at<int>(y, x + 1) == 0){dst.at<int>(y, x + 1) = label;pts.push(Point2i(x+1, y));}}}label++;//自增              }}}return label-1;//最后得到的连通域数量
}

四、算法解析

1、不遗漏像素点的访问

for (int i = 0;i < row ;i++)
{for (int j = 0;j < col ;j++){.....}
}

遍历图像行和宽都从0开始,可以确保每个像素点都被访问;
2、避免入过栈的像素再次入栈

int curPixel = (int)src.at<uchar>(i,j);
int curLabel = (int)dst.at<int>(i, j);
if (curPixel != 0 && curLabel == 0)

curPixel表示当前访问的像素点,curLabel表示该像素点在输出图像dst中对应的标注。输出图像dst是一个像素初始值全为零的图像。当输出图像dst中的某个像素值不为0,说明已经访问过其对应于输入图像中的像素点,即该像素点已经被标注了,无需再次标注。
3、越界访问控制
由于是从(0,0)开始访问的,包含了边界的像素点,但边界像素点并不是四个邻域像素都存在。所以在访问栈顶像素四个邻域像素之前在相应的边界进行一次边界判定,使用if (y > 0)、if (y < row - 1)、if (x > 0)和if (x < col - 1)防止相应边界的越界访问。

算法比较简单,就是一个DFS的算法,只需要在访问元素的过程中注意越界和遗漏边界像素的问题即可。

五、测试效果
测试代码

int main()
{   Mat test = (cv::Mat_<uchar>(8, 8) <<0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0);Mat testResult;//Mat preConnect;//cout<<"连通域个数为:"<<myTwoPass(test, testResult, preConnect);cout << "testResult连通域个数为:" << myBoundaryFill(test, testResult);cout << endl;//Mat img = imread("../coins.png");//原图Mat img = imread("../rice.png");if (img.empty()){cout << "请确认图像文件名称是否正确" << endl;return -1;}Mat rice, riceBW;//将图像转换成二值图像,用于统计连通域cvtColor(img, rice, COLOR_BGR2GRAY);threshold(rice, riceBW, 50, 255, THRESH_BINARY);//用于生成随机颜色,用于区分不同的连通域RNG rang(10086);int w = img.cols;int h = img.rows;Mat myout,preConnect;//int mynumber = myTwoPass(riceBW, myout, preConnect);//自定义函数// mynumber = myTwoPass(riceBW, myout);//自定义函数int mynumber = myBoundaryFill(riceBW, myout);//自定义函数vector<Vec3b> mycolors;for (int i = 0;i < mynumber;i++){//使用均匀分布的随机数确定颜色Vec3b myvec3 = Vec3b(rang.uniform(0, 256), rang.uniform(0, 256), rang.uniform(0, 256));mycolors.push_back(myvec3);}//以不同的颜色标记不同的连通域Mat myresult = Mat::zeros(rice.size(), img.type());//自定义输出图像//cout << "mycolors number= " << mycolors.size();for (int i = 0;i < h;i++){for (int j = 0;j < w;j++){int label = myout.at<int>(i, j);if (label == 0){//背景颜色不改变continue;}myresult.at<Vec3b>(i, j) = mycolors[label-1];}}Mat out;int number = connectedComponents(riceBW, out, 4, CV_16U);//库函数vector<Vec3b> colors;for (int i = 0;i < number;i++){//使用均匀分布的随机数确定颜色Vec3b vec3 = Vec3b(rang.uniform(0, 256), rang.uniform(0, 256), rang.uniform(0, 256));colors.push_back(vec3);}Mat result = Mat::zeros(rice.size(), img.type());//库函数输出图像for (int i = 0;i < h;i++){for (int j = 0;j < w;j++){int label = out.at<uint16_t>(i, j);if (label == 0){//背景颜色不改变continue;}result.at<Vec3b>(i, j) = colors[label-1];}}cout << "库函数得到的连通域数:" << number << endl;cout << "自定义函数得到的连通域数:" << mynumber << endl;//显示结果imshow("原图", img);imshow("库函数输出图像", result);imshow("自定义函数输出图像", myresult);waitKey(0);return 0;
}

自定义Mat变量的测试结果,图像被分为1,2,3,4一共4个连通域

图片的测试
原图

测试结果对比

计算出的连通域数量对比,库函数计算了背景所以多1。

连通域分析之种子填充法相关推荐

  1. 【OpenGL C++】画一个空心汉字和一个圆,并填充汉字(中点画线法,中点画圆法,种子填充法)

    内容:画一个空心汉字和一个圆 设计一个画任意直线和圆的算法,可选所学的任一图形扫描转换算法(中点或bresenham算法),不能使用任何画线/画圆的API: 使用画线算法实现空心汉字的绘制,汉字必须为 ...

  2. 【OpenCV】8邻域种子填充法剔除短连通域的高效算法

    //本文档参考种子填充算法描述及C++代码实现(https://www.bbsmax.com/A/amd0AVWzge/)讲解的原理,实现快速种子填充算法,运行效果高. //具体功能如下:依次扫描每个 ...

  3. 【OpenCV 4开发详解】图像连通域分析

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  4. cv2.error: opencv(4.4.0)_【OpenCV 4开发详解】图像连通域分析

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  5. OpenCV二值图像连通域分析

    版权声明:本文为博主原创文章,可以随意共享转载,注明来源即可 https://blog.csdn.net/qq_37059483/article/details/78018539 通域分析对于图像处理 ...

  6. OpenCV——二值图像连通域分析

    通域分析对于图像处理后面涉及到模式识别的内容来说是基础 连通区域(Connected Component)一般是指图像中具有相同像素值且位置相邻的前景像素点组成的图像区域(Region,Blob).连 ...

  7. Two-Pass算法——图像连通域分析

    在处理二值图像,提取感兴趣目标时经常需要通过连通域的大小对候选目标进行初步筛选.OpenCV中findContour 方法可以返回轮廓并能够计算轮廓面积.可其局限性在对于非凸多边形的面积计算是不准确的 ...

  8. OpenCV-二值图像连通域分析

    原文地址:https://blog.csdn.net/qq_37059483/article/details/78018539 通域分析对于图像处理后面涉及到模式识别的内容来说是基础 连通区域(Con ...

  9. c语言 连通域算法 递归,VC++ 6.0编写计算机图形学中的种子填充算法,想用递归的八向连通域,求助!...

    VC++ 6.0编写计算机图形学中的种子填充算法,想用递归的八向连通域,求助!0 填充函数代码如下: void CComputerGraphicsView::PolygonFill2()//区域填充函 ...

最新文章

  1. R语言可视化R原生plot函数与ggplot可视化结果组合、整合输出实战:原生R绘图plot函数可视化、ggplot2包可视化、R原生plot函数与ggplot可视化结果组合
  2. 虚拟机非法关机不能重启了
  3. fastbin attack攻击中关于 malloc__hook
  4. brand.php dnfire.cn_能美火灾报警_能美西科姆消防报警主机如何屏蔽故障点_滁州气象...
  5. C++读取配置文件的写法
  6. Maven 使用bat批量清除本地仓库的lastUpdated文件
  7. getconf 取系统配制 --CPU
  8. Spark集群新增节点方法
  9. java switch的应用
  10. function传值传字符串,然后Ajax url传值的时候传这个装字符串的变量
  11. 下载!《Linux 命令行大全》pdf
  12. 工程、通信中的3dB带宽含义
  13. c语言中char的赋值
  14. C#彩色艺术化二维码样式设计(仅说思路)
  15. 全国计算机大赛获奖奖品,国内含金量高的竞赛证书全汇总
  16. 行人重识别的挑战 与 最新进展 (35页PPT整理)
  17. linux强制网卡linkup,使用ip link set eth0 up 命令启用网卡后,网络不通的问题的解决...
  18. 【PyTorch】50行代码实现GAN——PyTorch
  19. 使用反射+注解封装一个基于Sqlite极简的android数据库框架
  20. 老牌ERP厂商集体沉沦之谜(转)

热门文章

  1. 规划、建筑、景观设计VR交互式展示
  2. 诊断仪在线$3E服务
  3. 【机器学习】音乐表示Music Representation
  4. Neuron:背侧流中θ振荡的选择性夹带可提高听觉工作记忆表现
  5. 购物车(Shopping cart) —— B2C网站核心产品设计 (二)
  6. 树莓派 —— USB 摄像头简单测试 (拍照 录像)
  7. 静态内部类的单例模式如何保证线程安全
  8. [日推荐]『台湾景点大全』小编带你游台湾!
  9. 李飞飞计算机视觉笔记(2)--线性分类器损失函数与最优化
  10. c语言dword转float,vc中float与DWORD的互想转换实现代码