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

news/2024/7/7 19:17:22

二值图像的边缘追踪(内边缘与外边缘)
  近段时间来,在学习图像处理的课程。使用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环境下实现的,只是本人编写项目的一部分。有什么不明可联系本人。


http://www.niftyadmin.cn/n/4071045.html

相关文章

新手单元测试的疑惑

今天刚刚学习如何在vs中进行单元测试&#xff0c;在网上搜索了一番后&#xff0c;下载了最新的Nunit。在公司是用vs2003的&#xff0c;按着教程的做法将Nunit的使用方法实践了番&#xff0c;很是喜欢绿灯的Pass。晚上回家后在自己的vs2005上也安装了&#xff0c;但正如网上很多…

“LinkedOut” 失败注入测试框架

领英工程团队最近更详细地讨论了他们的“LinkedOut”失败注入测试框架。该框架支持围绕应用程序和服务弹性的假设生成数据&#xff0c;并允许通过linkin LiX a/B测试框架或通过cookie中的数据向特定请求注入失败。可以测试的失败场景包括错误、延迟和超时。LinkedOut项目是更大…

The MASM32 SDK version 10 发布了!

用win32asm做开发的朋友都知道masm32SDK开发包&#xff0c;每一次的更新都带有不少的新东西出现。 这次发布了10版本&#xff0c;主要更新了什么&#xff1f;详细的信息大家可以到 http://www.masm32.com/ 查看&#xff0c; 这里我翻译一下10的特性&#xff1a; 1&#xff1…

发布软件:TreeInfo(分层信息管理器)

软件下载地址&#xff1a; http://jhkdiy.download.csdn.net/ 我发觉对信息进行分门别类和有条理地进行整理在很大程度上能帮助我们记忆和理解一些难懂的概念。而很多信息都可以像windows的文件目录树一样进行分层管理&#xff0c;像现实生活中的公司组织架构图&#xff1a;总…

K-Means算法的10个有趣用例

K-means算法具有悠久的历史&#xff0c;并且也是最常用的聚类算法之一。K-means算法实施起来非常简单&#xff0c;因此&#xff0c;它非常适用于机器学习新手爱好者。首先我们来回顾K-Means算法的起源&#xff0c;然后介绍其较为典型的应用场景。 起源 1967年&#xff0c;James…

打造自定义的 AfxMessageBox

一、需求   与标准的 MessageBox 相比&#xff0c;MFC 提供了 AfxMessageBox 的方法是我们对消息框的变得更加容易。然而简单的 AfxMessageBox 有时已经不能够满足我们的需求了&#xff1a;有时候我仅仅想提示用户一下&#xff0c;并不需要用户确认&#xff0c;也就是说…

NTDDI_VERSION,_WIN32_WINNT,WINVER,_WIN32_IE定义宏的含义

在使用一些新版本的API&#xff0c;或者控件的新特性&#xff08;比如新版的ComCtl32.dll&#xff09;的时候,你可能会得到“error C2065: undeclared identifier.“这个错误。原因是这些功能是依赖于你的操作系统的版本的。而你的头文件中的定义并不是最新的。&#xff08;对于…

令人触目惊心的软件工程!

触目惊心&#xff1f;是的&#xff0c;我没说错&#xff0c;事实上该项目已经瘫痪了。 公司是做电力行业的软件为主的&#xff0c;该行业在业务流程方面并不复杂&#xff0c;但是在计算方面却难以琢磨。公司在一开始的时候由两个人负责该项目&#xff0c;因为公司已有网络版&am…