canny主要工作:推导了最优边缘检测算子。
图像的边缘检测是:图像最基本特征,边缘点指的是图像中周围像素灰度有阶跃变化或屋顶变化的那些像素点,即:灰度值导数极大的地方。
边缘检测的目的是:标识数字图像中亮度变化的明显的点。之前介绍过增强边缘的图像锐化的方法,本节文章主要介绍一种专门用于边缘检测的canny算子。
PPT下载:/download/weixin_42346564/10846987
本节的重点是分割方法,是基于检测急剧的,局部的强度变化。我们感兴趣的三种图像特征是孤立的点、线和边缘。
边缘像素是图像强度突然变化的像素,边缘(或边缘段)是一组连通的边缘像素;
线可以被看作是(通常)较细的边缘段,其中线两侧背景的强度要么比线像素的强度高得多,要么比线像素的强度低得多。线条产生了所谓的“屋顶边缘”。最后,一个孤立的点可以看作是被背景(前景)像素包围的前景(背景)像素。局部平均平滑图像。考虑到平均值类似于积分,很明显,利用导数可以检测到强度的突变和局部变化。由于很快就会证明的原因,一阶和二阶导数特别适合于这个目的。数字函数的导数是用有限差分定义的。有很多种方法来计算这些差异,但是。正如3.6节所解释的
我们要求:
(1)一阶导数的任何近似在等强度区域必须为零
(2)在强度阶跃或斜坡开始时必须非零;
(3)在强度斜坡上的点必须非零。
Canny边缘检测基本特征如下:
须满足条件:①抑制噪声;②精确定位边缘。l边缘检测算子应满足以下3个判断准则:
从数学上表达了三个准则[信噪比准则(低错误率)、定位精度准则、单边缘响应准则],并寻找表达式的最佳解。
(1)信噪比准则SRN(低误判率),即尽可能少地把边缘点误认为是非边缘点,目的是找出H(x,y);SNR越大,误判率越低。
(2)定位精确度准则,即准确地把边缘点定位在灰度变化最大的像素上;
(3)单边缘响应准则,抑制虚假边缘。
Canny边缘检测算法步骤:
步骤1:用高斯滤波器平滑处理原图像;
步骤2:用一阶偏导的有限差分进行计算梯度的幅值和方向;
步骤3:对梯度幅值进行非极大值抑制;
步骤4:用双阈值算法检测和连接边缘。
步骤详解
先看一下Canny算子的效果:
步骤1:用高斯滤波器平滑处理原图像
令f(x,y)表示数据(输入源数据),G(x,y)表示二维高斯函数(卷积操作数),fs(x,y)f(x,y)表示数据(输入源数据),G(x,y)表示二维高斯函数(卷积操作数),fs(x,y)为卷积平滑后的图像。
实现步骤有四个子过程:
第一步首先用二维高斯函数的一阶导数对图像进行平滑,对原图像进行高斯平滑处理,得到处理后的图像如下:
对原图像f(x,y) 进行高斯平滑处理,得到处理后的图像g(x,y) 如下:
使用平滑滤波的原因从根本上来说是边缘检测算子中的导数计算。导数计算对噪声十分敏感,如果不提前使用滤波器加以改善,则在导数计算后,噪声将会被放大,使得检测出来的虚假边缘变多,不利于边缘的提取。
平滑滤波和边缘检测是一对矛盾的概念。一方面,平滑滤波能够有效的抑制噪声,而在此过程中会使得图像边缘模糊,增加了边缘定位的不确定性。另一方面,平滑滤波能够除去对边缘检测中导数运算敏感的噪声,有效的抑制了虚假边缘的产生。实际工程经验表明,高斯滤波器可以在抗噪声干扰和边缘检测精确定位之间提供一个较好的折中方案。
步骤2:用一阶偏导的有限差分进行计算梯度的幅值和方向;
第二步用2×2 邻域一阶偏导的有限方差来计算平滑后的数据阵列I(x,y) 的梯度幅值和梯度方向
注:其中,I是图像像素的值(亮度值),(i,j)为像素的坐标。梯度是方向导数分别在x,y轴的投影(dx(i,j),dy(i,j)).梯度的模就是方向导数的值,用勾股定理求得。已知x,y方向上的偏导, 再通过反正切, 就可以求出具体的角度(与x轴的夹角), 即梯度的方向.
补充:求变化率时,对于一元函数,即求导;对于二元函数,求偏导。
数字图像处理中,用一阶有限差分近似求取灰度值的梯度值(变化率)。
(即:使差商(Δf/Δx)近似取代微商(∂f/∂x)。求灰度的变化率,分别取x和y方向上相邻像素做差,代替求取x和y(Δf/Δx)近似取代微商(∂f/∂x)。求灰度的变化率,分别取x和y方向上相邻像素做差,代替求取x和y方向一阶偏导)
例:计算一点x方向和yx方向和y方向的梯度幅值和方向;
上图中显示一段直的边缘线段放大后一部分,每个方块代表一个像素点,用一个方框强调点处边缘的幅值和方向。令灰色像素值为0,白色像素值为1。
根据x方向和y方向的卷积模板,可知,在3×3邻域中从底部一行像素值减去顶部一行的像素,得到x方向的偏导数(梯度);同样,从右边一列像素值减去左边一列的像素,得到y方向的偏导数。
x方向的梯度:gx=∂f/∂x=(0−0)+(0−1)+(0−1)=−2
y方向的梯度:gy=∂f/∂x=(1−0)+(1−0)+(0−0)= 2
由此,可以得到该点梯度的幅值和方向:
图像的边缘有方向和幅度两个属性,沿边缘方向像素变化平缓,垂直于边缘方向像素变化剧烈,边缘上的这种变化可以用微分算子检测出来,通常用一阶或二阶导数来检测边缘.
一阶导数可以用于检测图像中的一个点是否是边缘点(也就是判断一个点是否在斜坡上)。同样,二阶导数的符号可以用于判断一个边缘像素是否在亮的一边还是暗的一边。
用一阶偏导的有限差分来计算梯度的幅值和方向。
for y = 1:(Ay-1)for x = 1:(Ax-1)gx = src(y, x) + src(y+1, x) - src(y, x+1) - src(y+1, x+1);gy = -src(y, x) + src(y+1, x) - src(y, x+1) + src(y+1, x+1);m(y,x) = (gx^2+gy^2)^0.5 ;%--------------------------------theta(y,x) = atand(gx/gy) ;tem = theta(y,x);%--------------------------------if (tem<67.5)&&(tem>22.5)sector(y,x) = 0; elseif (tem<22.5)&&(tem>-22.5)sector(y,x) = 3; elseif (tem<-22.5)&&(tem>-67.5)sector(y,x) = 2; elsesector(y,x) = 1; end%-------------------------------- end end
其中,直角坐标系中坐标与幅值和方位角之间得关系如公式:其中,M(x,y)代表幅值,反映了图像的边缘强度;θ(x,y)代表方位角反映了梯度方向。当M(x,y)取得局部最大值时,其对应的梯度方向θ(x,y)反映了边缘方向(边缘方向与梯度方向垂直)。
步骤3:对梯度幅值进行非极大值抑制;
第三步,为了精确定位边缘,必须细化梯度幅值图像M(i, j) 中的屋脊带,只保留幅值局部变化最大的点,这一过程称为非极大值抑制,在每一点上,领域中心 x 与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置0,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。
仅仅得到全局的梯度并不足以确定边缘。因此,为了确定边缘,必须保留局部梯度最大的点,而且要抑制非极大值(NMS)。
图像梯度幅值矩阵中的元素值越大,说明图像中该点的梯度值越大,单着并不是能够说明该点就是边缘(这仅仅是属于图像增强的过程)。在canny算法中,非极大值抑制,是进行边缘检测的重要步骤,通俗意义上是指寻找像素点局部最大值,将非极大值点所对应的灰度值为0,这样可以剔除掉一大部分的非边缘的点。
解决这个问题的方法就需要利用梯度的方向,与邻域像素的梯度幅值进行比较,从而抑制非极大值。
判断像素点为中心分成四个扇区,代表梯度方向近似的四个可能角度(0°, 45°, 90°,135°),将梯度角离散为圆周的四个扇区之一,以便使用3x3的窗口做抑制运算。四个扇区的标号从0-3,对应于3x3的8邻域空间四种可能组合。
对每一个像素点的梯度进行非极大值抑制,首先将判断像素梯度值M(x,y)与沿着梯度方向的2个8邻域像素的梯度M(x±1,y±1)进行比较。如果该像素点位置的梯度幅值没有沿着梯度方向的两个相邻像素的梯度值大,则说明该点的梯度值不是局部最大值需被抑制,令M(x,y)=0,即该点不是边缘点。用此方法进行抑制全局梯度值中的非极大值。
这一步骤将会排除非边缘的像素,仅仅保留一些细的线条,即就是候选的边缘。
%matlab%-------------------------%非极大值抑制%------> x% 2 1 0% 3 X 3%y 0 1 2for y = 2:(Ay-1)for x = 2:(Ax-1) if 0 == sector(y,x) %右上 - 左下if ( m(y,x)>m(y-1,x+1) )&&( m(y,x)>m(y+1,x-1) )canny1(y,x) = m(y,x);elsecanny1(y,x) = 0;endelseif 1 == sector(y,x) %竖直方向if ( m(y,x)>m(y-1,x) )&&( m(y,x)>m(y+1,x) )canny1(y,x) = m(y,x);elsecanny1(y,x) = 0;endelseif 2 == sector(y,x) %左上 - 右下if ( m(y,x)>m(y-1,x-1) )&&( m(y,x)>m(y+1,x+1) )canny1(y,x) = m(y,x);elsecanny1(y,x) = 0;endelseif 3 == sector(y,x) %横方向if ( m(y,x)>m(y,x+1) )&&( m(y,x)>m(y,x-1) )canny1(y,x) = m(y,x);elsecanny1(y,x) = 0;endend end%end for xend%end for y
步骤4:用双阈值算法检测和连接边缘。
最后在第四步,对经过非极大值抑制的数据阵列N(i, j) 分别使用高、低2 个阈值τh 和τl分割图像,得到两个阈值边缘图像。
–阈值τ太低和阴影à假边缘;
–阈值τ取得太高à部分轮廊丢失.
–选用两个阈值: 更有效的阈值方案.
•具体做法:
n 1 取高低两个阈值作用在幅值图;
n 2 得到两个边缘图,高阈值和低阈值边缘图;
n 3 连接高阈值边缘图,出现断点时,在低阈值边缘图中的8邻点域搜寻边缘点。
n 4 取阈值,检测边缘,将低于阈值的所有值赋零值,得到图像的边缘阵列.
对非极大值抑制之后的图像与高阈值和低阈值进行判断,根据判断的情况分为以下三种情况:
如果某一像素位置的梯度幅值超过高阈值,则该像素被保留为边缘像素;如果某一像素位置的梯度幅值小于低阈值,则该像素被排除;如果某一像素位置的梯度幅值介于高、低阈值之间,则判断该像素8邻域空间的像素是否存在高于高阈值的像素。如果存在,则该像素将被保留。
%matlab%---------------------------------%双阈值检测ratio = 2;for y = 2:(Ay-1)for x = 2:(Ax-1) if canny1(y,x)<lowTh %低阈值处理canny2(y,x) = 0;bin(y,x) = 0;continue;elseif canny1(y,x)>ratio*lowTh %高阈值处理canny2(y,x) = canny1(y,x);bin(y,x) = 1;continue;else %介于之间的看其8邻域有没有高于高阈值的,有则可以为边缘tem =[canny1(y-1,x-1), canny1(y-1,x), canny1(y-1,x+1);canny1(y,x-1), canny1(y,x), canny1(y,x+1);canny1(y+1,x-1), canny1(y+1,x), canny1(y+1,x+1)];temMax = max(tem);if temMax(1) > ratio*lowThcanny2(y,x) = temMax(1);bin(y,x) = 1;continue;elsecanny2(y,x) = 0;bin(y,x) = 0;continue;endendend%end for xend%end for y
选取高阈值TH和低阈值TL,比率为2:1或3:1。(一般取TH=0.3/0.2,TL=0.1TH和低阈值TL,比率为2:1或3:1。(一般取TH=0.3/0.2,TL=0.1)取出非极大值抑制后的图像中的最大梯度幅值,重新定义高低阈值。即:TH×Max,TL×MaxTH×Max,TL×Max。(当然可以自己给定)将小于TL的点抛弃,赋0;将大于TH的点立即标记(这些点就是边缘点),赋1。将小于TL的点抛弃,赋0;将大于TH的点立即标记(这些点就是边缘点),赋1。将大于TL,小于TH的点使用8连通区域确定(即:只有与TH像素连接时才会被接受,成为边缘点,赋1)将大于TL,小于TH的点使用8连通区域确定(即:只有与TH像素连接时才会被接受,成为边缘点,赋1)。
注意:双阈值做法是将候选像素点拼接成轮廓,轮廓的形成时对这些像素运用滞后性阈值。
Eg:示例
Canny算子的检测比较优越,可以减少小模板检测中边缘中断,有利于得到较完整的边缘。
MATLAB程序:
I = imread(‘1.jpg');
imshow(I);
BW5 =edge(I,‘ canny’);
figure,imshow(BW5,[]);
咦,为什么canny会产生双边缘的结果呢,
我们来看一下 BW5 =edge(I,‘ canny’); 的edge的这个function的解释:
不难看出,因为阈值的不同,所产生的边缘检测的结果也略有差异,则thresh阈值设置需要手动修改一下,
最后的最后,如果您觉得此篇文章对您有帮助,扫码支持或点个赞呗,家里的喵儿想吃小鱼干了~
如果觉得《算法应用三:【图像分割】+【边缘检测】canny边缘检测--冈萨雷斯--《数字图像处理》》对你有帮助,请点赞、收藏,并留下你的观点哦!