二值图像的边缘追踪(内边缘与外边缘)

来源:互联网 发布:jsp按钮调用java方法 编辑:程序博客网 时间:2024/05/19 18:48

二值图像的边缘追踪(内边缘与外边缘)
  近段时间来,在学习图像处理的课程。使用Lab Windows/CVI为平台。自己学过一些C语言,不过对于CVI可是第一次接触,虽说它是C语言环境,可不是纯C的。举个例子:变量的定义不可以在switch...case语句里面。
  对图像进行处理,首先要先将其二值化。二值化的关键是在于阈值的选择。CVI中利用IMAQ里的IPI_Threshold可以很容易实现二值化,阈值的选择可以根据图像的直方图选择其峰谷的值的作为阈值。在此不多说,有关资料查IMAQ。
  图像二值化后(目标灰度值为128,背景灰度值为0),要对其进行边缘追踪。首先要对其进行区域标记,不同的区域标记不同的值(非背景与目标灰度值)。
  区域标记方生长法,可以对8领域进行标记也可以,使用4领域也行。使用4领域的算法如下:

int CVICALLBACK Labeling_image (int panel, int control, int event,
  void *callbackData, int eventData1, int eventData2)
{
   
  int x,y,startx,starty;
    int width,height;
    float gray_level;
    IPIImageInfo Image_Info;
   
 switch (event)
  {
  case EVENT_COMMIT:
       IPI_GetImageInfo(TempImage,&Image_Info);
     width=Image_Info.width;
     height=Image_Info.height;
    LabelledImage=TempImage;
     for (y=0;y<height;y++)
       for(x=0;x<width;x++)
         {
           IPI_GetPixelValue(TempImage,x,y,&gray_level); //得到原图像点(x,y)的像素值
           if(gray_level==128.0)
           {
              startx=x;
              starty=y;
              FloodFill4(startx,starty,gray_level,20+10*AreaNum);//4领域区域生长法
              AreaNum++;//连通区域数目
           }
       }
      IPI_SetWindowAttribute(3,ATTR_LEFT,100);
      IPI_SetWindowAttribute(3,ATTR_TOP,15);
      IPI_WindDraw(LabelledImage,3,"标记图像",TRUE);
   break;
  }
 return 0;
}

 

区域标记完后,就可以进行边界追踪。外边界追踪比较容易,日前已经有不少算法,如虫随法,光栅扫描法。本人使用的是虫随法。而对于内边界追踪则比较难,在网上没有找到有用的算法。所以本人自己写算法。经过我的研究,我对内边界追踪也使用虫随法。思想如下:先找到目标区域的最小外接矩形,然后在这个矩形区域里面搜索内边界点(这是最难的,我花费最久时间在这方面),找到后,由于内边界是被目标区域包围的,所以这时把目标区域看成背景,把被内边界包围的区域看成目标,这样用虫随法就可以很容易的把内边界追踪出来。另外还有一个内边界追踪算法,如下:
    内边界跟踪算法
通过对二值图像进行图像腐蚀合相减处理, 生成了目标物
新体内部的零域。根据封闭空间的连通性及下述的内边界点跟踪
原则, 在当前点八邻域内寻找邻接“1”点的“0”点, 进行跟踪搜
索并标记为“- 1”, 为下一步外边界跟踪做准备。
(1) 根据外边界起始点在其八邻域内寻找内部“0”点作为
内边界起始点 Ei1 并标记;
e)各候选方向点权值
(2) 在当前点八邻域内按顺时针寻找首个顺序邻接“1”点
图 2 边界跟踪步骤演示
的“0”点作为下一个内边界点 Eik;
(3) 若新边界点 Eik=Ei1,即回到了内边界起始点,当次跟踪结束;
(4) 若新边界点 Eik≠Ei1,则以 Eik 作为当前点,对其标记,
象,然后转(2)。

程序代码如下:

 


