Bootstrap

图像处理算法1——区域生长法

前几天看到一篇博客,题为《为什么你应该写博客》,学到了很多,同时也思考了很多,里面讲到“用博客的形式来记录下你有价值的思考,会带来很多好处,却没有任何明显的坏处”,一句话概括就是:书写是为了更好的思考,分享是为了让思考更有价值!    

    这是本人开通CSDN博客的第一天,刚开始着手学习计算机视觉这方面不久,对今天的工作做一个小的总结吧。

    历史:区域生长是一种古老的图像分割方法,最早的区域生长图像分割方法是由Levine等人提出的。该方法一般有两种方式,一种是先给定图像中要分割的目标物体内的一个小块或者说种子区域(seed point),再在种子区域基础上不断将其周围的像素点以一定的规则加入其中,达到最终将代表该物体的所有像素点结合成一个区域的目的;另一种是先将图像分割成很多的一致性较强,如区域内像素灰度值相同的小区域,再按一定的规则将小区域融合成大区域,达到分割图像的目的,典型的区域生长法如T. C. Pong等人提出的基于小面(facet)模型的区域生长法,区域生长法固有的缺点是往往会造成过度分割,即将图像分割成过多的区域 。  

    区域生长是一种串行区域分割的图像分割方法,其优点是基本思想相对简单,通常能将具有相同特征的联通区域分割出来,并能提供很好的边界信息和分割结果。在没有先验知识可以利用时,可以取得最佳的性能,可以用来分割比较复杂的图象,如自然景物。但是,区域生长法是一种迭代的方法,空间和时间开销都比较大,噪声和灰度不均一可能会导致空洞和过分割,并在对图像中的阴影效果处理上往往不是很好。 

    区域生长的基本思想是将具有相似性质的像素集合起来构成区域。具体先对每个需要分割的区域找一个种子像素作为生长的起点,然后将种子像素周围邻域中与种子像素具有相同或相似性质的像素(根据某种事先确定的生长或相似准则来判定)合并到种子像素所在的区域中。将这些新像素当做新的种子像素继续进行上面的过程,直到再没有满足条件的像素可被包括进来,这样,一个区域就长成了。

    区域生长是指从某个像素出发,按照一定的准则,逐步加入邻近像素,当满足一定的条件时,区域生长终止。区域生长的好坏决定于1.初始点(种子点)的选取。2.生长准则。3.终止条件。区域生长是从某个或者某些像素点出发,最后得到整个区域,进而实现目标的提取。

    简单来说下三个法则,对出需要分割的图像:1、选取图像中的一点为种子点(种子点的选取需要具体情况具体分析)。2、在种子点处进行8邻域或4邻域扩展,判定准则是:如果考虑的像素与种子像素灰度值差的绝对值小于某个门限T,则将该像素包括进种子像素所在的区域。3、当不再有像素满足加入这个区域的准则时,区域生长停止。

区域生长实现的步骤如下:

1. 对图像顺序扫描!找到第1个还没有归属的像素, 设该像素为(x0, y0);

2. 以(x0, y0)为中心, 考虑(x0, y0)的8邻域像素(x, y),如果(x,, y)满足生长准则, 将(x, y)与(x0, y0)合并(在同一区域内), 同时将(x, y)压入堆栈;

3. 从堆栈中取出一个像素, 把它当作(x0, y0)返回到步骤2;

4. 当堆栈为空时!返回到步骤1;

5. 重复步骤1 - 4直到图像中的每个点都有归属时。生长结束。

进一步解释:注意“没有归属”四个字,从种子点出发,在其8领域内查找满足生长准则的点归并到种子点所在区域内,在程序中就是通过 push 到 stack 堆栈中来实现,每一个被遍历的元素都会被标记,凡是被标记的元素在下次检测的时候都不会被考虑,因为它已经有了“归属”,区域生长的目的也就是将“归属”于种子点区域的部分分割出来而已。随着迭代次数的增加,每次在 top 一个元素并 pop 后加入到 stack 中的元素慢慢变少,直到停止生长为止!

