zoukankan      html  css  js  c++  java
  • 实现二值图像连通区标记之区域生长法

    连通区标记是最主要的图像处理算法之中的一个。

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

    区域生长法利用区域生长的思想。一次生长过程能够标记一整个连通区,仅仅需对图像进行一次扫描就能标记出全部连通区。

    算法描写叙述例如以下:

    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.


  • 相关阅读:
    sqlhelper使用指南
    大三学长带我学习JAVA。作业1. 第1讲.Java.SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行 大三学长带我学习JAVA。作业1.
    pku1201 Intervals
    hdu 1364 king
    pku 3268 Silver Cow Party
    pku 3169 Layout
    hdu 2680 Choose the best route
    hdu 2983
    pku 1716 Integer Intervals
    pku 2387 Til the Cows Come Home
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6803407.html
Copyright © 2011-2022 走看看