canny算子共分四步:高斯滤波-》求梯度-》非最大抑制-》用双阈值法检测和连接边缘。 canny四部曲将详细分析各个步骤,并且附上每个步骤的源码。 第一个步骤为高斯滤波。高斯函数的傅立叶变换也是高斯函数,高斯函数可看成一个低通滤波器,可以去除高斯噪声。对图像来说,常用二维零均值离散高斯函数作平滑滤波器,函数表达式如下: 式(1) 高斯函数具有可分离性,因此高斯滤波器可以有效实现。通过二维高斯函数的卷积可以分两步来进行,首先将图像与一维高斯函数进行卷积,然后将卷积的结果与方向垂直的相同一维高斯函数进行卷积。因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长。 高斯函数的可分离性很容易表示: 式(2) 式(3) 式(4) 于是在高斯滤波器的设计中,二维高斯函数的卷积运算可以通过使用单个一维高斯模板,对两次卷积之间的图像和最后卷积的结果图像进行转置来完成。 以下是产生一维高斯模板的函数: -
-
-
-
-
-
- void CreatGauss(double sigma, double **pdKernel, int *pnWidowSize)
- {
- LONG i;
-
- int nCenter;
- double dDis;
-
-
- double dValue;
- double dSum;
- dSum = 0;
-
- *pnWidowSize = 1+ 2*ceil(3*sigma);
-
- nCenter = (*pnWidowSize)/2;
-
- for(i=0;i<(*pnWidowSize);i++)
- {
- dDis = (double)(i - nCenter);
- dValue = exp(-(1/2)*dDis*dDis/(sigma*sigma))/(sqrt(2*3.1415926)*sigma);
- (*pdKernel)[i] = dValue;
- dSum+=dValue;
- }
-
- for(i=0;i<(*pnWidowSize);i++)
- {
- (*pdKernel)[i]/=dSum;
- }
- }
以下函数调用一阶函数模板,对原图想分水平垂直两次卷积实现高斯平滑: -
-
-
-
-
-
-
- void GaussianSmooth(SIZE sz, LPBYTE pGray, LPBYTE pResult, double sigma)
- {
- LONG x, y;
- LONG i;
-
- int nWindowSize;
-
- int nLen;
-
- double *pdKernel;
-
- double dDotMul;
-
- double dWeightSum;
-
- double *pdTemp;
-
- nWindowSize = 1+ 2*ceil(3*sigma);
-
-
- if ((pdTemp = (double *)malloc(sz.cx*sz.cy*sizeof(double)))==NULL)
- {
- printf("melloc memory for pdTemp failed!!");
- exit(0);
- }
- if ((pdKernel = (double *)malloc(nWindowSize*sizeof(double)))==NULL)
- {
- printf("malloc memory for pdKernel,failed!!");
- exit(0);
- }
-
-
- CreatGauss(sigma, &pdKernel, &nWindowSize);
-
- nLen = nWindowSize/2;
-
-
- for(y=0;y<sz.cy;y++)
- {
- for(x=0;x<sz.cx;x++)
- {
- dDotMul = 0;
- dWeightSum = 0;
- for(i=(-nLen);i<=nLen;i++)
- {
-
- if((i+x)>=0 && (i+x)<sz.cx)
- {
- dDotMul+=(double)(pGray[y*sz.cx+(i+x)] * pdKernel[nLen+i]);
- dWeightSum += pdKernel[nLen+i];
- }
- }
- pdTemp[y*sz.cx+x] = dDotMul/dWeightSum;
- }
- }
-
-
- for(x=0; x<sz.cx;x++)
- {
- for(y=0; y<sz.cy; y++)
- {
- dDotMul = 0;
- dWeightSum = 0;
- for(i=(-nLen);i<=nLen;i++)
- {
- if((i+y)>=0 && (i+y)< sz.cy)
- {
- dDotMul += (double)pdTemp[(y+i)*sz.cx+x]*pdKernel[nLen+i];
- dWeightSum += pdKernel[nLen+i];
- }
- }
- pResult[y*sz.cx+x] = (unsigned char)dDotMul/dWeightSum;
- }
- }
-
- free(pdTemp);
- free(pdKernel);
- }
以下是用到的一些type:
- typedef struct {
- int cy;
- int cx;
- } SIZE;
-
- typedef unsigned char *LPBYTE;
-
- typedef long LONG;
|