区域生长法的编程实现——程序员数字图像处理第一步

数字图像处理的书数不胜数。相关的方法,从直方图、卷积到小波、机器学习方面的方法也举不胜举。


OpenCV库给我们提供了一整套图像存储、显示方法外,也集成了很多很多的图像、视频处理算法以及机器学习算法,以函数的形式提供给我们使用。

然而在初学阶段,我们往往过分依赖于OpenCV中的那些库函数。

虽说OpenCV集成了很多高效算法,然而,毕竟不是无所不包。

OpenCV中基础的算法有时会缺失,有时用起来不是很得心应手。


区域生长算法就是一例(OpenCV的FloodFill用起来非常不顺手)。


区域生长法,思路很简单:将一个图像中的一点作为种子,此种子会沿8邻域/4邻域进行扩展,扩展具有一定限制(即差值不能过大,当然你可以引入梯度这个概念,甚至二维偏导数……),求出种子生长的最终结果。

把示例程序的几张结果发过来,何谓区域生长法,大家一看便知。


区域生长法对于较为均衡的背景中提取目标物而言,效果较为理想。与阈值法、边缘检测法孰优孰劣,俺笔力及精力有限,不进行比较了。单从工程角度,区域生长法是统计闭合图形个数的基础。


这里自己写了一下这个程序的演示代码,只负责将背景同生长不上去的区域分开:

#define INIT 0  
#define SEED -1  
#define CONT -2  
#define INVAL -3  

int color_templ[5*6*3]
= {
	0,0,0,		40,40,40,	80,80,80,	120,120,120,160,160,160,	200,200,200,
	76,0,13,	113,52,0,	127,91,0,	188,114,0,	203,140,68,		236,211,190,
	0,0,121,	93,0,158,	91,20,237,	255,61,255,	170,110,240,	200,161,245,
	38,88,0,	77,118,46,	66,130,98,	112,182,46,	118,197,124,	174,221,178,
	19,57,96,	10,98,163,	0,160,171,	0,242,255,	59,245,255,		139,247,255
};

class g_point  
{  
public:  
	g_point();  
	g_point(int x_i, int y_i);  
	g_point(int x_i, int y_i, int lbl_i);  
public:  
	int x;  
	int y;  
	int lbl;      //标签  
};  

g_point::g_point(int x_i, int y_i)  
{  
	x = x_i;  
	y = y_i;  
	lbl = SEED;  
}  

g_point::g_point()  
{  
	x = 0;  
	y = 0;  
	lbl = INIT;  
}  

g_point::g_point(int x_i, int y_i, int lbl_i)  
{  
	x = x_i;  
	y = y_i;  
	lbl = lbl_i;  
}  

