原创 (原创)图像处理学习系列4:单区域边界跟踪

2009-3-16 21:50 7196 9 10 分类: 软件与OS

边缘检测的方法有
  (1)使用边缘检测算子
  (2)形态学操作,使用原图像和开闭运算得到的结果进行异或运算
  (3)边缘跟踪,可以直接对灰度图片进行边缘跟踪
 
 第一种情况使用边缘检测算子得到的边沿具有一定的厚度。形态学操作得到的边界具有单像素宽的优点。他们都可以对图片进行全局处理。但是无论哪种情况都要进行轮廓的跟踪来得到轮廓的数据才能进行下面的计算。

边缘跟踪我看的是陆宗骐的一本书,里面对边缘跟踪讲解的很详细。我大概说一下
边缘的记录有链码表和线段表2种,链码表适合计算周长,线段表容易计算面积以及相关的,他们之间可以相互的转换。

跟踪的原理我就不写了,太长,下面的文档里面有讲
二值图像目标邻域点法边界跟踪算法.PDFPDF

二值图像中目标物体轮廓的边界跟踪算法.PDFPDF

基于二值图像的目标边界跟踪算法及应用.PDFPDF

一种基于优先搜索方向的边界跟踪算法.PDFPDF

基于边界跟踪的区域面积计算.PDFPDF

图像测量中的边界跟踪算法改进.PDFPDF


网上的代码;http://loren.cqthx.com/browse.aspx?Group=1

下面是我的代码:写了2天的时间才完善点不过还有一下问题?:
1.在一些极值的情况下,例如边界刚好和边缘重合的情况。
  在这种情况下,需要对边缘方向进行判断。
  如果只是想刚才那样进行极值处理,肯定只会在远处循环
2.对于北京比较暗、边界亮度也不太高的图片需要预处理的图片的检测,如果还是用上面的处理方法,检测不到点的。要进行预处理才行

3.增加4邻域 8邻域 左右看
4.需改BOOL ImgDrawTrace(BITMAPINFO* pbmpinfo,BYTE* pbmpdata,int *code,int black_or_white)函数,通过最后一个参数来设置线条颜色
遗留问题:
搜索方向的改变以及搜索算法没有进行优化,可能会出现某个部分检测不到或者在某个角落里面进行死循环的问题。还有就是阈值背景比较暗的话不行

