广度优先搜索写的连通区域标记算法

之前发过一篇博文是用python写连通区域标记算法,搜索过程采用的是深度优先搜索,对于一些像素数目较多的目标区域,容易陷入深度递归,造成stack溢出,所以这次用广度优先搜索写了一下,算法中用到了队列数据结构,平台是VS2008+opencv2.3.1,对一副二值图进行连通区域标记。

广度优先搜索的伪代码如下:

广度优先搜索写的连通区域标记算法_第1张图片

连通区域标记的代码如下:

#include "stdafx.h"

#include   
#include "highgui.h"  
#include   
typedef  unsigned long uint32;
typedef  unsigned int  uint16;
typedef  unsigned char uint8;

#define WHITE 1
#define GRAY 2
#define BLACK 3
#define NIL 0
#define INFINITE 255

typedef CvPoint ElemType;  
  
typedef struct Queue  
{  
    ElemType* data;  
    int front;  
    int rear;  
    int Qsize;  
  
}Queue;  
  
//初始化通过参数传进来创建队列的大小  
bool initQueue(Queue* q,int size)  
{  
    q->front = 0;  
    q->rear = 0;  
    q->Qsize = size;  
    q->data = (ElemType*)malloc(q->Qsize*sizeof(ElemType));  
    if( NULL == q->data)  
        return false;  
    return true;  
  
}  
  
//销毁队列,释放内存  
void destroyQueue(Queue* q)  
{  
    q->front = 0;  
    q->rear = 0;  
    q->Qsize = 0 ;  
    free((q->data));  
    q->data = NULL;  
}  
  
//清空队列  
void clearQueue(Queue* q)  
{  
    q->front = 0;  
    q->rear = 0;  
}  
  
//判断队列是否为空  
bool is_empty(Queue *q)  
{  
    if(q->front == q->rear)  
    {  
        printf("the queue is empty! \n");  
        return true;  
    }  
    else  
    {  
        return false;     
    }  
}  
  
//返回队首元素  
bool getHead(Queue *q,ElemType *e)  
{  
    if(is_empty(q))  
    {  
        printf("can not get the head element! \n");  
        return false;  
    }  
    else  
    {  
        *e = q->data[q->front];  
        return true;  
    }  
}  
  
//返回队列长度:在循环队列中  
int Qlength(Queue *q)  
{  
    return (q->rear-q->front+q->Qsize)%q->Qsize;  
}  
  
//入队  
bool enQueue(Queue *q,ElemType e)  
{  
    //如果队列已满,重新分配内存  
    if(q->rear == q->Qsize-1)  
    {  
        q->data = (ElemType*)realloc(q->data,2*q->Qsize*sizeof(ElemType));  
        if(q->data == NULL)  
            return false;  
        else  
            q->Qsize *= 2;  
    }  
    //先赋值,然后队尾循环加1  
    q->data[q->rear] = e;  
    q->rear = (q->rear+1)%q->Qsize;  
    return true;  
  
}  
//出队
bool deQueue(Queue *q,ElemType *e)  
{  
    if(is_empty(q))  
        return false;  
    else  
    {  
        *e = q->data[q->front];  
        //队首标记循环加1  
        q->front = (q->front+1+q->Qsize) % q->Qsize;  
    }  
    return true;  
}
void BFS( IplImage* G, IplImage* Label_Image, int x, int y ,uint8 num)
{
	IplImage* Color_src,*D_src;//白色表示未被搜索过,黑色表示搜索完毕,灰色表示正在搜索
	//Queue *Q;
	CvPoint *u=&cvPoint(0,0);
	int i,j,m,n;
	Queue Q; 
	initQueue(&Q,10);
	
	//return;
	Color_src = cvCreateImage( cvGetSize(G), 8, 1 );
	D_src = cvCreateImage( cvGetSize(G), 8, 1 );
	
	//给所有点标记为白色
	for( j=0; jheight; j++ )
	{
		for( i=0; iwidth; i++ )
		{
			cvSetReal2D(Color_src,j,i,WHITE);
			cvSetReal2D(D_src,j,i,INFINITE);
		}
	}
	cvSetReal2D( Color_src, y, x, GRAY );
	cvSetReal2D( D_src, y, x, 0 );

	enQueue( &Q, cvPoint( x, y ));
	
	while( !is_empty(&Q) )
	{
		if( deQueue( &Q, u ) )
		{
			cvSetReal2D( Label_Image,u->y, u->x, num );
			if( u->x==0|| u->x==G->width||u->y==0|| u->y==G->height )//不处理边界点
				continue;
			else
			{
				for( n=u->y - 1;n<=u->y+1; n++ )//八邻域
				{
					for( m=u->x - 1;m<=u->x+1; m++ )
					{
						if( m==u->x && n==u->y ){}
						else if( cvGetReal2D(G,n,m)==0 ){}
						else
						{
							if(WHITE==cvGetReal2D(Color_src,n,m))
							{
								cvSetReal2D( Label_Image,n, m, num );//标记图像
								cvSetReal2D( Color_src, n, m, GRAY );
								uint8 dis = cvGetReal2D(D_src,u->y, u->x)+1;//该点距离种子点的距离
								if(dis>255) dis=255;
								
								cvSetReal2D(D_src,n,m,dis);
								enQueue( &Q, cvPoint( m, n ));
							}
						}
					}
				}
				cvSetReal2D( Color_src, u->y, u->x, BLACK);
			}
		}
		else break;
	}

	
	clearQueue(&Q);
	cvReleaseImage(&Color_src);
	cvReleaseImage(&D_src);

}
void bwLabel(IplImage* img, IplImage* L_src ,IplImage* dst)
{
	int i,j;
	char s[5];
	uint8 Label_value=0;
	CvFont font;
	cvInitFont( &font,CV_FONT_HERSHEY_SIMPLEX,1,0.5);
	for( j=0; jheight; j++ )
	{
		for( i=0; iwidth; i++ )
		{
			uint8 Label=cvGetReal2D(L_src,j,i);
			uint8 value=cvGetReal2D(img,j,i);
			
			if(Label==0&&value!=0)
			{
				Label_value++;
				
				itoa( Label_value,s,10);
				cvPutText(dst, s, cvPoint(i,j),&font,cvScalar(255,255,255));
				
			    BFS(img, L_src, i,j,Label_value);//以i,j为种子点标记同一目标
			}
		}
	}
}
int _tmain(int argc, _TCHAR* argv[])
{
	IplImage* src,*src_gray,*L_src;
	
	int i,j,w,h;
	
	src = cvLoadImage( "bwlabel.bmp" );//读取原图
	src_gray = cvCreateImage( cvGetSize(src), 8, 1 );
	L_src = cvCreateImage( cvGetSize(src), 8, 1 );
	cvSetZero(L_src);//对标记图像清零
	
	w = cvGetSize(src).width;
	h = cvGetSize(src).height;
	cvCvtColor( src, src_gray, CV_BGR2GRAY );

	
	bwLabel(src_gray,L_src,src);//对图像进行标记
	
	cvNamedWindow("1",CV_WINDOW_AUTOSIZE);
	cvShowImage("1",src);//标记后的图像

	cvNamedWindow("2",CV_WINDOW_AUTOSIZE);
	cvShowImage("2",src_gray);//原图

	cvWaitKey(0); 
	cvReleaseImage(&src); 
	cvReleaseImage(&src_gray);
	cvDestroyWindow("1"); 
	return 0;
}

标记结果和原图:


你可能感兴趣的:(图像处理)