void regionGrowth(IplImage* img, int* p_mat, int x_g, int y_g, int threshold_g)  
{  
	//常用变量:  
	int x;  
	int y;  
	int gradient = 0;  


	//设置前次边缘点  
	std::list<class g_point> cont_pts_pre;  
	std::list<class g_point> * pcont_pts_pre = &cont_pts_pre;


	//设置边缘点  
	std::list<class g_point> cont_pts;  
	std::list<class g_point> * pcont_pts = &cont_pts;


	//种子点+边缘点 = 下次的种子点  
	//上次的边缘点 = 前次边缘点(用于下次减少点数)   
	cont_pts_pre.push_back(class g_point(x_g, y_g, CONT));  
	p_mat[y_g * img->width + x_g] = SEED;  

	std::list<class g_point>::iterator iter_cont;  
	std::list<class g_point>::iterator iter_prt;  
	std::list<class g_point>::iterator iter_swap;  




	while( !cont_pts_pre.empty() )  
	{  



		//一轮生长  
		iter_cont = cont_pts_pre.begin();  
		while(iter_cont != cont_pts_pre.end())  
		{  
			x = (*iter_cont).x;  
			y = (*iter_cont).y;  
			//         if( !(x-1<0 || y-1<0) )                       //#1  
			//         {     
			//             if(p_mat[(y-1)*img->width + (x-1)] == INIT)  
			//             {  
			//                 gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
			//                     ((char*)(img->imageData + (y-1)*img->widthStep))[x-1];  
			//                 if(abs(gradient) < threshold_g)      //满足阈值要求  
			//                 {  
			//                     cont_pts.push_back(class g_point(x-1, y-1, CONT));  
			//                     p_mat[(y-1)*img->width + (x-1)] = SEED;  
			//                 }  
			//                 else                                //不满足阈值要求  
			//                 {  
			//                     p_mat[(y-1)*img->width + (x-1)] = INVAL;  
			//                 }  
			//             }  
			//         }  
			if( !(x-1<0) )                                   //#2  
			{  
				if(p_mat[(y)*img->width + (x-1)] == INIT)  
				{  
					gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
						((char*)(img->imageData + (y)*img->widthStep))[x-1];  
					if(abs(gradient) < threshold_g)      //满足阈值要求  
					{  
						cont_pts.push_back(class g_point(x-1, y, CONT));  
						p_mat[(y)*img->width + (x-1)] = SEED;  
					}  
					else                                //不满足阈值要求  
					{  
						p_mat[(y)*img->width + (x-1)] = INVAL;  
					}         

				}  
			}  
			//         if( !(x-1<0 || y+1 >= img->height) )           //#3  
			//         {  
			//             if(p_mat[(y+1)*img->width + (x-1)] == INIT)  
			//             {  
			//                 gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
			//                     ((char*)(img->imageData + (y+1)*img->widthStep))[x-1];  
			//                 if(abs(gradient) < threshold_g)      //满足阈值要求  
			//                 {  
			//                     cont_pts.push_back(class g_point(x-1, y+1, CONT));  
			//                     p_mat[(y+1)*img->width + (x-1)] = SEED;  
			//                 }  
			//                 else                                //不满足阈值要求  
			//                 {  
			//                     p_mat[(y+1)*img->width + (x-1)] = INVAL;  
			//                 }  
			//                   
			//             }  
			//         }  
			if( !(y+1 >= img->height) )                       //#4  
			{  
				if(p_mat[(y+1)*img->width + (x)] == INIT)  
				{  
					gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
						((char*)(img->imageData + (y+1)*img->widthStep))[x];  
					if(abs(gradient) < threshold_g)      //满足阈值要求  
					{  
						cont_pts.push_back(class g_point(x, y+1, CONT));  
						p_mat[(y+1)*img->width + (x)] = SEED;  
					}  
					else                                //不满足阈值要求  
					{  
						p_mat[(y+1)*img->width + (x)] = INVAL;  
					}  
				}  
			}  
			//         if( !(x+1>=img->width || y+1>=img->height) )    //#5  
			//         {  
			//             if(p_mat[(y+1)*img->width + (x+1)] == INIT)  
			//             {  
			//                 gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
			//                     ((char*)(img->imageData + (y+1)*img->widthStep))[x+1];  
			//                 if(abs(gradient) < threshold_g)      //满足阈值要求  
			//                 {  
			//                     cont_pts.push_back(class g_point(x+1, y+1, CONT));  
			//                     p_mat[(y+1)*img->width + (x+1)] = SEED;  
			//                 }  
			//                 else                                //不满足阈值要求  
			//                 {  
			//                     p_mat[(y+1)*img->width + (x+1)] = INVAL;  
			//                 }  
			//                   
			//             }  
			//         }  
			if( !(x+1>=img->width) )                      //#6  
			{  
				if(p_mat[(y)*img->width + (x+1)] == INIT)  
				{  
					gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
						((char*)(img->imageData + (y)*img->widthStep))[x+1];  
					if(abs(gradient) < threshold_g)      //满足阈值要求  
					{  
						cont_pts.push_back(class g_point(x+1, y, CONT));  
						p_mat[(y)*img->width + (x+1)] = SEED;  
					}  
					else                                //不满足阈值要求  
					{  
						p_mat[(y)*img->width + (x+1)] = INVAL;  
					}  

				}  
			}  
			//         if( !(x+1>=img->width || y-1<0) )              //#7  
			//         {  
			//             if(p_mat[(y-1)*img->width + (x+1)] == INIT)  
			//             {  
			//                 gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
			//                     ((char*)(img->imageData + (y-1)*img->widthStep))[x+1];  
			//                 if(abs(gradient) < threshold_g)      //满足阈值要求  
			//                 {  
			//                     cont_pts.push_back(class g_point(x+1, y-1, CONT));  
			//                     p_mat[(y-1)*img->width + (x+1)] = SEED;  
			//                 }  
			//                 else                                //不满足阈值要求  
			//                 {  
			//                     p_mat[(y-1)*img->width + (x+1)] = INVAL;  
			//                 }  
			//                   
			//             }  
			//         }  
			if( !(y-1<0) )                                   //#8  
			{  
				if(p_mat[(y-1)*img->width + (x)] == INIT)  
				{  
					gradient = ((char*)(img->imageData + y*img->widthStep))[x] -   
						((char*)(img->imageData + (y-1)*img->widthStep))[x];  
					if(abs(gradient) < threshold_g)      //满足阈值要求  
					{  
						cont_pts.push_back(class g_point(x, y-1, CONT));  
						p_mat[(y-1)*img->width + (x)] = SEED;  
					}  
					else                                //不满足阈值要求  
					{  
						p_mat[(y-1)*img->width + (x)] = INVAL;  
					}  
				}  
			}  

			iter_cont ++;  
		}  

		//将cont_pts中的点赋给cont_pts_pre  
		cont_pts_pre.clear();
		iter_swap = cont_pts.begin();  
		while(iter_swap != cont_pts.end() )  
		{  
			cont_pts_pre.push_back((*iter_swap));  
			iter_swap ++;  
		}
		cont_pts.clear();


	}  
	//结束while  




	cont_pts_pre.clear(); 
	cont_pts.clear();

	// 	delete pseed_pts;
	// 	delete pcont_pts_pre;
	// 	delete pcont_pts;
}  