/*******************************************************************************
边界跟踪寻找第一个边界点
图像信息
图像数据
阈值:默认检测的是边界具有低灰度,小于阈值确认是边界
///////
寻找方向从走到右 从上到下
///////
返回值 :失败时返回(0,0)
*******************************************************************************/
ImgDot ImgFindFirstDot(BITMAPINFO* pbmpinfo,BYTE* pbmpdata,int threshold)
{

    LONG  img_width=pbmpinfo->bmiHeader.biWidth;
    LONG  img_heigth=pbmpinfo->bmiHeader.biHeight;
        LONG  Linebyte =( pbmpinfo->bmiHeader.biBitCount * img_width +31)/32*4;
    LONG  ImageSize=Linebyte * img_heigth;

    ImgDot temp;
    temp.cx=0;
    temp.cy=0;
    if (pbmpdata == NULL)
    {
        return temp;
    }
       
        BYTE *psrc= pbmpdata;
    for (LONG heigth = 0 ; heigth < img_heigth ;heigth++  )
    {
       
        for (LONG width = 0 ; width < img_width ; width++)
        {
                  psrc = (pbmpdata + (ImageSize  -Linebyte- heigth * Linebyte) + width);
                          if ((*psrc) <=threshold)
              {
                              temp.cx = width;
                  temp.cy = heigth;
                  return temp;
              }
        }
    }

       return temp;

}
/***************************************************************************
轮廓跟踪之寻找下一个边界点
当前点坐标
得到的下一个点坐标,开始的方向必须指向背景像素
搜索下一个点的初始方向
阈值:默认检测的是边界具有低灰度,小于阈值确认是边界
使用的链码,是4链码还是8链码
搜索的方向
//返回值:
direction 是从当前点到下一个点的方向
TRUE :找到新的边界点
FALSE:该点为孤立点
****************************************************************************/
BOOL ImgNextDot(BITMAPINFO* pbmpinfo,BYTE* pbmpdata,ImgDot *current , ImgDot *next , char *direction,int threshold,int chain,int search_direction)
{
    int inc[8][2]={{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}}; //搜索方向与坐标

        BOOL flag=FALSE;//搜索是否成功成功标志
        int  ns=*direction;

    int temp_direction=0;
        int gain=1;
    int temp=0;
    int x=current->cx;
    int y=current->cy;
   
    if (chain==IMG_CHAIN_4)
    {
             gain = 2;
    }
    if (chain==IMG_CHAIN_8)
    {
         gain = 1;
    }
        if (search_direction==IMG_SEARCH_DIR_RIGHT)//向右看齐
        {   
        for (int nx=ns + 8; nx > ns ; nx -= gain)
        {
                         temp_direction = nx % 8 ;       
                     //得到方向
                     //这里出现的问题:当输入的点是0的时候,因为ImgDot里面定义的是无符号类型,就出现了溢出
                     //还没有解决极限情况
                      /*
                     3月8号
                     出现极值情况的时候,
                      */
                     next->cx =  x+ inc[temp_direction][0];

                     next->cy =  y+ inc[temp_direction][1];
             
                     temp = ImgGetPixel(pbmpinfo,pbmpdata,*next);
             if(temp == -1)
             {
                 return FALSE;
             }

                         if ( temp <= threshold)//检测到新边界点
                                      break;
                         else
                              continue;
        }
    }
        if (search_direction==IMG_SEARCH_DIR_LIGHT)//向左看齐
        {
        for (int nx = ns; nx < ns + 8 ; nx += gain)
        {
                         temp_direction = nx % 8 ;       
                     //得到方向
                     //这里出现的问题:当输入的点是0的时候,因为ImgDot里面定义的是无符号类型,就出现了溢出
                     //还没有解决极限情况
                      /*
                     3月8号
                     出现极值情况的时候,
                      */
                     next->cx =  x+ inc[temp_direction][0];

                     next->cy =  y+ inc[temp_direction][1];
             
                     temp = ImgGetPixel(pbmpinfo,pbmpdata,*next);
             if(temp == -1)
             {
               return FALSE;
             }

                         if ( temp <= threshold)//检测到新边界点
                                      break;
                         else
                              continue;
        }

        }

     //这个判断必须是在初始化指针指向背景方向为前提
    //3月9号
        //如果使用4邻域的话会出现进入初始的方向指向的就是边界的情况,如果进行下面的判断,返回的值是0
    //
//    if (temp_direction != ns )         
//    {
       *direction = temp_direction;
        flag = TRUE;         //搜索成功
//    }

        return flag;
}

/****************************************************************************************
单区域跟踪
参数:
图片信息
图片数据
初始化点
初始方向
链码数据
使用的链码,是4链码还是8链码
搜索的方向
///////
链码:
前两个数据是初始化坐标,第三个是链表总数,下面的是链码
/////
返回值:搜索到的点数  ,所有失败返回-1
****************************************************************************************/
int ImgSingleTrace(BITMAPINFO* pbmpinfo,BYTE* pbmpdata,ImgDot *Begin_Dot,char Begin_direction,int *code,int chain,int search_direction)
{

    BOOL flag = TRUE;
    code[0] = Begin_Dot->cx;   //初始点x坐标
    code[1] = Begin_Dot->cy;   //初始点y坐标
    code[2] = 3;               //初始链表点数
    code[3] = -1 ;

    ImgDot  *current_dot ;
    ImgDot  *next_dot  ;
    current_dot = new ImgDot;
    next_dot    = new ImgDot;

    memcpy(current_dot,Begin_Dot,sizeof(ImgDot));

    char    temp_direction = Begin_direction;
    int     code_num=3;

    while(flag)
    {
       if (ImgNextDot(pbmpinfo,pbmpdata,current_dot,next_dot,&temp_direction,200,chain,search_direction))
       {
              if (current_dot->cx == Begin_Dot->cx && current_dot->cy==Begin_Dot->cy && temp_direction==code[3] )//检测结束标志
              {
              break;
              }

          code[code_num++] = temp_direction ;             //存储链表数据

          memcpy(current_dot,next_dot,sizeof(ImgDot));

          //current_dot = next_dot;                         //把这次检测到的数据作为下次检测的当前点
              if (search_direction==IMG_SEARCH_DIR_RIGHT)//向右看齐
              {
              if (chain == IMG_CHAIN_4)
              {
                  temp_direction =( temp_direction  + 2) % 8;
              }
              if (chain == IMG_CHAIN_8)
              {
                  temp_direction =( temp_direction  + 3) % 8;
              }

              }
               if (search_direction==IMG_SEARCH_DIR_LIGHT)//向右看齐
              {
               if (chain == IMG_CHAIN_4)
               {
                   temp_direction =(temp_direction  +  6) % 8;
               }
               if (chain == IMG_CHAIN_8)
               {
                   temp_direction = (temp_direction  + 6) % 8;
               }
              }
         
        /*  if (temp_direction%2)                           //改变方向???????????????????
          {
              temp_direction = (temp_direction  + 1) % 8;
          }
          else
              temp_direction = (temp_direction  + 2) % 8;*/



       }
       else
       {
           return -1;
       }

    } 
   
     code[2] = code_num - 3;   
     delete current_dot;
     delete next_dot;
                          //存储链表中链码的数目
     return code[2];

}

