关于Two-Pass标记连通域个数
关于Two-Pass标记连通域个数
背景
在完成图像的一系列处理后,得到二值图,一般会统计目标数量,即是获取连通域个数,这里采用TwoPass的方法。
基本思想
在Two-pass连通域标记中,第一次标记(first pass)时从左向右,从上向下扫描,会将各个有效像素置一个label值,判断规则如下(以4邻域为例):
- 当该像素的左邻像素和上邻像素为无效值时,给该像素置一个新的label值,label ++;
- 该像素的左邻像素或者上邻像素有一个为有效值时,将有效值像素的label赋给该像素的label值;
- 当该像素的左邻像素和上邻像素都为有效值时,选取其中较小的label值赋给该像素的label值。
此时,还需维护一个关系表,记录哪些label值属于同一个连通域。这个关系表通常用union-find数据结构来实现。
原文在这
还有个图:

原文说用union-find结构保存连通域,没仔细看,于是自己用了个数组保存,类似于hash...实现起来也并不是很麻烦,大概这样,在开始建立一个map数组固定大小,一般而言应该与用于标记的最大数一致(注意,这里是标记数,是小于连通域数的),这里取uint16最大值,65535,这样也就意味着连通域数不能太大,估计最大能达到万把个吧,因为不同的图标记数和连通域数关系是不一样的。
在FirstPass时,取周围点的标记最小值,map[标记]=min,这样就构成了map数组,然后根据map数据进行第二次标记。
实现
int ImageAlgorithm::TwoPassConnetedDomin(Mat image) {
Mat imageFlag;
imageFlag.create(image.rows, image.cols, CV_16UC1);
for (int k = 0; k < image.rows; ++k) {
for (int i = 0; i < image.cols; ++i) {
imageFlag.at<ushort>(k, i) = UINT16_MAX;
}
}
uint16_t mapp[UINT16_MAX];
memset(mapp, UINT16_MAX, sizeof(uint16_t));
//第一次扫描,完成ImageFlag中的标记
int num = 0;
for (int i = 0; i < image.rows; ++i) {
for (int j = 0; j < image.cols; ++j) {
auto &cu = image.at<Vec3b>(i, j);
if (cu[0] == 255) {
uint16_t pos[4];
auto &up = pos[0];
auto &left = pos[1];
auto &ul = pos[2];
if (i > 0)
up = imageFlag.at<ushort>(i - 1, j);
if (j > 0)
left = imageFlag.at<ushort>(i, j - 1);
if (i > 0 && j > 0)
ul = imageFlag.at<ushort>(i - 1, j - 1);
uint16_t min = pos[0];
for (int m = 1; m < 3; m++)
if (min > pos[m])
min = pos[m];
for (int m = 0; m < 3; m++) {
if (mapp[pos[m]] > min)
mapp[pos[m]] = min;
}
if (min == UINT16_MAX) {
imageFlag.at<ushort>(i, j) = num;
mapp[num] = num;
num++;
if(num>=UINT16_MAX)
return -1;
} else {
imageFlag.at<ushort>(i, j) = min;
}
}
}
}
//第二次扫描,进行标记,以及修改map
map<ushort, uint32_t> colorMap;
int total = 0;
for (int n = 0; n < num; ++n) {
if (mapp[n] == n) {
total++;
uint32_t t = 0;
for (int i = 0; i < 3; ++i) {
t += (uint32_t) (rand() / (RAND_MAX + 0.0) * 255) << (i * 8);
}
colorMap[n] = t;
} else
mapp[n] = mapp[mapp[n]];
}
for (int i = 0; i < imageFlag.rows; ++i) {
for (int j = 0; j < imageFlag.cols; ++j) {
auto t = imageFlag.at<ushort>(i, j);
if (t != UINT16_MAX) {
uint32_t c = colorMap[mapp[t]];
image.at<Vec3b>(i, j)[0] = (uchar) c;
image.at<Vec3b>(i, j)[1] = (uchar) (c >> 8);
image.at<Vec3b>(i, j)[2] = (uchar) (c >> 16);
}
}
}
return total;
}
关于Two-Pass标记连通域个数的更多相关文章
- two Pass方法连通域检测
原理: Two-Pass方法检测连通域的原理可参见这篇博客:http://blog.csdn.net/lichengyu/article/details/13986521. 参考下面动图,一目了然. ...
- [代码片段]YEAH!连通域标记和计数
//标记的连通域存储在buff[]里 //返回值为连通域个数 int LinkBlob(unsigned char **imagedata,unsigned char buff[], int heig ...
- Java 对二值化图片识别连通域
用Java 对 已经 二值化了的图片 标记连通域 每块的连通域都标记不一样的数字 public static void main(String [] args) throws IOException ...
- CDOJ 1965 连通域统计【DFS】
求连通域个数,简单题 #include <bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; typedef l ...
- nyoj 86 --位标记
nyoj 86 --位标记 点击打开题目链接 : 找球号(一) 这道题目很多解法,其他解法请参考 http://www.cnblogs.com/play ...
- 使用OpenCV进行相机标定
1. 使用OpenCV进行标定 相机已经有很长一段历史了.但是,伴随着20世纪后期的廉价针孔照相机的问世,它们已经变成我们日常生活的一种常见的存在.不幸的是,这种廉价是由代价的:显著的变形.幸运的是, ...
- 使用OpenCV进行标定(转载)
转载自牛猫靖 http://www.cnblogs.com/2008nmj/p/6278076.html 使用OpenCV进行相机标定 1. 使用OpenCV进行标定 相机已经有很长一段历史了.但是 ...
- python之路之线程,进程,协程2
一.线程 1.创建线程 2.主线程是否等待子线程 t.setDaemon(Ture/False):默认是false,等待子线程完成,ture,表示不等待子线程结束 3.主线程等待,子线程执行 join ...
- 剖析虚幻渲染体系(12)- 移动端专题Part 1(UE移动端渲染分析)
目录 12.1 本篇概述 12.1.1 移动设备的特点 12.2 UE移动端渲染特性 12.2.1 Feature Level 12.2.2 Deferred Shading 12.2.3 Groun ...
随机推荐
- Random随机数
Random类的常用方法 方法 备注 Int nextInt() 返回一个int类型的随机数 Int nextInt(n) 返回一个0到n之间的数,不包括n Double nextDouble() 返 ...
- 为ASP.NET MVC应用程序读取相关数据
为ASP.NET MVC应用程序读取相关数据 2014-05-08 18:24 by Bce, 299 阅读, 0 评论, 收藏, 编辑 这是微软官方教程Getting Started with En ...
- 领域驱动设计(DDD)的实际应用
领域驱动设计(DDD)的实际应用 笔者先前参与了一个有关汽车信息的网站开发,用于显示不同品牌的汽车的信息,包括车型,发动机型号,车身尺寸和汽车报价等信息.在建模时,我们只需要创建名为Car的实体( ...
- Linq无聊练习系列7----Insert,delete,update,attach操作练习
/*********************Insert,delete,update,attach操作练习**********************************/ ...
- IOS开发小功能2:二维码扫描界面的设计(横线上下移动)
效果图如上,实现的是一个二维码扫描界面. 下面我贴出线条上下移动的代码,至于二维码的代码是用的第三方库. 首先是整体的结构: 注意下面的库文件一个都不能少,否则会报错. TLTiltHighlight ...
- CSS 选择器的学习
从蛋学习 CSS 选择器 + 做一个 Jumony 桌面工具,真费劲,目前Jumony Tool两大问题无法解决,完美的显示 html 文档和根据结果在文档中定位,有点儿跑题了…… 1. 选择“cla ...
- WCF/WPF公司内部订餐程序开发
WCF/WPF公司内部订餐程序开发 (服务端篇) 上班的第一天,群里讨论关于订餐的问题,所以想到了要不要自己开发一个公司内部的订餐系统呢?方便公司内部员工的订餐,有了想法就简单的实践了下 . 实现还是 ...
- 【NET】Winform分页控件初探
public partial class WinFormPager : UserControl { ; /// <summary> /// 当前页 /// </summary> ...
- 利用微信公众平台实现自动回复消息—java版
最近公司需要拿微信公众平台做个东西,所以就开始了最基本学习,网上很多是php版的,对于我这个只会java,不会php的就只能在网上找点只言片语来一点一点学习了.不费话了直接贴图看效果(很简单的). 不 ...
- 利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句
利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 (喷血分享)利用.NET生成数据库表的创建脚本,类似SqlServer编写表的CREATE语句 在我们RDIFram ...