canny算法的理解

传统边缘检测方法的主要缺点:

      1、没有很好的利用梯度方向

      2、最后得到的二值图像,只是简单的利用单一阈值做处理

canny算法的优势:

      1、基于边缘梯度方向的非极大值抑制

      2、双阈值的滞后阈值处理

canny算法的主要步骤如下:

  1. 对输入图像进行高斯平滑,降低错误率(主要目的是降低噪声,剔除伪边缘)
  2. 计算梯度幅度和方向来估计每一点处的边缘强度与方向
  3. 幅度和角度的理论计算方法,梯度的具体计算在上一篇博客中已经讲过,这里就不做过多的解读
  4. 根据梯度方向,对梯度幅值进行非极大值抑制。本质上是对Sobel、Prewitt等算子结果的进一步细化
  5. 用双阈值处理和连接边缘

         边缘抑制算法讲解:

         

 

    核心代码如下:

/*
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;
				}			
			}
		}
	}
} 
posted @ 2021-08-24 12:08  vegetable_chick  阅读(446)  评论(0编辑  收藏  举报