canny算子的边缘提取算法

canny算子边缘提取分为四个步骤

1、去噪:

利用高斯滤波对图像卷积进行去噪处理;

2、求梯度:

采用梯度滤波模板对图像进行卷积,求取图像X方向和Y方向的梯度,以及对应的夹角;

3、非极大值抑制:

将各像素的梯度模值与梯度方向上相邻两个像素进行比较,保留梯度为极大值点的像素灰度;

算法设计

算法目标:完成像素梯度方向相邻两点的梯度比较。

方式:C点梯度一致,dTemp1和dTemp2梯度未知,采用相邻像素梯度,通过插值求得dTemp1和dTemp2的梯度,进行比较。

方法:根据C点的梯度角度确定相邻像素,通过相邻像素进行插值得到dTemp的梯度。

1、首先需要选取插值像素g1,g2,再选取插值比例K。

参数设定依据,尽量选择一致的不随条件改变的规则,简化算法。

2、插值比例K与C点斜率相关,tanU=dx/dy——K=短边/长边,tanU与K存在条件转换关系

插值比例与斜率的条件转换关系

1、以角度45°,90°,135°,180°作为边界判断条件。

<45°,tanU=dx/dy=K   

45°<U<90°,tanU=dx/dy=1/K   

90°<U<135°,tanU=dx/dy=-1/K   

135°<U<180°,tanU=dx/dy=-K   

2、以K=短边/长边

tanU=dx/dy

abs(dx)?abs(dy):比较大小

K=小/大

第二种方法不需要判断条件,这是取决于斜率=dx/dy;插值比例是短边占整边的比例(等价于占长边的比例)所以只需要在斜率中提取出短长边的比值信息即可。

3、插值规则:temp=g1*K+g2*(1-K),g1是对角像素,g2是轴向像素

插值像素选取依据:

g1是对角像素,g2是轴向像素,g1,g2的定义源于插值条件,但对角和轴向是相对于C点的抽象的概念,当C点的斜率不相同时,对角和轴向对应不同的坐标,计算机无法自动识别,所以需要将不同情况下的坐标赋值给g1,g2。

继承长短边的判断条件:

当dx是长边,代表斜率距x轴更近,当dx,dy同号在第一三象限,g1=C(x+1,y+1),g2=C(x+1,y),反之在二四象限g1=C(x-1,y-1),g2=C(x-1,y)

当dy是长边,代表斜率距y轴更近,当dx,dy同号在第一三象限,g1=C(x+1,y+1),g2=C(x,y+1),反之在二四象限g1=C(x-1,y-1),g2=C(x,y-1)

象限问题和网上搜的程序有出入,还望大佬们帮我指出问题。

canny算子及边缘提取原理_jiachen0212的博客-CSDN博客_canny算子阈值怎么取

边缘检测(Edge Detection)_长江之声的博客-CSDN博客_边缘测试

