图像细化算法

来源:互联网 发布:金桥软件公园 编辑:程序博客网 时间:2024/06/05 15:59
 图像细化(Image Thinning),一般指二值图像的骨架化(Image Skeletonization) 的一种操作运算。

         所谓的细化就是经过一层层的剥离,从原来的图中去掉一些点,但仍要保持原来的形状,直到得到图像的骨架。骨架,可以理解为图象的中轴。

    好的细化算法一定要满足:

  • 收敛性;
  • 保证细化后细线的连通性
  • 保持原图的基本形状
  • 减少笔画相交处的畸变
  • 细化结果是原图像的中心线
  • 细化的快速性和迭代次数少

依据是否使用迭代运算可以分为两类:

  • 非迭代算法
    • 一次即产生骨架,如基于距离变换的方法。游程长度编码细化等。
  • 迭代算法

即重复删除图像边缘满足一定条件的像素,最终得到单像素宽带骨架。

迭代方法依据其检查像素的方法又可以再分成

  • 串行算法

是否删除像素在每次迭代的执行中是固定顺序的,它不仅取决于前次迭代的结果,也取决于本次迭代中已处理过像素点分布情况.

  • 并行算法

像素点删除与否与像素值图像中的顺序无关,仅取决于前次迭代的结果

细化算法:

  • Burning Algorithm

使用迭代的方法去除图像的边界, 可使用扫描线法来获取边界

 

  • Zhang并行快速细化算法

模板:

p3 p2 p9

p4 p1 p8

p5 p6 p7

   第一步,(其中p1为前景点,如果以下四个条件同时满足,则删除p1,即令p1=0)

1. 2<=N(p1)<=6                    // 中心为黑点

2. Z0(p1)=1                // Nz为八邻域中黑点的数目

3. p2*p8*p6=0           // 避免图像被打断( 其反条件时不可删)

4. p4*p8*p6=0 

 

其中,Z0(p1)是以p2,p3,...p8,p9为序时,这些点的值从0->1变化的次数

          N(p1)是p1的非0邻近点的个数

被判定为删除的点暂不删除,但要加以记录。

等所有边界点都被判断完后,再一起将所有标记了的点删除,接下来进入第二阶段的删除步骤。

 

   第二步,按照如下条件进行第二阶段的删除,条件为

1. 2<=N(p1)<=6                       // 中心为黑点

2.  Z0(p1)=1                  // Nz为八邻域中黑点的数目

3. p2*p4*p6=0                // 避免图像被打断( 其反条件时不可删)

4. p2*p4*p8=0  

同第一步一样,判定要删除的点只是加以记录而暂不删除,等待最后同时删除

 

对一副图像反复执行第一步与第二步的算法步骤,知道都没有可删除的点为止

 

我的zhang细化代码如下:

//                                        p3  p2  p1

//**********使用zhang并行快速算法进行细化 p4  p   p0

//                                        p5  p6  p7

void ZhangThinning(int w,int h,BYTE *imgBuf)

