最近老师布置了一个边缘检测的作业,我借此机会详细学习了一下canny算子,在此进行总结,并分别给出OpenCV代码和MATLAB代码,自己水平有限,若有错误或者更好的编程方法,请广大网友留言,一定虚心学习。好了废话少说,直接开始吧。
基本原理
- 须满足条件:抑制噪声;精确定位边缘。
- 从数学上表达了三个准则[信噪比准则(低错误率)、定位精度准则、单边缘响应准则],并寻找表达式的最佳解。
- 属于先平滑后求导的方法。
算法步骤
- 高斯平滑滤波(这个比较简单,后续介绍会省略)
- 计算图像梯度的幅值和方向
- 对幅值图像进行非极大值抑制
- 用双阈值算法检测和连接边缘
详细过程
1、高斯平滑滤波(略)
2、计算图像梯度的幅值和方向
可选用的模板:soble算子、Prewitt算子、一阶差分卷积模板等等;
在此选用Prewitt算子为例:
由此可算得x方向梯度幅值:
y方向梯度幅值:
进一步可以得到图像梯度的幅值和方向:
如下图表示了中心点的梯度向量、方位角以及边缘方向。(任一点的边缘与梯度向量正交)
3、对幅值图像进行非极大值抑制
首先将角度划分成四个方向范围 :水平(0°)、−45°、垂直(90°)、+45°。如下图:
注:在opencv中由于反三角函数 cv::fastAtan2()得到的角度是0~360°,故划分为:水平(0°)、45°、垂直(90°)、135°,原理同上。
下面看上述角度划分对应于3*3邻域的4种可能组合,如下图:
扇形区标号d1~d4,对应3*3领域的4种可能的组合,1-x-5 , 7-x-3 , 2-x-6 , 8-x-4。
在每一点上,领域中心 x 与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置0,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。
4、用双阈值算法检测和连接边缘
选取系数TH和TL,比率为2:1或3:1。(一般取TH=0.3或0.2,TL=0.1);
取出非极大值抑制后的图像中的最大梯度幅值,定义高低阈值。即:TH×Max,TL×Max (当然可以自己给定) ;
将小于低阈值的点抛弃,赋0;将大于高阈值的点立即标记(这些点就是边缘点),赋1;
将小于高阈值,大于低阈值的点使用8连通区域确定(即:只有与TH像素连接时才会被接受,成为边缘点,赋 1)。
算法实现
matlab代码
clc
clear all
img_in=imread('lenna.jpg');
img_in=rgb2gray(img_in);
figure,imshow(img_in);
title('原图');
[rows,cols]=size(img_in);
thresh=graythresh(img_in);
img_bw=im2bw(img_in,thresh);%二值图像
%%%%step1:高斯滤波
template=fspecial('gaussian',3,0.8);%生成一个3*3的高斯模板,标准差选0.8
img_filt=imfilter(img_bw,template);
%%%%step2:计算梯度(幅度和方向)
%Prewitt梯度模板
%也可选择一阶差分卷积模板:
%dx=[-1,-1;1,1] dy=[1,-1;1,-1]
%*********************
dx = [-1 -1 -1;0 0 0;1 1 1];%x方向的梯度模板
dy = [-1 0 1; -1 0 1;-1 0 1];%y方向的梯度模板
img_filt=double(img_filt);
grad_x=conv2(img_filt,dx,'same');%获取x方向的梯度图像.使用梯度模板进行二维卷积,结果与原图像大小相同
grad_y=conv2(img_filt,dy,'same');%获取y方向的梯度图像.使用梯度模板进行二维卷积,结果与原图像大小相同
grad=sqrt((grad_x.^2)+(grad_y.^2));%梯度幅值图像
figure,imshow(grad);
title('梯度幅值图');
grad_dir=atan2(grad_y,grad_x);%获取梯度方向弧度
grad_dir=grad_dir*180/pi;
%%%%step3:对梯度幅值进行非极大值抑制
%首先将角度划分成四个方向范围:水平(0°)、-45°、垂直(90°)、+45°
for i = 1:rows
for j = 1:cols
if((grad_dir(i,j)>=-22.5 && grad_dir(i,j)<=22.5) || (grad_dir(i,j)>=157.5 && grad_dir(i,j)<=180)...
||(grad_dir(i,j)<=-157.5 && grad_dir(i,j)>=-180) )
grad_dir(i,j) = 0;
elseif((grad_dir(i,j) >= 22.5) && (grad_dir(i,j) < 67.5) || (grad_dir(i,j) <= -112.5) && (grad_dir(i,j) > -157.5))
grad_dir(i,j) = -45;
elseif((grad_dir(i,j) >= 67.5) && (grad_dir(i,j) < 112.5) || (grad_dir(i,j) <= -67.5) && (grad_dir(i,j) >- 112.5))
grad_dir(i,j) = 90;
elseif((grad_dir(i,j) >= 112.5) && (grad_dir(i,j) < 157.5) || (grad_dir(i,j) <= -22.5) && (grad_dir(i,j) > -67.5))
grad_dir(i,j) = 45;
end
end
end
%讨论对3x3区域的四个基本边缘方向进行非极大值抑制.获取非极大值抑制图像
Nms = zeros(rows,cols);%定义一个非极大值抑制图像
for i = 2:rows-1
for j= 2:cols-1
if (grad_dir(i,j) == 90 && grad(i,j) == max([grad(i,j), grad(i,j+1), grad(i,j-1)]))
Nms(i,j) = grad(i,j);
elseif (grad_dir(i,j) == -45 && grad(i,j) == max([grad(i,j), grad(i+1,j-1), grad(i-1,j+1)]))
Nms(i,j) = grad(i,j);
elseif (grad_dir(i,j) == 0 && grad(i,j) == max([grad(i,j), grad(i+1,j), grad(i-1,j)]))
Nms(i,j) = grad(i,j);
elseif (grad_dir(i,j) == 45 && grad(i,j) == max([grad(i,j), grad(i+1,j+1), grad(i-1,j-1)]))
Nms(i,j) = grad(i,j);
end;
end;
end;
figure,imshow(Nms);
title('非极大值抑制图');
%%%%step4:双阈值检测和连接边缘
img_out=zeros(rows,cols);%定义一个双阈值图像
YH_L=0.1*max(max(Nms));%低阈值
YH_H=0.3*max(max(Nms));%高阈值
for i = 1:rows
for j = 1:cols
if(Nms(i,j)<YH_L)
img_out(i,j)=0;
elseif(Nms(i,j)>YH_H)
img_out(i,j)=1;
%对TL < Nms(i, j) < TH 使用8连通区域确定
elseif ( Nms(i+1,j) < YH_H || Nms(i-1,j) < YH_H || Nms(i,j+1) < YH_H || Nms(i,j-1) < YH_H ||...
Nms(i-1,j-1) < YH_H || Nms(i-1, j+1) < YH_H || Nms(i+1, j+1) < YH_H || Nms(i+1, j-1) < YH_H)
img_out(i,j) = 1;
end
end
end
bw=edge(img_bw,'canny');
figure,imshow(img_out);
title('本实验结果图');
figure,imshow(bw);
title('工具箱Canny算子效果图');
效果图
评论(0)
您还未登录,请登录后发表或查看评论