关于区域生长的代码如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. //区域生长,4连通区域,基于一个种子点,种子点可以自选,种子点在seed图像内设置为255  
  2. void Grow(IplImage* src,IplImage* src1,IplImage* seed, int t1)//gray=255  
  3. {  
  4.     stack <seedpoint> seedd;//定义一个堆栈  
  5.     seedpoint point;//堆栈的元素为point  
  6.     // 获取图像数据,保存种子区域  
  7.     int height     = seed->height;  
  8.     int width      = seed->width;    
  9.     int step       = seed->widthStep;  
  10.     uchar* seed_data    = (uchar *)seed->imageData;  
  11.     uchar* src_data     =(uchar *)src->imageData;  
  12.     uchar* src1_data    =(uchar*)src1->imageData;  
  13.     int temp;//用于当前点的像素值  
  14. //现在种子点图片中找到所有种子点,一般种子点选择灰度值为255的
  15.     for(int i=0;i<height;i++)  
  16.     {  
  17.         for(int j=0;j<width;j++)  
  18.         {  
  19.             if(seed_data[i*step+j]==255)  
  20.             {  
  21.                 point.x=i;  
  22.                 point.y=j;  
  23.                 temp = src1_data[point.x*step+point.y];  
  24.                 seedd.push(point);  
  25.             }  
  26.         }  
  27.     }  
  28.     seedpoint temppoint;//临时存放种子点的中间变量  
  29.     while(!seedd.empty())  
  30.     {  
  31.         point=seedd.top();           //返回栈顶数据,不删除     
  32.         seedd.pop();                 //栈顶数据出栈,删除栈顶元素,但不返回其值  
  33.       
  34.         if((point.x>0)&&(point.x<(height-1))&&(point.y>0)&&(point.y<(width-1)))//如果种子点在图像范围内,分别检测其8个邻域点  
  35.         {  
  36.             //邻域一点像素为0,即不是种子点本身,并且该点与种子点之差小于设定的阈值  
  37.             if((seed_data[(point.x-1)*step+point.y]==0)&&(abs(src1_data[(point.x-1)*step+point.y]-temp) < t1))  
  38.             {  
  39.                 //cvSet2D(seed,(point.x-1),point.y,pixel);  
  40.                 seed_data[(point.x-1)*step+point.y]=255;  
  41.                 src_data[(point.x-1)*step+point.y]=src1_data[(point.x-1)*step+point.y];  
  42.                 temppoint.x=point.x-1;  
  43.                 temppoint.y=point.y;  
  44.                 seedd.push(temppoint);  
  45.             }  
  46.             if((seed_data[point.x*step+point.y+1]==0)&&(abs(src1_data[point.x*step+point.y+1]-temp) < t1))  
  47.             {  
  48.                 //cvSet2D(seed,(point.x),(point.y+1),pixel);  
  49.                 seed_data[point.x*step+point.y+1]=255;  
  50.                 src_data[point.x*step+point.y+1]=src1_data[point.x*step+point.y+1];  
  51.                 temppoint.x=point.x;  
  52.                 temppoint.y=point.y+1;  
  53.                 seedd.push(temppoint);  
  54.             }  
  55.             if((seed_data[point.x*step+point.y-1]==0)&&(abs(src1_data[point.x*step+point.y-1]-temp) < t1))  
  56.             {  
  57.                 //cvSet2D(seed,(point.x),(point.y-1),pixel);  
  58.                 seed_data[point.x*step+point.y-1]=255;  
  59.                 src_data[point.x*step+point.y-1]=src1_data[point.x*step+point.y-1];  
  60.                 temppoint.x=point.x;  
  61.                 temppoint.y=point.y-1;  
  62.                 seedd.push(temppoint);  
  63.             }  
  64.             if((seed_data[(point.x+1)*step+point.y]==0)&&(abs(src1_data[(point.x+1)*step+point.y]-temp) < t1))  
  65.             {  
  66.                 //cvSet2D(seed,(point.x),(point.y+1),pixel);  
  67.                 seed_data[(point.x+1)*step+point.y]=255;  
  68.                 src_data[(point.x+1)*step+point.y]=src1_data[(point.x+1)*step+point.y];  
  69.                 temppoint.x=point.x+1;  
  70.                 temppoint.y=point.y;  
  71.                 seedd.push(temppoint);  
  72.             }  
  73. /  
  74.             if((seed_data[(point.x-1)*step+point.y-1]==0)&&(abs(src1_data[(point.x-1)*step+point.y-1]-temp) < t1))  
  75.             {  
  76.                 //cvSet2D(seed,(point.x-1),point.y,pixel);  
  77.                 seed_data[(point.x-1)*step+point.y-1]=255;  
  78.                 src_data[(point.x-1)*step+point.y-1]=src1_data[(point.x-1)*step+point.y-1];  
  79.                 temppoint.x=point.x-1;  
  80.                 temppoint.y=point.y-1;  
  81.                 seedd.push(temppoint);  
  82.             }  
  83.             if((seed_data[(point.x-1)*step+point.y+1]==0)&&(abs(src1_data[(point.x-1)*step+point.y+1]-temp) < t1))  
  84.             {  
  85.                 //cvSet2D(seed,(point.x-1),point.y,pixel);  
  86.                 seed_data[(point.x-1)*step+point.y+1]=255;  
  87.                 src_data[(point.x-1)*step+point.y+1]=src1_data[(point.x-1)*step+point.y+1];  
  88.                 temppoint.x=point.x-1;  
  89.                 temppoint.y=point.y+1;  
  90.                 seedd.push(temppoint);  
  91.             }  
  92.             if((seed_data[(point.x+1)*step+point.y-1]==0)&&(abs(src1_data[(point.x+1)*step+point.y-1]-temp) < t1))  
  93.             {  
  94.                 //cvSet2D(seed,(point.x-1),point.y,pixel);  
  95.                 seed_data[(point.x+1)*step+point.y-1]=255;  
  96.                 src_data[(point.x+1)*step+point.y-1]=src1_data[(point.x+1)*step+point.y-1];  
  97.                 temppoint.x=point.x+1;  
  98.                 temppoint.y=point.y-1;  
  99.                 seedd.push(temppoint);  
  100.             }  
  101.             if((seed_data[(point.x+1)*step+point.y+1]==0)&&(abs(src1_data[(point.x+1)*step+point.y+1]-temp) < t1))  
  102.             {  
  103.                 //cvSet2D(seed,(point.x-1),point.y,pixel);  
  104.                 seed_data[(point.x+1)*step+point.y+1]=255;  
  105.                 src_data[(point.x+1)*step+point.y+1]=src1_data[(point.x+1)*step+point.y+1];  
  106.                 temppoint.x=point.x+1;  
  107.                 temppoint.y=point.y+1;  
  108.                 seedd.push(temppoint);  
  109.             }  
  110.         }  
  111.     }   
  112. }  


 
实现效果图如下: 


;