原理:

Two-Pass方法检测连通域的原理可参见这篇博客:http://blog.csdn.net/lichengyu/article/details/13986521

参考下面动图,一目了然。

代码:

代码中标记图的数据类型要注意,如果first pass中标记数多于255,就不要用uchar类型,我直接设置为int类型。

 #include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <map>
#include <cassert>
#include <iostream> using namespace std; const int max_size = ;
int parent[max_size] = { }; // 找到label x的根节点
int Find(int x, int parent[])
{
assert(x < max_size);
int i = x;
while ( != parent[i])
i = parent[i];
return i;
} // 将label x 和 label y合并到同一个连通域
void Union(int x, int y, int parent[])
{
assert(x < max_size && y < max_size);
int i = x;
int j = y;
while ( != parent[i])
i = parent[i];
while ( != parent[j])
j = parent[j];
if (i != j)
parent[i] = j;
} cv::Mat twoPassConnectComponent(cv::Mat &binaryImg)
{
int imgW = binaryImg.cols;
int imgH = binaryImg.rows;
int channel = binaryImg.channels();
int type = binaryImg.type();
// first pass
int label = ; cv::Mat dst = cv::Mat::zeros(cv::Size(imgW, imgH), CV_32SC1);
for (int y = ; y < imgH; y++)
{
for (int x = ; x < imgW; x++)
{
if (binaryImg.at<uchar>(y, x) != )
{
int left = (x - < ) ? : dst.at<int>(y, x - );
int up = (y - < ) ? : dst.at<int>(y - , x); if (left != || up != )
{
if (left != && up != )
{
dst.at<int>(y, x) = min(left, up);
if (left <= up)
Union(up, left, parent);
else if (up<left)
Union(left, up, parent);
}
else
dst.at<int>(y, x) = max(left, up);
}
else
{
dst.at<int>(y, x) = ++label;
}
}
}
} //second pass
for (int y = ; y < imgH; y++)
{
for (int x = ; x < imgW; x++)
{
if (binaryImg.at<uchar>(y, x) != )
dst.at<int>(y, x) = Find(dst.at<int>(y, x), parent);
}
} return dst;
} cv::Scalar getRandomColor()
{
uchar r = * (rand() / (1.0 + RAND_MAX));
uchar g = * (rand() / (1.0 + RAND_MAX));
uchar b = * (rand() / (1.0 + RAND_MAX));
return cv::Scalar(b, g, r);
} cv::Mat showColorLabel(cv::Mat label)
{
int imgW = label.cols;
int imgH = label.rows;
std::map<int, cv::Scalar> colors; cv::Mat colorLabel = cv::Mat::zeros(imgH, imgW, CV_8UC3);
int *pLabel = (int*)label.data;
uchar *pColorLabel = colorLabel.data;
for (int i = ; i < imgH; i++)
{
for (int j = ; j < imgW; j++)
{
int idx = (i*imgW + j) * ;
int pixelValue = pLabel[i*imgW + j];
if (pixelValue > )
{
if (colors.count(pixelValue) <= )
{
colors[pixelValue] = getRandomColor();
}
cv::Scalar color = colors[pixelValue];
pColorLabel[idx + ] = color[];
pColorLabel[idx + ] = color[];
pColorLabel[idx + ] = color[];
}
}
} return colorLabel;
} int main()
{
// 加载图像
string imageName = "data/source_images/logo.png";
cv::Mat image = cv::imread(imageName, );
if (!image.data)
{
cout << "No image data" << endl;
getchar();
return -;
}
//转为灰度图
cv::cvtColor(image, image, CV_RGB2GRAY);
//阈值化,情景为255,背景为0
cv::Mat threshImg;
cv::threshold(image, threshImg, , , cv::THRESH_BINARY);
cv::bitwise_not(threshImg, threshImg); //连通域检测 two Pass方法标记图像
cv::Mat labelImg = twoPassConnectComponent(threshImg); //不同连通区域用不同颜色表示
cv::Mat colorLabelImg=showColorLabel(labelImg); //显示
cv::imshow("thresh", threshImg);
cv::imshow("label", labelImg*);
cv::imshow("colorLabel", colorLabelImg);
cv::waitKey();
}

结果:

使用OpenCV的logo为素材图,如下:

(1)转为灰度图然后阈值化

(2)寻找连通域

(3)不同连通区域不同颜色显示

   

   

封装后的代码见我的码云code:https://gitee.com/rxdj/twoPassMethod.git