/*************************************************************************************
画出轮廓
图像信息
图像数据
链码
线条的颜色
/////该函数不改变数据信息
***************************************************************************************/
BOOL ImgDrawTrace(BITMAPINFO* pbmpinfo,BYTE* pbmpdata,int *code,int black_or_white)
{
    int inc[8][2]={{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}}; //搜索方向与坐标
    UINT  img_width=pbmpinfo->bmiHeader.biWidth;
    UINT  img_heigth=pbmpinfo->bmiHeader.biHeight;
    LONG  Linebyte =( pbmpinfo->bmiHeader.biBitCount * img_width +31)/32*4;
    LONG  ImageSize=Linebyte * img_heigth;

    if (black_or_white==IMG_BLACK)
    {
        memset(pbmpdata,255,ImageSize);
    } 
    else
    {
        memset(pbmpdata,0,ImageSize);
    }   



    int code_num = code[2];
    ImgDot current_dot = {code[0],code[1]};
    int    temp;
    for (int i = 0 ;i < code_num ; i++)
    {
        if (black_or_white==IMG_BLACK)
        {
            ImgSetPixel(pbmpinfo,pbmpdata,current_dot,0);
           
            if (ImgGetPixel(pbmpinfo,pbmpdata,current_dot) != 0)
            {
                AfxMessageBox("!!");
                return FALSE;
               
            }
        } 
        else
        {
            ImgSetPixel(pbmpinfo,pbmpdata,current_dot,255);
           
            if (ImgGetPixel(pbmpinfo,pbmpdata,current_dot) != 255)
            {
                AfxMessageBox("!!");
                return FALSE;
               
     }
        }
      
         temp = code[i+3];
     current_dot.cx =  current_dot.cx + inc[temp][0];
     current_dot.cy =  current_dot.cy + inc[temp][1];
    }

    return  TRUE;

}





PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

tengjingshu_112148725 2009-3-10 09:03

学习了
相关推荐阅读
zhangshaobing517_935512703 2011-03-21 01:28
KC24RT-300调试笔记
项目中需要使用LED驱动器,主要是为了让一串LED发出的光照一致,所以在试验中采用LED串联的方式比较好点,LED并联容易导致LED发光的 不均匀以及寿命减少。我在项目中采用金升阳公司的KC24RT-...
zhangshaobing517_935512703 2010-11-19 14:53
线程中CreateEvent和SetEvent及WaitForSingleObj
首先介绍CreateEvent是创建windows事件的意思,作用主要用在判断线程退出,程锁定方面.CreateEvent 函功能描述:创建或打开一个命名的或无名的事件对象.EVENT有两种状态:发信...
zhangshaobing517_935512703 2010-11-15 13:29
VS2008 BEGIN
Visual Studio 2008环境与VC6.0的环境存在着比较大的区别,下面就一些小小的区别在这里做一些探讨,欢迎指教!1、如果是调试控制台程序,很多时候点击“启动调试”后是一闪而过,此时可有两...
zhangshaobing517_935512703 2010-11-01 20:38
使用MFC的数组类
 MFC的数组类支持的数组类似于C++中的常规数组,可以存放任何数据类型。C++的常规数组在使用前必须将其定义成能够容纳所有可能需要的元素,而MFC数组类创建的对象可以根据需要动态地增大或减小,数组的...
zhangshaobing517_935512703 2010-09-07 13:14
循环
 循环设计的注意的事情:(1)双重循环的跳出问题,break只挑出所在的循环,如果使用双层FOR循环,单个BREAK就不可能跳出所有的双层(2)在迭代的时候,注意起始和终止的条件,尤其是终止问题(3)...
zhangshaobing517_935512703 2010-09-02 01:09
图像处理改进
1.特征点提取的算法  标志点的提取算法对结果的影响虽然没有经过试验或者计算的推算,每1个pix的偏差对结果的影响有多大,但是不可避免的,要想获得高精度的  测量结果,高精度的提取对结果的影响还是很大...
EE直播间
更多
我要评论
1
9
关闭 站长推荐上一条 /3 下一条