实现二值图像连通区标记之区域生长法

连通区标记是最基本的图像处理算法之一。该算法中,按从左至右、从上至下的顺序,对整幅图像进行扫描,通过比较每个前景像素的邻域进行连通区标记,并创建等效标记列表。最后,合并等效标记列表,并再次扫描图像以更新标记。算法的优点的是通俗易懂,缺点是需要两次扫描图像,效率不高。

区域生长法利用区域生长的思想,一次生长过程可以标记一整个连通区,只需对图像进行一次扫描就能标记出所有连通区。算法描述如下:

  1. 输入待标记图像bitmap,初始化一个与输入图像同样尺寸的标记矩阵labelmap,一个队列queue以及标记计数labelIndex;
  2. 按从左至右、从上至下的顺序扫描bitmap,当扫描到一个未被标记的前景像素p时,labelIndex加1,并在labelmap中标记p(相应点的值赋为labelIndex),同时,扫描p的八邻域点,若存在未被标记的前景像素,则在labelmap中进行标记,并放入queue中,作为区域生长的种子;
  3. 当queue不为空时,从queue中取出一个生长种子点p1,扫描p1的八邻域点,若存在未被标记过的前景像素,则在labelmap中进行标记,并放入queue中;
  4. 重复3直至queue为空,一个连通区标记完成;
  5. 转到2,直至整幅图像被扫描完毕,得到标记矩阵labelmap和连通区的个数labelIndex。

该算法最坏情况下,将对每个像素点都进行一次八邻域搜索,算法复杂度为O(n)。

typedef struct QNode{
	int data;
	struct QNode *next;
}QNode;

typedef struct Queue{
	struct QNode* first;
	struct QNode* last;
}Queue;

void PushQueue(Queue *queue, int data){
	QNode *p = NULL;
	p = (QNode*)malloc(sizeof(QNode));
	p->data = data;
	if(queue->first == NULL){
		queue->first = p;
		queue->last = p;
		p->next = NULL;
	}
	else{
		p->next = NULL;
		queue->last->next = p;
		queue->last = p;
	}
}

int PopQueue(Queue *queue){
	QNode *p = NULL;
	int data;
	if(queue->first == NULL){
		return -1;
	}
	p = queue->first;
	data = p->data;
	if(queue->first->next == NULL){
		queue->first = NULL;
		queue->last = NULL;
	}
	else{
		queue->first = p->next;
	}
	free(p);
	return data;
}

static int NeighborDirection[8][2] = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};

void SearchNeighbor(unsigned char *bitmap, int width, int height, int *labelmap,
                    int labelIndex, int pixelIndex, Queue *queue){
	int searchIndex, i, length;
	labelmap[pixelIndex] = labelIndex;
	length = width * height;
	for(i = 0;i < 8;i++){
		searchIndex = pixelIndex + NeighborDirection[i][0] * width + NeighborDirection[i][1];
		if(searchIndex > 0 && searchIndex < length &&
			bitmap[searchIndex] == 255 && labelmap[searchIndex] == 0){
			labelmap[searchIndex] = labelIndex;
			PushQueue(queue, searchIndex);
		}
	}
}

int ConnectedComponentLabeling(unsigned char *bitmap, int width, int height, int *labelmap){
	int cx, cy, index, popIndex, labelIndex = 0;
	Queue *queue = NULL;
	queue = (Queue*)malloc(sizeof(Queue));
	queue->first = NULL;
    	queue->last = NULL;
	memset(labelmap, 0, width * height);
	for(cy = 1; cy < height - 1; cy++){
		for(cx = 1; cx < width - 1; cx++){
			index = cy * width + cx;
			if(bitmap[index] == 255 && labelmap[index] == 0){
				labelIndex++;
				SearchNeighbor(bitmap, width, height, labelmap, labelIndex, index, queue);

				popIndex = PopQueue(queue);
				while(popIndex > -1){
				SearchNeighbor(bitmap, width, height, labelmap, labelIndex, popIndex, queue);
					popIndex = PopQueue(queue);
				}
			}
		}
	}
	free(queue);
	return labelIndex;
}

关于Image Engineering& Computer Vision更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.

实现二值图像连通区标记之区域生长法

时间: 2024-11-09 02:55:48

实现二值图像连通区标记之区域生长法的相关文章

OpenCV:二值图像连通区域分析与标记算法实现

