高斯滤波核函数满足如下分布:
一维核函数:
二维核函数:
通过核函数可以计算K*K的高斯平滑模板:(貌似opencv 和matlab 中都有封装好的函数)
sigma需要自己设定,根据生成的模板大小,x和y表示当前元素距模板中心的距离。可以由opencv直接调用求模板,也可以分别通过一维/二维自己代码求模板。【注意,一维滤波的时候需要对x和y方向分别滤波】
//通用变量定义 double nSigma = 0.4; //定义高斯函数的标准差 int nWidowSize = 1+2*ceil(3*nSigma); //定义滤波窗口的大小 int nCenter = (nWidowSize)/2; //定义滤波窗口中心的索引 double nSigma = 0.4; //定义高斯函数的标准差 int nWidowSize = 1+2*ceil(3*nSigma); //定义滤波窗口的大小 int nCenter = (nWidowSize)/2; //定义滤波窗口中心的索引
//////////////////////生成一维高斯滤波系数,高斯模板也可以是非对称的///////////////////////////// double* pdKernal_1 = new double[nWidowSize]; //定义一维高斯核数组 double dSum_1 = 0.0; //求和,用于进行归一化 ////////////////////////一维高斯函数公式////////////////////////////// //// x*x ///////////////// //// -1*---------------- ///////////////// //// 1 2*Sigma*Sigma ///////////////// //// ------------ e ///////////////// //// ///////////////// //// /2*pi*Sigma ///////////////// ////////////////////////////////////////////////////////////////////// for(int i=0; i<nWidowSize; i++) { double nDis = (double)(i-nCenter); pdKernal_1[i] = exp(-(0.5)*nDis*nDis/(nSigma*nSigma))/(sqrt(2*3.14159)*nSigma); dSum_1 += pdKernal_1[i]; } for(i=0; i<nWidowSize; i++) { pdKernal_1[i] /= dSum_1; //进行归一化 }
//////////////////////生成二维高斯滤波系数////////////////////////////////// double* pdKernal_2 = new double[nWidowSize*nWidowSize]; //定义一维高斯核数组 double dSum_2 = 0.0; //求和,进行归一化 ///////////////////////二维高斯函数公式//////////////////////////////////// //// x*x+y*y /////////////// //// -1*-------------- /////////////// //// 1 2*Sigma*Sigma /////////////// //// ---------------- e /////////////// //// 2*pi*Sigma*Sigma /////////////// /////////////////////////////////////////////////////////////////////////// for(i=0; i<nWidowSize; i++) { for(int j=0; j<nWidowSize; j++) { int nDis_x = i-nCenter; int nDis_y = j-nCenter; pdKernal_2[i+j*nWidowSize]=exp(-(1/2)*(nDis_x*nDis_x+nDis_y*nDis_y) /(nSigma*nSigma))/(2*3.1415926*nSigma*nSigma); dSum_2 += pdKernal_2[i+j*nWidowSize]; } } for(i=0; i<nWidowSize; i++) { for(int j=0; j<nWidowSize; j++) //进行归一化 { pdKernal_2[i+j*nWidowSize] /= dSum_2; } }
========================================================
高斯平滑:
//一维核函数生成的模板平滑 for(i=0; i<nHeight; i++) //进行x向的高斯滤波(加权平均) { for(j=0; j<nWidth; j++) { double dSum = 0; double dFilter=0; //滤波中间值 for(int nLimit=(-nCenter); nLimit<=nCenter; nLimit++) { if((j+nLimit)>=0 && (j+nLimit) < nWidth ) //图像不能超出边界 { dFilter += (double)nImageData[i*nWidth+j+nLimit] * pdKernal_1[nCenter+nLimit]; dSum += pdKernal_1[nCenter+nLimit]; } } nData[i*nWidth+j] = dFilter/dSum; } } for(i=0; i<nWidth; i++) //进行y向的高斯滤波(加权平均) { for(j=0; j<nHeight; j++) { double dSum = 0.0; double dFilter=0; for(int nLimit=(-nCenter); nLimit<=nCenter; nLimit++) { if((j+nLimit)>=0 && (j+nLimit) < nHeight) //图像不能超出边界 { dFilter += (double)nData[(j+nLimit)*nWidth+i] * pdKernal_1[nCenter+nLimit]; dSum += pdKernal_1[nCenter+nLimit]; } } pCanny[j*nWidth+i] = (unsigned char)(int)dFilter/dSum; } }
//二维核函数平滑 int x; int y; for(i=0; i<nHeight; i++) { for(j=0; j<nWidth; j++) { double dFilter=0.0; double dSum = 0.0; for(x=(-nCenter); x<=nCenter; x++) //行 { for(y=(-nCenter); y<=nCenter; y++) //列 { if( (j+x)>=0 && (j+x)<nWidth && (i+y)>=0 && (i+y)<nHeight) //判断边缘 { dFilter += (double)nImageData [(i+y)*nWidth + (j+x)] * pdKernal_2[(y+nCenter)*nWidowSize+(x+nCenter)]; dSum += pdKernal_2[(y+nCenter)*nWidowSize+(x+nCenter)]; } } } pCanny[i*nWidth+j] = (unsigned char)dFilter/dSum; } }
在选择Sigma时要注意,如果选的过大,那么会加深滤波程度,这样会导致图像边缘模糊,不利于下一步的边缘检测,如果过小,则滤波效果不佳,
参考:
http://blog.csdn.net/likezhaobin/article/details/6892176(整个canny总览)
http://blog.csdn.net/likezhaobin/article/details/6892629(整个canny算法步骤的细致讲解+代码)
http://blog.csdn.net/xiaojiegege123456/article/details/7714897
http://blog.csdn.net/likezhaobin/article/details/6835049(对opencv参数和sigma的讲解)