Canny边缘检测算法的步骤:
1 用高斯滤波器平滑滤波;
2 用一阶偏导的有限差分来计算图片的梯度的幅值与方向;
3 对梯度幅值进行非极大值检测(目的是细化边缘);
4 通过双阈值算法对进行边缘连接。
第一步:高斯滤波
高斯函数如下公式所示:
它的图像是这样的:
高斯滤波,其实就是将图片与一个高斯模块求卷积。根据高斯函数的特性,大于3×σ的部分,可以不考虑,所以一般而言,这个模板就是(6×σ+1)行,(6×σ+1)列的一个二维矩阵。如下图所示:
注意,这一步的生成的数据可能没有归一化,最好归一化。
接下来将得到的高斯矩阵与图片卷积就可以啦。其中σ越大,滤波后的图片的平滑性就越好,同时图片也越模糊。
下面举个例子,这是原图:
当σ=1时的滤波后的图片如下:
当σ=5时的图片为:
尺度越大,滤波效果也越好,但同时图片本身的高频分量也会被滤掉。
第二步:通过求差分求解梯度的方向与幅值
差分算子有很多,可以是sobel算子,robert算子,LOG算子等,我用的是canny算子,如下所示:
A=-1/2*[-1 1;-1 1];
B=-1/2*[1 1;-1 -1];
求解X与Y方向的差分公式为:
f'x=1/2*( f(x+1,y)-f(x,y) + f(x+1,y+1)-f(x,y+1) );
f'y=1/2*( f(x,y+1)-f(x,y) + f(x+1,y+1)-f(x+1,y) );
求差分可以通过求卷积得到,如下公式:
pic_x=conv2(double(pic),A);
pic_y=conv2(double(pic),B);
然后再通过下面的公式求梯度的方向与幅值。
gradamp=sqrt(double(pic_x.^2)+double(pic_y.^2));
gradori=atan(double(pic_y)./double(pic_x));
第三步:非极大值抑制
将0-360分成8个区间,分别是0-45,45-90,90-135,135-180及与他们相对的区间。
以0-45为例分析:
C到T1的方向是C点梯度的方向,非极大值抑制就是指,如果C点的值比它梯度方向的点的值要小,那么这个点就会被抑制。而它的梯度方向不一会正好有像素,所以要对之进行插值。经过非极值点抑制后的图像如下:
第四步:双阈值算法
这一步的原理是这样的,要选择两个阈值,第一个阈值比较大,梯度图中,大于它的点都是真边缘点。第二个阈值比较小,大于第二个阈值,但小于第一个阈值的点是假边缘点。如果一个真边缘点周围的点有假边缘点,那么这个假边缘点也会变成真边缘点。经过双阈值算法,图像如下:
上图是我的程序实现的,与MATLAB中给出的效果还有差距。下面的matlab中的canny函数滤波效果
关于算法的问题与改进,希望能与大家交流交流。欢迎拍砖。