{

    int neighbor[8];

 

    BYTE *mark=new BYTE[w*h];

    memset(mark,0,w*h);

 

    BOOL loop=TRUE;

    int x,y,k;

    int markNum=0;

 

    while(loop)

    {

       loop=FALSE;

 

       //第一步

       markNum=0;

       for(y=1;y<h-1;y++)

       {

           for(x=1;x<w-1;x++)

           {

              //条件1:p必须是前景点

              if(imgBuf[y*w+x]==0 ) continue;

 

              neighbor[0]= imgBuf[y*w+x+1] ;

              neighbor[1]= imgBuf[(y-1)*w+x+1];

              neighbor[2]= imgBuf[(y-1)*w+x];

              neighbor[3]= imgBuf[(y-1)*w+x-1];

              neighbor[4]= imgBuf[y*w+x-1];

              neighbor[5]= imgBuf[(y+1)*w+x-1];

              neighbor[6]= imgBuf[(y+1)*w+x];

              neighbor[7]= imgBuf[(y+1)*w+x+1];

 

              //条件2:2<=N(p<=6

              int np=(neighbor[0]+neighbor[1]+neighbor[2]+neighbor[3]+neighbor[4]+neighbor[5]+neighbor[6]+neighbor[7])/255;

              if(np<2 || np>6) continue;

 

              //条件3:S(p=1

              int sp=0;

              for(int i=1;i<8;i++)

              {

                  if(neighbor[i]-neighbor[i-1]==255)

                     sp++;

              }

              if(neighbor[0]-neighbor[7]==255)

                  sp++;            

              if(sp!=1) continue;

 

              //条件4:p2*p0*p6=0

              if(neighbor[2]&neighbor[0]&neighbor[6]!=0)

                  continue;

                //条件5:p0*p6*p4=0

              if(neighbor[0]&neighbor[6]&neighbor[4]!=0)

                  continue;

 

 

              //标记删除

              mark[w*y+x]=1;   

              markNum++;

              loop=TRUE;

           }

       }

 

       //将标记删除的点置为背景色

       if(markNum>0)

       {

           for(y=0;y<h;y++)

           {

              for(x=0;x<w;x++)

              {

                  k=y*w+x;

                  if(mark[k]==1)

                  {

                     imgBuf[k]=0;

                  }

              }

           }

       }

      

 

       //第二步

        markNum=0;

       for(y=1;y<h-1;y++)

       {

           for(x=1;x<w-1;x++)

           {

              //条件1:p必须是前景点

              if(imgBuf[y*w+x]==0 ) continue;

 

              neighbor[0]= imgBuf[y*w+x+1] ;

              neighbor[1]= imgBuf[(y-1)*w+x+1];

              neighbor[2]= imgBuf[(y-1)*w+x];

              neighbor[3]= imgBuf[(y-1)*w+x-1];

              neighbor[4]= imgBuf[y*w+x-1];

              neighbor[5]= imgBuf[(y+1)*w+x-1];

              neighbor[6]= imgBuf[(y+1)*w+x];

              neighbor[7]= imgBuf[(y+1)*w+x+1];

 

              //条件2:<=N(p)<=6

              int np=(neighbor[0]+neighbor[1]+neighbor[2]+neighbor[3]+neighbor[4]+neighbor[5]+neighbor[6]+neighbor[7])/255;

              if(np<2 || np>6) continue;

 

              //条件3:S(p)=1

              int sp=0;

              for(int i=1;i<8;i++)

              {

                  if(neighbor[i]-neighbor[i-1]==255)

                     sp++;

              }

              if(neighbor[0]-neighbor[7]==255)

                  sp++;

              if(sp!=1) continue;

 

              //条件4:p2*p0*p4==0

              if(neighbor[2]&neighbor[0]&neighbor[4]!=0)

                  continue;

              //条件5:p2*p6*p4==0

              if(neighbor[2]&neighbor[6]&neighbor[4]!=0)

                  continue;

 

              //标记删除

              mark[w*y+x]=1;   

              markNum++;

              loop=TRUE;

           }

       }

 

       //将标记删除的点置为背景色

       for(y=0;y<h;y++)

       {

           for(x=0;x<w;x++)

           {

              k=y*w+x;

              if(mark[k]==1)

              {

                  imgBuf[k]=0;

              }

           }

       }

 

    } 

}

 

 

 

判断一个点是否能去掉, 要根据它的八个相邻点的情况来判断。(中间的点)


       (1)不能删,因为它是个内部点,我们要求的是骨架,如果连内部点也删了,骨架也会被掏空的;

       (2)不能删,和(1)是同样的道理;

       (3)可以删,这样的点不是骨架;

       (4)不能删,因为删掉后,原来相连的部分断开了;

       (5)可以删,这样的点不是骨架;

       (6)不能删,因为它是直线的端点,如果这样的点删了,那么最后整个直线也被删了,剩不下什么;

   总结:

(1)内部点不能删除;

(2)孤立点不能删除;

(3)直线端点不能删除;

(4)如果P是边界点,去掉P后,如果连通分量不增加,则P可以删除。

 

  • HilditchPavlidisRosenfeld细化算法

这类算法则是在程序中直接运算,根据运算结果来判定是否可以删除点的算法,差别在于不同算法的判定条件不同。

Hilditch算法使用于二值图像,比较普通,是一般的算法;

Pavlidis算法通过并行和串行混合处理来实现,用位运算进行特定模式的匹配,所得的骨架是8连接的,使用于0-1二值图像;

Rosenfeld算法是一种并行细化算法,所得的骨架形态是8-连接的,使用于0-1二值图像。

(后两种算法的效果要更好一些,但是处理某些图像时效果一般,第一种算法使用性强些。)

 

  • 索引表细化算法

经过预处理后得到待细化的图像是01二值图像。像素值为1的是需要细化的部分,像素值为0的是背景区域。基于索引表的算法就是依据一定的判断依据,所做出的一张表,然后根据魔鬼要细化的点的八个邻域的情况查询,若表中元素是1,若表中元素是1,则删除该点(改为背景),若是0则保留。因为一个像素的8个邻域共有256中可能情况,因此,索引表的大小一般为256

         查找表为二值图像处理提供了简洁而有效的方法。考虑一个像素的3乘3邻域。由于在这个邻域范围有9个像素,每个像素有两个状态(二值图像,取0,1),那么整个邻域不同状态的总数量为2^9=512 .这样,我们可以相对不同的情况(512种),来安排对应的输出值,而这512种可能是事先预知的,给每一个单元(一共9个单元)分别安排不同的权值,

           

1 8       6

2 16 128

4 32 256

也就是2的不同幂次,0,1,2,3。。。 8次幂

那么,某种状态数值就是加权值的和。

比如,

下面一种邻域组合:

0 1 0

1 1 0

0 0 1

它的值=2+8+16+256=282

这样的话,我们通过一个数值,就可以表达一种3乘3邻域的一种空间分布状态。

                             
原创粉丝点击