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

一直在使用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) 

根据引用\[1\]和引用\[2\]的内容,连通域分析是指将图像中具有相同像素值且位置相邻的像素点组成的连通区域找出并标记的过程。在连通域分析中,可以使用两遍扫描法来实现。第一遍扫描时,给每个像素位置赋予一个label,并记录同一个连通区域内的像素集合中可能被赋予不同label的情况。第二遍扫描时,将具有连通关系的标记的像素归为一个连通区域,并赋予相同的label。 至于如何在Halcon中合并连通域,我无法提供具体的方法,因为我没有引用到相关的资料。但是你可以参考引用\[3\]中提供的链接,该链接提供了关于OpenCV中连通区域分析的内容,可能对你有所帮助。 #### 引用[.reference_title] - *1* *2* [图像连通域分析及相关算法研究——很详细的原理以及简单的代码](https://blog.csdn.net/weixin_43373833/article/details/103192617)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [基于行程标记快速连通域提取实现](https://blog.csdn.net/u010050735/article/details/107348151)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值