void display_mat(int * p_mat, int width, int height)
{
	IplImage* disp;
	disp = cvCreateImage( cvSize(width, height), 8, 3 );
	cvZero(disp);

	for(int h = 0; h < height; h++)
	{
		for(int w = 0; w < width; w++)
		{
			if(p_mat[h * width + w] == SEED)
			{
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 0] = color_templ[0*18 + 0*3 + 0];
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 1] = color_templ[0*18 + 0*3 + 1];
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 2] = color_templ[0*18 + 0*3 + 2];
			}
			else if(p_mat[h * width + w] == INIT)
			{
				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 0] = color_templ[0*18 + 2*3 + 0];
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 1] = color_templ[0*18 + 2*3 + 1];
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 2] = color_templ[0*18 + 2*3 + 2];
			}
			else if(p_mat[h * width + w] == INVAL)
			{
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 0] = color_templ[0*18 + 4*3 + 0];
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 1] = color_templ[0*18 + 4*3 + 1];
 				((UCHAR *)(disp->imageData + h*disp->widthStep))[w*3 + 2] = color_templ[0*18 + 4*3 + 2];
			}
		}
	}
	cvNamedWindow("display");
	cvShowImage("display", disp);
	cvWaitKey(0);

	cvDestroyWindow("display");
	cvReleaseImage(&disp);
}


int _tmain(int argc, _TCHAR* argv[])
{
	IplImage* img;
	img = cvLoadImage("1.bmp", CV_LOAD_IMAGE_ANYCOLOR);


	//建立需要使用的单通道8位深图像
	IplImage* img_gray;
	img_gray = cvCreateImage(cvGetSize(img), img->depth, 1);
	cvSplit(img, NULL, img_gray, NULL, NULL);

	cvNamedWindow("original image", -1);
	cvShowImage("original image", img_gray);
	cvWaitKey(0);

	//建立所需的与图像同样宽高的整型数矩阵并赋初值
	int * pres_mat;
	pres_mat = new int[img_gray->width * img_gray->height];
	for(int i = 0; i < img_gray->width * img_gray->height; i++)
	{
		pres_mat[i] = INIT;
	}

	//开始进行区域生长
	regionGrowth(img_gray, pres_mat, 1, 1, 50);

	display_mat(pres_mat, img_gray->width, img_gray->height);

	return 0;
}
regionGrowth函数详解

参数:
img:需要进行区域生长的图像,8位单通道的IplImage
p_map:整型数矩阵指针,宽高与图像相同,用于储存图像生长结果
矩阵已经被全部赋值为INIT(#define INIT 0)
x_g, y_g区域生长初始种子点
threshold_g区域生长邻域梯度的阈值
 
生长过程中存储中间数据的容器:
list<class g_point> cont_pts                 
//contour points 生长边缘链表
list<class g_point> cont_pts_pre            
//contour points previously前次生长边缘链表
class g_point为自定义的一个类,具有3个整型数成员变量:x,y坐标以及点点类型函数lbl
 
 
处理过程:
第一步,初始生长点(x_g, y_g):将此点坐标压入cont_pts_pre矩阵,并在矩阵上将此点标注为SEED
 
第二步,第一轮生长:
将cont_pts清空,存储此轮生长点边缘点。访问cont_pts_pre中的每一个点,对点进行四邻域/八邻域生长条件判断。
若满足生长条件,1、将该点接到cont_pts末尾;供下轮生长使用。2、在矩阵上将词典标注为SEED。
若不满足生长条件,之在矩阵上将此点标注为INVAL。(以后的边界,便可由INVAL来确定)
这一步骤,是由程序中连着的8个if语句完成。
 
第三步,为下一轮生长做准备。将cont_pts_pre清空,将cont_pts赋值给cont_pts_pre
 
接下来的步骤,第2、3、4、……轮生长
 
迭代终止条件:cont_pts_pre为空,则无点可生长。
 
处理结果
在p_map中,生长到的点取值为:SEED;未生长到的点:INIT;边界点:INVAL
 




在编写过程中,考虑过迭代次数、各类点的存储选择的数据结构等限制区域生长法效率的因素。俺将日后写一个运算量、处理时间的评估报告。


RegionGrowth经过优化后的程序,在此处。

http://download.csdn.net/detail/sera_ph/4505725

第一次上传资源,没有设置资源积分。希望大家能用得爽快。

此程序可将不同的联通区域用区别开来,处理的结果为:


评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值