原创 (原创)图像处理学习系列3:边缘检测之一阶微分算子

2009-3-13 20:41 5752 9 9 分类: 软件与OS
一阶微分算子首先出现就是Proberts算子,是一个2x2的算子,检测精度比后面的算子要高,但是和高斯算子一样具有对噪声敏感的特性,所以。。。。后来出现了Prewitt算子,这个算子是3x3的,但是对噪声也比较敏感。Sobel算子使用了3x3的模板,但是对中心点的权重增加所以对噪声具有一定的抵抗能力,可以很好的检测到边缘,所以现在使用的比较多。前面几种算子对都是提供2个或者4个模板来检测一个区域,取其中响应最大的那个方向来作为该点的输出。

一些资料l:
   边缘检测算子的分析比较.PDFPDF

一种ROBERTS自适应边缘检测方法.PDFPDF
 资料网上很多;
代码很长,打包了:https://static.assets-stash.eet-china.com/album/old-resources/2009/3/13/75f8b7b5-d4f4-4844-aa89-76bf46209b15.rar
/****************************************************************

利用算子进行边缘检测
EDGE_ROBERT   
     -1   |  0
  --------|-------
       0  |  1

      1   |  0
  --------|-------
       0  | -1
Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后结果边缘不是很平滑。
经分析,由于Robert算子通常会在图像边缘附近的区域内 产生较宽的响应,故采用上述算子检测的边缘图像
常需做细化处理,边缘定位的精度不是很高。
*****************************************************************/
BOOL ImgEdge_Robert(BITMAPINFO* pbmpinfo,BYTE* pbmpdata)
{
         
    LONG imagewidth=(int)pbmpinfo->bmiHeader.biWidth;
    LONG imageheigth=(int)pbmpinfo->bmiHeader.biHeight;
    //image size
    LONG  Linebyte =( pbmpinfo->bmiHeader.biBitCount * imagewidth +31)/32*4;
    LONG  ImageSize=Linebyte * imageheigth;
    //data is not null
    if (pbmpdata == NULL)
    {
        return FALSE;
    }
    //color must be gray
    if (pbmpinfo->bmiHeader.biBitCount != 8)
    {
            AfxMessageBox("只对灰度图像进行操作!");
        return FALSE;
    }

        //copy
    BYTE *pNewbmpdata=(BYTE*)malloc(ImageSize);
    if (pNewbmpdata == NULL)
    {
        return FALSE;
    }
   
    memcpy(pNewbmpdata,pbmpdata,ImageSize);
        //注意数组不要越界,不对右边和下边的数据进行处理
    LONG width=0,heigth=0;
    BYTE *psrc=NULL;
    BYTE *pdest=NULL;
    BYTE template_box[4]={0};
    BYTE result=0;
    for (heigth = 0; heigth < imageheigth -1 ; heigth++)
    {
        for (width=0; width < imagewidth-1; width++)
        {
            psrc  =  pbmpdata+ImageSize- Linebyte*heigth - Linebyte + width;
            pdest =  pNewbmpdata+ImageSize- Linebyte*heigth - Linebyte + width;

                        template_box[0]=  *psrc;
            template_box[1]=  *(psrc+1);
            template_box[2]=  *(psrc-Linebyte);
            template_box[3]=  *(psrc-Linebyte+1);


            result    =  2*(unsigned char)sqrt( (template_box[3]-template_box[0])*(template_box[3]-template_box[0])+\
                 (template_box[0]-template_box[3])*(template_box[0]-template_box[3]) );

                 //将2个模板的平方的和的sprt
            if (result>255)
            {
                result=255;
            }
            *pdest=result;        
                
        }
    }

    memcpy(pbmpdata,pNewbmpdata,ImageSize);
    free(pNewbmpdata);
    return TRUE;
 
}
/***********************************************************************
SOBLE算子
边沿检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是检测水平边沿的 ;另一个是检测垂直平边沿的 。与 和
相比,Sobel算子对于象素的位置的影响做了加权,因此效果更好。
Sobel算子另一种形式是各向同性Sobel(Isotropic Sobel)算子,也有两个,一个是检测水平边沿的 ,另一个是检测垂直平边沿的。
各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。由于建筑物图
像的特殊性,我们可以发现,处理该类型图像轮廓时,并不需要对梯度方向进行运算,
所以程序并没有给出各向同性Sobel算子的处理方法。
由于Sobel算子是滤波算子的形式,用于提取边缘,可以利用快速卷积函数,简单有效,因此应用广泛。美中不足的是,Sobel算子
并没有将图像的主体与背景严格地区分开来,换言之就是Sobel算子没有基于图像灰度进行处理,由于Sobel算子没有严格地模拟人
的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。
***********************************************************************/
BOOL ImgEdge_Soble(BITMAPINFO* pbmpinfo,BYTE* pbmpdata)
{
    LONG imagewidth=(int)pbmpinfo->bmiHeader.biWidth;
    LONG imageheigth=(int)pbmpinfo->bmiHeader.biHeight;
    //image size
    LONG  Linebyte =( pbmpinfo->bmiHeader.biBitCount * imagewidth +31)/32*4;
    LONG  ImageSize=Linebyte * imageheigth;
    //data is not null
    if (pbmpdata == NULL)
    {
        return FALSE;
    }
    //color must be gray
    if (pbmpinfo->bmiHeader.biBitCount != 8)
    {
        AfxMessageBox("只对灰度图像进行操作!");
        return FALSE;
    }
   
        //copy
    BYTE *pNewbmpdata=(BYTE*)malloc(ImageSize);
    if (pNewbmpdata == NULL)
    {
        return FALSE;
    }
   
    memcpy(pNewbmpdata,pbmpdata,ImageSize);
    //memset(pNewbmpdata,255,ImageSize);
        //注意数组不要越界,不对右边和下边的数据进行处理
    LONG width=0,heigth=0;
    BYTE *psrc=NULL;
    BYTE *pdest=NULL;
    int temp_horizon=0;
    int temp_vetical=0;
    int result=0;
    int temp[9]={0};
    int maxnum=0;
    for (heigth = 1; heigth < imageheigth -1 ; heigth++)
    {
        for (width=1; width < imagewidth-1; width++)
        {
            psrc  =  pbmpdata + ImageSize- Linebyte*heigth - Linebyte + width;
            pdest =  pNewbmpdata+ImageSize- Linebyte*heigth - Linebyte + width;
            //这里没有使用模板来做,减少寻址的次数
            temp_horizon = ( *(psrc-Linebyte+1) )-  ( *(psrc-Linebyte-1) ) +\
                       ( *(psrc+1) )*2 - ( *(psrc-1) )*2 +\
                       ( *(psrc+Linebyte+1) )-  ( *(psrc+Linebyte-1) );

                        temp_vetical = ( *(psrc - Linebyte-1) ) - ( *(psrc + Linebyte-1) )+\
                       ( *(psrc - Linebyte) ) *2 - ( *(psrc + Linebyte)) *2+\
                       ( *(psrc - Linebyte+1) ) - ( *(psrc + Linebyte+1) );
             
            result=(int)sqrt(temp_horizon*temp_horizon + temp_vetical*temp_vetical);

            if (result>255)
            {
                result=255;
            }

            *pdest= result;        
           
        }
    }
   
    memcpy(pbmpdata,pNewbmpdata,ImageSize);
    free(pNewbmpdata);
   return TRUE;
}
/*****************************************************************************
Sobel算子和Prewitt算子具有平滑作用,能滤除一些噪声,去掉部分伪边缘,但同时也平滑了真正的边缘;
定位精度不高
******************************************************************************/
BOOL ImgEdge_Prewitt(BITMAPINFO* pbmpinfo,BYTE* pbmpdata)
{
    LONG imagewidth=(int)pbmpinfo->bmiHeader.biWidth;
    LONG imageheigth=(int)pbmpinfo->bmiHeader.biHeight;
    //image size
    LONG  Linebyte =( pbmpinfo->bmiHeader.biBitCount * imagewidth +31)/32*4;
    LONG  ImageSize=Linebyte * imageheigth;
    //data is not null
    if (pbmpdata == NULL)
    {
        return FALSE;
    }
    //color must be gray
    if (pbmpinfo->bmiHeader.biBitCount != 8)
    {
        AfxMessageBox("只对灰度图像进行操作!");
        return FALSE;
    }
   
        //copy
    BYTE *pNewbmpdata=(BYTE*)malloc(ImageSize);
    if (pNewbmpdata == NULL)
    {
        return FALSE;
    }
   
    memcpy(pNewbmpdata,pbmpdata,ImageSize);
    //memset(pNewbmpdata,255,ImageSize);
        //注意数组不要越界,不对右边和下边的数据进行处理
    LONG width=0,heigth=0;
    BYTE *psrc=NULL;
    BYTE *pdest=NULL;
   
    //    BYTE template_box_vertical[9]={-1,-2,-1,0,0,0,1,2,1};
    //    BYTE template_box_horizon[9]={-1,0,1,-2,0,2,-1,0,1};
   
    //    unsigned char temp_horizon=0;
    //    unsigned char temp_vetical=0;
    int temp_horizon=0;
    int temp_vetical=0;
    int result=0;
    for (heigth = 1; heigth < imageheigth -1 ; heigth++)
    {
        for (width=1; width < imagewidth-1; width++)
        {
            psrc  =  pbmpdata + ImageSize- Linebyte*heigth - Linebyte + width;
            pdest =  pNewbmpdata+ImageSize- Linebyte*heigth - Linebyte + width;
            //这里没有使用模板来做,减少寻址的次数
            temp_horizon = ( *(psrc-Linebyte+1) )-  ( *(psrc-Linebyte-1) ) +\
                ( *(psrc+1) ) - ( *(psrc-1) ) +\
                ( *(psrc+Linebyte+1) )-  ( *(psrc+Linebyte-1) );
           
                        temp_vetical = ( *(psrc - Linebyte-1) ) - ( *(psrc + Linebyte-1) )+\
                ( *(psrc - Linebyte) )  - ( *(psrc + Linebyte)) +\
                ( *(psrc - Linebyte+1) ) - ( *(psrc + Linebyte+1) );
           
            result=(int)sqrt(temp_horizon*temp_horizon + temp_vetical*temp_vetical);
            //result=abs(temp_horizon) + abs(temp_vetical*temp_vetical);


            //将2个模板的平方的和的sprt
            if (result>255)
            {
                result=255;
            }

//可以对阈值进行处理
/*            if (result<50)
            {
                                result=0;
            }*/
            *pdest= result;        
           
        }
    }
   
    memcpy(pbmpdata,pNewbmpdata,ImageSize);
    free(pNewbmpdata);
    return TRUE;
}



 

 
  
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
9
关闭 站长推荐上一条 /1 下一条