two Pass方法连通域检测的更多相关文章

  1. OpenCV: 图像连通域检测的递归算法

    序言:清除链接边缘,可以使用数组进行递归运算; 连通域检测的递归算法是定义级别的检测算法,且是无优化和无语义失误的. 同样可用于寻找连通域 void ClearEdge(CvMat* MM,CvPoi ...

  2. 图像连通域检测的2路算法Code

    本文算法描述参考链接:http://blog.csdn.net/icvpr/article/details/10259577 两遍扫描法: (1)第一次扫描: 访问当前像素B(x,y),如果B(x,y ...

  3. 使用dlib自带的面向梯度直方图(HOG)和线性分类器方法来检测人脸

    之前使用opencv里面CascadeClassifier(级联分类器)来识别人脸, 下面使用dlib库来实现人脸识别. dlib是一个开源的库,它包含了很多内容有机器学习,图像处理,数值算法等等. ...

  4. 一种用单片机AD采样方式来检测交流市电电压的方法

    下面介绍一种用单片机AD采样的方式检测市电电压的方法  要检测交流市电的电压,通常有两种方法 一.通过频繁的采样后再求平均值来获得实际电压值 二.通过采样交流市电的峰值,再通过算法得出实际电压值 这里 ...

  5. Android手机安全软件的恶意程序检测靠谱吗--LBE安全大师、腾讯手机管家、360手机卫士恶意软件检测方法研究

    转载请注明出处,谢谢. Android系统开放,各大论坛活跃,应用程序分发渠道广泛,这也就为恶意软件的传播提供了良好的环境.好在手机上安装了安全软件,是否能有效的检测出恶意软件呢?下边针对LBE安全大 ...

  6. Spring Assert主张 (参议院检测工具的方法-主张)

    Web 收到申请表格提交的数据后都需要对其进行合法性检查,假设表单数据是不合法的,该请求将被拒绝.分类似的,当我们写的类方法,该方法还经常需要组合成参 法国检查.假设参议院不符合要求,方法通过抛出异常 ...

  7. android 检测是否插入U盘方法之一

    本方法是检测文件/proc/partitions. import java.io.*; File Usbfile = new File("/proc/partitions");if ...

  8. Android root检测方法小结

    转载目的,之前主要应用这里的原理解决了,手机被某个APP检测为root过的手机的问题,记录后续可能参考. 出于安全原因,我们的应用程序不建议在已经root的设备上运行,所以需要检测是否设备已经root ...

  9. VC++ 内存泄露与检测的一种方法

        本文介绍,当VC++或者MFC程序,出现内存泄露时,如何快速定位的方法,这种方法有一定的局限性,在注意事项中会给出的. MFC程序     当MFC程序出现内存泄露时,退出程序时的VS调试输出 ...

随机推荐

  1. Django学习日记01_环境搭建

    1. 使用Vagrant 创建ubuntu虚拟机: 首先安装vagrant,网上有比较多的方法,如:http://www.th7.cn/system/mac/201405/55421.shtml 我使 ...

  2. XCopy命令实现增量备份

    xcopy XCOPY是COPY的扩展,可以把指定的目录连文件和目录结构一并拷贝,但不能拷贝系统文件:使用时源盘符.源目标路径名.源文件名至少指定一个:选用/S时对源目录下及其子目录下的所有文件进行C ...

  3. 使用alembic进行数据库版本管理

    前言 随着项目业务需求的不断变更,数据库的表结构修改难以避免,此时就需要对数据库的修改加以记录和控制,便于项目的版本管理和随意的升级和降级. Alembic就可以很好的解决这个问题.Alembic是S ...

  4. 【HTML初识】

    一.BS模式 BS(Browser-Server)模式:顾名思义为浏览器-服务器的意思,对比的话类似我们PC上面浏览器使用的产品即为BS模式产品,例如google doc.各类网站等. 服务端开启一个 ...

  5. Python正则表达式返回首次匹配到的字符及查询的健壮性

    re.findall(pattern,string)会搜索所有匹配的字符,返回的是一个列表,获取首个匹配需要re.findall(pattern,string)[0]访问, 但是如果findall没匹 ...

  6. mysql分组查询前n条数据

    建表: CREATE TABLE hard(id INT,aa varchar(50) ,bb INT,PRIMARY key(id))insert into hard values(1,'a',9) ...

  7. [python]使用xlrd对Excel表格进行读写操作

    2.1 导入模块 import xlrd 2.2 打开Excel文件读取数据 data = xlrd.open_workbook("excelFile.xls") 2.3 使用技巧 ...

  8. IntelliJ IDEA运行项目成功后,无法访问Tomcat主页

    问题 初次使用IntelliJ IDEA,但今天在运行项目启动Tomcat后,发现无法访问Tomcat首页,出现404错误:输入http://localhost:8080时无法访问Tomcat首页,但 ...

  9. ajax struts2 数据的返回形式

    这篇随笔算是接上篇的数据请求返回,上一篇关于分页用的返回的数据形式是json,http://www.cnblogs.com/tele-share/p/7192206.html这次主要探讨ajax从st ...

  10. windows第七层负载均衡--基于IIS的ARR负载均衡

    载均衡有很多种方法,有硬件负载均衡,软件负载均衡,还可以从域名解析下手. 不过,今天只讲软件负载均衡 软件负载均衡一般分两种,从网络协议来讲(tcp/ip),主要集中在第四层和第七层进行负载均衡. 第 ...