原理:

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. 阿里云的oss使用技巧

    1初始化: 使用阿里云sdk包(php) 方法一:使用composer 加载sdk包 composer require aliyuncs/oss-sdk-php 或 "require&quo ...

  2. Spark源码剖析(八):stage划分原理与源码剖析

    引言 对于Spark开发人员来说,了解stage的划分算法可以让你知道自己编写的spark application被划分为几个job,每个job被划分为几个stage,每个stage包括了你的哪些代码 ...

  3. docker for windows & dotnet core app

    Step 1: 安装docker for windows Step 2: 从github 上 clone 源代码:https://github.com/dotnet/dotnet-docker-sam ...

  4. DBCC page 数据页 堆 底层数据分布大小计算

    1.行的总大小: Row_Size = Fixed_Data_Size + Variable_Data_Size + Null_Bitmap + 4(4是指行标题开销) 开销定义: Fixed_Dat ...

  5. pythonseleniumAPI

    一.浏览器操作 1.浏览器最大化 driver.maximize_window() #将浏览器最大化显示 2.设置浏览器宽.高 driver.set_window_size(480, 800)#设置浏 ...

  6. form注册表单圆角 demo

    form注册表单圆角 <BODY> <div class="form"> <ul class="list"> <li& ...

  7. Mysql使用小tips

    一..常用函数 1.IFNULL(expr1,expr2)          如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2.IFNULL()返回一个数字或字符串值, ...

  8. "软件随想录" 读书笔记

    人员管理: 三种方法: 军事化管理方法, 经济利益驱动法, 认同法. 军事化管理方法不行. 经济利益驱动法也不行. 认同法, 其中一条建议是一起干活的人一起吃饭. 但这种做法比较困难. 设计的作用 寸 ...

  9. python-集合内置函数详解

        集合(S).方法名 等价符号 方法说明 s.issubset(t) s<=t 子集测试(允许不严格意义上的子集):s中所有的元素都是t的成员   s<t 子集测试(严格意义上的子集 ...

  10. K:哈弗曼树

    相关介绍:  树形结构除了应用于查找和排序等操作时能调高效率,它在信息通讯领域也有着广泛的应用.哈弗曼(Huffman)树就是一种在编码技术方面得到广泛应用的二叉树,它同时也是一种最优二叉树. 哈弗曼 ...