canny算法的理解

传统边缘检测方法的主要缺点:
1、没有很好的利用梯度方向
2、最后得到的二值图像,只是简单的利用单一阈值做处理
canny算法的优势:
1、基于边缘梯度方向的非极大值抑制
2、双阈值的滞后阈值处理
canny算法的主要步骤如下:
- 对输入图像进行高斯平滑,降低错误率(主要目的是降低噪声,剔除伪边缘)
- 计算梯度幅度和方向来估计每一点处的边缘强度与方向
- 幅度和角度的理论计算方法,梯度的具体计算在上一篇博客中已经讲过,这里就不做过多的解读
![]()
- 根据梯度方向,对梯度幅值进行非极大值抑制。本质上是对Sobel、Prewitt等算子结果的进一步细化
- 用双阈值处理和连接边缘
边缘抑制算法讲解:

核心代码如下:
/*
fucntion: non-maximum suppression
input:
pMag: pointer to Magnitude,
pGradX: gradient of x-direction
pGradY: gradient of y-direction
sz: size of pMag (width = size.cx, height = size.cy)
output:
pNSRst: result of non-maximum suppression
*/
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分量
if (abs(gy)>abs(gx))
{
// calculate the factor of interplation
weight=fabs(gx)/fabs(gy);
g2 = pMag[nPos-sz.cx]; // 上一行
g4 = pMag[nPos+sz.cx]; // 下一行
//如果x,y两个方向导数的符号相同
//C 为当前像素,与g1-g4 的位置关系为:
//g1 g2
// C
// g4 g3
if(gx*gy>0)
{
g1 = pMag[nPos-sz.cx-1];
g3 = pMag[nPos+sz.cx+1];
}
//如果x,y两个方向的方向导数方向相反
//C是当前像素,与g1-g4的关系为:
// g2 g1
// C
// g3 g4
else
{
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;
}
}
}
}
}


浙公网安备 33010602011771号