void NonMaxSuppress(int*pMag,int* pGradX,int*pGradY,SIZE sz,LPBYTE pNSRst)  
{  
    LONG x,y;  
    int nPos;  
    // the component of the gradient   
    int gx,gy;  
    // the temp varialbe   
    int g1,g2,g3,g4;  
    double weight;  
    double dTemp,dTemp1,dTemp2;  
    //设置图像边缘为不可能的分界点   
    for(x=0;x<sz.cx;x++)  
    {  
        pNSRst[x] = 0;  
        pNSRst[(sz.cy-1)*sz.cx+x] = 0;  
          
    }  
    for(y=0;y<sz.cy;y++)  
    {  
        pNSRst[y*sz.cx] = 0;  
        pNSRst[y*sz.cx + sz.cx-1] = 0;  
    }  
      
    for (y=1;y<sz.cy-1;y++)  
    {  
        for (x=1;x<sz.cx-1;x++)  
        {  
            nPos=y*sz.cx+x;  
            // if pMag[nPos]==0, then nPos is not the edge point   
            if (pMag[nPos]==0)  
            {  
                pNSRst[nPos]=0;  
            }  
            else  
            {  
                // the gradient of current point   
                dTemp=pMag[nPos];  
                // x,y 方向导数   
                gx=pGradX[nPos];  
                gy=pGradY[nPos];  
                //如果方向导数y分量比x分量大,说明导数方向趋向于y分量,即更贴近y轴   
                if (abs(gy)>abs(gx))  
                {  
                    // calculate the factor of interplation   
                    weight=fabs(gx)/fabs(gy);  
                    g2 = pMag[nPos-sz.cx];  // 确定g2出现在c(中心点)的上一行   
                    g4 = pMag[nPos+sz.cx];  // 确定g4出现在c(中心点)的下一行   
                     
                    //C 为当前像素,与g1-g4 的位置关系为:   
                    //g1 g2   
                    //   C   
                    //   g4 g3   
                    if(gx*gy>0) //如果x,y两个方向导数的符号相同  
                    {  
                        g1 = pMag[nPos-sz.cx-1];  
                        g3 = pMag[nPos+sz.cx+1];  
                    }   //对的,画个图可以很好的理解。 左上角为原点,x,y导数相同即导数线跨越2 4象限 如上图1                     
                    //如果x,y两个方向的方向导数方向相反   
                    //C是当前像素,与g1-g4的关系为:   
                    //    g2 g1   
                    //    C   
                    // g3 g4   
                    else  //左上角为原点,x,y导数相反即导数线跨越1 3象限  如上图2
 
                    {  
                        g1 = pMag[nPos-sz.cx+1];  
                        g3 = pMag[nPos+sz.cx-1];  
                    }  
                }  
                else  
                {  
                    //插值比例   
                    weight = fabs(gy)/fabs(gx);                   
                    g2 = pMag[nPos+1]; //后一列   
                    g4 = pMag[nPos-1];  // 前一列                 
                    //如果x,y两个方向的方向导数符号相同   
                    //当前像素C与 g1-g4的关系为   
                    // g3   
                    // g4 C g2   
                    //       g1   
                    if(gx * gy > 0)  
                    {  
                        g1 = pMag[nPos+sz.cx+1];  
                        g3 = pMag[nPos-sz.cx-1];  
                    }  
                      
                    //如果x,y两个方向导数的方向相反   
                    // C与g1-g4的关系为   
                    // g1   
                    // g4 C g2   
                    //      g3   
                    else  
                    {  
                        g1 = pMag[nPos-sz.cx+1];  
                        g3 = pMag[nPos+sz.cx-1];  
                    }  
                }  
                  
                dTemp1 = weight*g1 + (1-weight)*g2;  
                dTemp2 = weight*g3 + (1-weight)*g4;               
                //当前像素的梯度是局部的最大值   
                //该点可能是边界点   
                if(dTemp>=dTemp1 && dTemp>=dTemp2)  
                {  
                    pNSRst[nPos] = 128;  
                }  
                else  
                {  
                    //不可能是边界点   
                    pNSRst[nPos] = 0;  
                }             
            }  
        }  
    }  
}  

4、双阈值绘制边缘:

以高阈值提取出的边缘为主边缘,在边缘残缺部分补充与主边缘相连接的低阈值边缘,最终构成完整的边缘信息。

这个先挖坑,后边再补。

5、算法设计思路总结:

首先清楚算法的目标,以及想要实现的方式。

细化方法:

将方法中的每一个对象,进行具体定位;

考虑全所有的情况,进行对象在不同条件下的行为匹配;

将对象所要实施的行为进行细化拆解,转化为电脑可理解的,可实行的基础动作;

整合简化判断条件,变量规则一致化设置,起到简化算法的效果。

如果我的博文有帮到你,请点赞给我加油呀,也谢谢在解决问题过程中参考的诸位大佬们啦~

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值