基于行程标记的快速连通域提取实现

一直在使用halcon进行图像处理,但本人更倾向于自己写算法,所以也一直在使用Opencv。对于halcon,其连通域的处理相当方便,所以一直想用Opencv来实现这样的功能。由于最近项目以及对后续转用Opencv的想法,利用工作之余的时间查了些资料,再结合自己的一些想法,用Opencv实现了这项功能。

最开始在网上找了些方法,例如1)Two-Pass法;2)Seed-Filling种子填充法[1] ,这两种方法容易理解,都是基于8连通或者4连通的基础,但效率相当低。后来找了几篇论文,提到了基于行程的提取方式,只需要对图像进行单次扫描就可以实现连通域的提取。所谓基于行程,其实就是在每一行中,一个连续的区域,其起始到结束,相对于图像最左侧起始端的距离。具体理解可以看参考论文[2][3][4]。但实现方式多样,有的基于二叉树数据结构来构建连通域,有的基于多叉树。本篇博文,主要是基于双向列表。下面介绍连通域结构的定义,最后贴上伪码。

一、数据结构:

//连通域结构定义,此结构对应于每一行中连通的区域
typedef struct stRegion
{
	int row;    //行号
	int begin;    //区域在行中的起始列
	int end;    //区域在行中的结束列
	int prevNum;    
	int nextNum;
	stRegion* prev;
	stRegion* next;
	stRegion* header;
	stRegion* tail;
	int label;//仅供表头使用
	bool ispaint;
	
}Region;
//连通域集合
typedef struct stRegions
{
private:
	vector<OCVRegion*> arr;
}Regions;

二、算法原理:

扫描每一行,对每行中的连通域进行标记,每一行的每一个连通域对应于一个Region结构。然后,对前一行与当前行的连通域进行比较,如果两个连通域的行程,也即它们的起始和终止点之间的区域有重合的情况,如下图所示,1和2,5和6之间就是重合的关系。如果当前Region与上一行Region有重合,如果是第一次,则创建一个空的Region结构,将上一行Region的next指向当前行Region,将当前行Region的prev指向上一行Region,然后将空的Region的next指向当前行Region,作为表头,同时给空的Region的label赋上当前行号。再创建一个空的Region,其next指向上一行Region,作为表底。然后将表头压入Regions中

如果不是第一次,则有新的Region,则插入表中,然后更新表头的指向,直至扫描结束。最终Regions中压入的表头,就是一个连通区域,通过表头可以遍历整个区域在图像中的每一行,进而进行其他的运算。

三、伪码


Require lastRow:Region指针数组,用于存放上一行连通区域结构

Require label:连通标记号

Require currentRow:Region指针数组,用于存放当前行连通区域结构

def Connection(image):

normalize(image) 

for y in image's rows   do

    for x in image's cols   do
        if pixel value equal to 1 
            创建新 region 同时设置 reigon.begin as x
            继续扫描直到像素等于 0 同时设置 region.end as x-1 
        endif
        for n in lastRow  do
            if lastRow 与 region重合
                if lastRow.header == region.header==null
                    创建列表,及表头,将表头压入Regions中
                else if lastRow.header!=null && region.header==null
                    将region加入列表的前头,并将列表header指向它
                else if lastRow.header==null && region.header!=null
                    将lastRow加入region当前列表头,并将列表header指向它
                else if lastRow.header!=null && region.header!=null
                    若是两个表,则合并
                endif
            endif
        endfor
    endfor
    将当前行的所有Region都赋给LastRow
endfor

输出Regions

 


四、效率

这里不做严谨的实验,只说说大概的效率,对于如下图像(500万原生图像)

 

处理效果:

时间在300ms左右。效率还可以提高,期待下篇博文。

参考:

[1].https://blog.csdn.net/icvpr/article/details/10259577 OpenCV_连通区域分析(Connected Component Analysis-Labeling)

[2].快速连通域分析算法及其实现. 著; 孙斌 ,模式识别与人工智能

[3].基于快速连通域分析的目标特征提取算法. 著;张恒,胡文龙,丁赤飙

[4].A run-based two-scan labeling algorithm[J].JEEE Transaction on Image Processing, 2008,17(5) 

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值