编译环境: 操作系统:Win8.1  64位 IDE平台:Visual Studio 2013 Ultimate OpenCV:2.4.8 一.连通域 在图像中,最小的单位是像素,每个像素周围有8个邻接像素,常见的邻接关系有2种:4邻接与8邻接.4邻接一共4个点,即上下左右,如下左图所示.8邻接的点一共有8个,包括了对角线位置的点,如下右图所示.         如果像素点A与B邻接,我们称A与B连通,于是我们不加证明的有如下的结论: 如果A与B连通,B与C连通,则A与C连通. 在视觉上看来,彼

使用cvFindContours函数与cvFillPoly填充连通区内部空洞

OpenCV基于图像轮廓填充连通区内部空洞 前言: 最近在做火焰识别项目时使用了一种火焰颜色模型分割疑似火焰区域,由于火焰内部温度高.焰色偏白而被该模型舍弃,造成火焰连通区域内部有空洞,影响进一步的火焰判断.通过查找资料学习,我使用cvFindContours()函数与cvFillPoly()函数填充连通区内部空洞,取得了良好的效果,特写此片博文总结.分享我的经验. 1. 主要函数介绍 1.1 FindContours 在二值图像中寻找轮廓  int cvFindContours( CvArr*

iOS开发学习之MapKit - 获得在MapView(地图)中显示多个标记的区域(MKCoordinateRegion)

-(MKCoordinateRegion)regionForAnnotations:(NSArray *)annotations //可原封不动的复制运用 { MKCoordinateRegion region; if([annotations count] == 0) { region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.coordinate, 1000, 1000); } else if([annota

图像连通域标记算法研究

把之前一篇记录过的日志贴过来 图像连通域标记算法研究 ConnectedComponent Labeling 最近在研究一篇复杂下背景文字检测的论文. “Detecting Text in Natural Scenes with Stroke Width Transform ” CPVR 2010的文章,它主要探讨利用文字内部笔画宽度一致作为主要线索来检测文字的一个新奇的算法,当然,我不是想讨论文字检测,论文算法实施的过程中有一步涉及到图像连通域标记算法,在这里我遇到了一些问题,查阅了一些相关文

ACM-水池数目问题

大家好,这是我的第一篇博文. 最近在做ACM练习,在讨论区发现有很多问题的解法多种多样,故萌生念头将自己已AC题目的解题思路整理发文. 发此博文不为求得最高效的解题代码,旨在分享自己的解题方法,与大家交流学习,共同探讨. 言归正传-----南阳ACM-27题  水池数目 水池数目 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 ***校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图,这个地图上仅标识了此处是否是水池,现在,你的

DSP VLIB实验

声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 引言 在dsp开发中,为了节省开发时间和难度,TI将一些成熟的算法封装为模块,供开发者使用.如果能充分利用这些算法支持库,对于加快dsp开发进程与提高代码质量.稳定性有非常大的帮助.VLIB是一个经过深入优化的计算机视觉算法库,支持C64x和C64x+处理器内核,提供了如下图所示的功能函数接口. 下面是在DSP6455上进行的测试实验总结: Canny 算子 好的 检 测 : 算法能够尽可能多地标识出图像中

区域生长算法(C# 实现)

区域生长算法 2014年9月19日 17:01:44 大道理一摆: (以下说明转载,感觉写的很好) 历史:区域生长是一种古老的图像分割方法,最早的区域生长图像分割方法是由Levine等人提出的.该方法一般有两种方式,一种是先给定图像中要分割的目标物体内的一个小块或者说种子区域(seed point),再在种子区域基础上不断将其周围的像素点以一定的规则加入其中,达到最终将代表该物体的所有像素点结合成一个区域的目的:另一种是先将图像分割成很多的一致性较强,如区域内像素灰度值相同的小区域,再按一定的规

Review of Segmentation for Medical image analysis

成像方法:X射线,CT,MRI,SPECT,PET等 分割的定义: Image segmentation is a procedure for extracting the region of interest (ROI) through an automatic or semi-automatic process[1]. 应用: border detection in angiograms of coronary冠状动脉血管造影, surgical planning, simulation o

【算法随记五】使用FFT变换自动去除图像中严重的网纹。

这个课题在很久以前就已经有所接触,不过一直没有用代码去实现过.最近买了一本<机器视觉算法与应用第二版>书,书中再次提到该方法:使用傅里叶变换进行滤波处理的真正好处是可以通过使用定制的滤波器来消除图像中某些特定频率,例如这些特定频率可能代表着图像中重复出现的纹理. 在网络上很多的PS教程中,也有提到使用FFT来进行去网纹的操作,其中最为广泛的是使用PS小插件FOURIER TRANSFORM,使用过程为:打开图像--进行FFT RGB操作,然后定位到红色通道,选取通道中除了最中心处的之外的白点区