int CVICALLBACK MultiTrace (int panel, int control, int event,
  void *callbackData, int eventData1, int eventData2)
{
 IPIImageInfo Image_Info;
    int x,y,k,startx,starty,secondx,secondy,width,height;
    int flag,nowx,nowy,lastx,lasty,nextx,nexty,direction,nextdirection;
    int ddirection;//内边界方向
    int x1,x2,y1,y2;//矩形区域四角
    int firstdirection;
   float gray_level;
   int ii,i,j,now_x,now_y; //循环计数
        float gray_leveled,bounded[8];
        int num=0,black=0,white=0,gray=0;
   flag=0;
 switch (event)
  {
  case EVENT_COMMIT:
   IPI_SetWindowAttribute(2,ATTR_LEFT,150);
  IPI_SetWindowAttribute(2,ATTR_TOP,250);
     IPI_GetImageInfo(LabelledImage,&Image_Info);
     width=Image_Info.width;
     height=Image_Info.height;
    // IPI_SetImageSize(MultiTraceImage,width,height);
     MultiTraceImage=LabelledImage;
  for (k=0;k<AreaNum;k++)
  {//区域个数
    
     for (y=0;y<height;y++)
     {
       for(x=0;x<width;x++)
         {
           IPI_GetPixelValue(LabelledImage,x,y,&gray_level);
           if(gray_level==20+10*k)
           {
              startx=x;
              starty=y;
              flag=1;
              break;
           }
         }
          
           if(flag) break;
         }   //找到起始边界点
  IPI_SetPixelValue(MultiTraceImage,x,y,255);
     lastx=startx; lasty=starty;
  direction=2;
  do
  {
     flag=0;
           do
              {
              direction=(direction+1)%8;
              nowx=lastx+direction_code[direction].dx;
              nowy=lasty+direction_code[direction].dy;
           
              flag=flag+1;
              if(startx==nowx&&starty==nowy) flag=8;
              if(flag==8) break;
               IPI_GetPixelValue(LabelledImage,nowx,nowy,&gray_level);
              }while (gray_level==0.0);
             
           if(flag==8) break; 
           direction=(direction+5)%8;
           secondx=lastx;
           secondy=lasty;
           lastx=nowx;
           lasty=nowy;
     IPI_SetPixelValue(MultiTraceImage,nowx,nowy,255);
      IPI_WindDraw(MultiTraceImage,2,"多区域边缘追踪图像",TRUE);             
      }
       while(!(startx==secondx&&starty==secondy&&nextx==nowx&&nexty==nowy));
      //追踪完外边界后
           //扫描整副图像,找出目标的矩形区域
        for (y=0;y<height;y++)
    for(x=0;x<width;x++)
    {
      IPI_GetPixelValue(MultiTraceImage,x,y,&gray_level);
      if(gray_level==20+10*k)
        { y2=y;break;}
    }
    for (y=height;y>0;y--)
    for(x=0;x<width;x++)
    {
      IPI_GetPixelValue(MultiTraceImage,x,y,&gray_level);
      if(gray_level==20+10*k)
        { y1=y;break;}
    } 
    for(x=0;x<width;x++) 
    for (y=0;y<height;y++)
  
    {
      IPI_GetPixelValue(MultiTraceImage,x,y,&gray_level);
      if(gray_level==20+10*k)
        { x2=x;break;}
    }
     for(x=width;x>0;x--)  
    for (y=0;y<height;y++)
  
    {
      IPI_GetPixelValue(MultiTraceImage,x,y,&gray_level);
      if(gray_level==20+10*k)
        { x1=x;break;}
       
    }
    // 结束矩形区域的查找
      //追踪内边界
  
      flag=0;     // 
    for (j=y1;j<y2;j++)
    for(i=x1;i<x2;i++)
    {  
                 black=0;white=0;gray=0;

           IPI_GetPixelValue(MultiTraceImage,i,j,&gray_leveled);
           /////////// //判断点(x,y)是不是内部点 
       if(gray_leveled==20+10*k)
   {
            for (ii=0;ii<8;ii++)
            {
               now_x=i+direction_code[ii].dx;
                     now_y=j+direction_code[ii].dy;
                    IPI_GetPixelValue(MultiTraceImage,now_x,now_y,&bounded[ii]);
                    if(bounded[ii]==0) black=1;
                    else if(bounded[ii]==20+10*k)  gray=1;
                   else if(bounded[ii]==255) white=1;
                  }
        if(black==1&&gray==1&&white!=1)  //如果某点的8领域有背景点(blace)和目标点(gray)且没有外边界点(white),则它为内边界点
       {    
           startx=i;
           starty=j;
           flag=1;
           IPI_SetPixelValue(MultiTraceImage,startx,starty,255);
          lastx=startx; lasty=starty;
           ddirection=2;//设定搜索起始方向为2
          do
          {  flag=0;
                  do
                     {
                   ddirection=(ddirection+1)%8;
                      nowx=lastx+direction_code[ddirection].dx;
                      nowy=lasty+direction_code[ddirection].dy;
            
                     flag=flag+1;
                     if(startx==nowx&&starty==nowy) flag=8;
                     if(flag==8) break;
                     IPI_GetPixelValue(MultiTraceImage,nowx,nowy,&gray_level);
                     }while (gray_level==20+10*k);
             if(flag==8) break;    
                  ddirection=ddirection+5;
                  secondx=lastx;
                  secondy=lasty;
                  lastx=nowx;
                  lasty=nowy;
            IPI_SetPixelValue(MultiTraceImage,nowx,nowy,255);
          
            IPI_WindDraw(MultiTraceImage,2,"多区域边缘追踪图像",TRUE);   
          } while(!(startx==secondx&&starty==secondy&&nextx==nowx&&nexty==nowy));
                   
       } // if(black==1&&gray==1&&white!=1) 
       }  // if(gray_leveled==20+10*k)   判断内部点结束    
  }  // //追踪内边界结束   
  
       flag=0;
    }  //for (k=0;k<AreaNum;k++)  
       break;
  }
 return 0;
}

  至此边界追踪结束,文中的代码都是是CVI环境下实现的,只是本人编写项目的一部分。有什么不明可联系本人。

原创粉丝点击