Canny图像边缘检测
实验目的
- 了解并掌握使用微分算子进行图像边缘检测的基本原理;
- 了解Canny边缘检测原理与实现,进一步理解图像锐化的实质。
实验设备
PC机、matlab2018b
实验原理
图像边缘信息主要集中在高频段,通常说图像锐化或检测边缘,实质就是高频滤波。我们知道微分运算是求信号的变化率,具有加强高频分量的作用。在空域运算中来说,对图像的锐化就是计算微分。由于数字图像的离散信号,微分运算就变成计算差分或梯度。图像处理中有多种边缘检测(梯度)算子,常用的包括普通一阶差分,Robert算子(交叉差分),Sobel算子等等,是基于寻找梯度强度。拉普拉斯算子(二阶差分)是基于过零点检测。通过计算梯度,设置阀值,得到边缘图像。
Canny边缘检测算子是一种多级检测算法。1986年由John F. Canny提出,同时提出了边缘检测的三大准则:
低错误率的边缘检测:检测算法应该精确地找到图像中的尽可能多的边缘,尽可能的减少漏检和误检。
最优定位:检测的边缘点应该精确地定位于边缘的中心。
图像中的任意边缘应该只被标记一次,同时图像噪声不应产生伪边缘。
进而,Canny的工作本质是,从数学上表达前面的三个准则。因此Canny的步骤如下:
对输入图像进行高斯平滑,降低错误率。
计算梯度幅度和方向来估计每一点处的边缘强度与方向。
根据梯度方向,对梯度幅值进行非极大值抑制。本质上是对Sobel、Prewitt等算子结果的进一步细化。
用双阈值处理和连接边缘。
问题描述
编程实现Canny图像边缘检测方法,对不同参数进行验证。
1.对灰度图像,–实现Canny的计算过程,(matlab, python, opencv)
2.Canny里面有大小2个阈值,分析这两个值对结果的影响。
计算方法
选用图片如下图所示:
高斯滤波器平滑
(1)读取实验用图像记为img:使用imread函数将图像读入Matlab;
(2)将图像转为double类型;
(3)如果图像是彩色图像,转为灰度图像;
(4)获取输入图像的行和列;
(5)计算图像中每一个点距频率矩形中心的距离矩阵;
(6)在本次实验中直接使用Matlab内置函数imfilter()进行高斯滤波如下图所示,记图像为img1:
计算图像梯度
(1)定义检测竖直边缘模板[-1,0,1;-2,0,2;-1,0,1]和检测水平边缘模板[-1,-2,-1;
0,0,0;1,2,1]对图像进行遍历得到竖直方向梯度矩阵Gy和水平方向梯度矩阵Gx;
(2)使用公式得到图像幅值矩阵Gmag,如下图所示;
(3)使用公式2得到梯度方向矩阵,因为arctanx函数的值域为 [ − π / 2 , π / 2 ] [-\pi / 2, \pi/ 2] [−π/2,π/2],将其按照如下关系映射到 [ 0 , 2 π ] [0, 2 \pi] [0,2π],得到的结果单位为弧度制;
G
x
>
0
,
G
y
>
0
,
θ
不
变
G_{x} > 0 , G_{y} > 0, \theta 不变
Gx>0,Gy>0,θ不变
G
x
<
0
,
G
y
>
0
,
θ
+
π
G_{x} < 0 , G_{y} > 0, \theta + \pi
Gx<0,Gy>0,θ+π
G
x
<
0
,
G
y
<
0
,
θ
+
π
G_{x} < 0 , G_{y} < 0, \theta + \pi
Gx<0,Gy<0,θ+π
G
x
>
0
,
G
y
<
0
,
θ
+
2
π
G_{x} > 0 , G_{y} < 0, \theta + 2\pi
Gx>0,Gy<0,θ+2π
梯度非极大值抑制
(1)初始化N(x, y)=Gmag(x, y);
(2)对于每个点,在梯度方向和反梯度方向各找n个像素点。
若Gmag(x, y)不是这些点中的最大点,则将N(x, y)置零,否则保持N(x, y)不变;
(3)为简单起见,我们使用梯度可能的四个方向[0,45,90,135],当梯度方向不在该四个方向上时,使用的方向取梯度方向最接近的方向,如下图所示
(4)我们使用3*3的区域,若在梯度方向上的三个点的最大值为中心点,则保留该点,否则,置0,结果Gmag1如下图所示:
双阈值提取边缘点图像
(1)选择低阈值ThresholdLow = 0.1 * max(max(Gmag1)),高阈值ThresholdHigh = 0.12* max(max(Gmag1));
(2)对Gmag1中的点,若大于ThresholdHigh,将该值置为1,若小于ThresholdLow,将该值置为0,若大于ThresholdLow并且小于ThresholdHigh,进行步骤3;
(3)对于该点的8连通区域,若该区域存在大于ThresholdHigh的点,该点置为1;
(4)进行如上处理得到的结果Gmag2如下图所示;
使用Matlab内置函数对图像进行Canny边缘检测如下图所示:
(5)选择低阈值ThresholdLow = 0.01 * max(max(Gmag1)),高阈值ThresholdHigh = 0.05* max(max(Gmag1)),得到图像如下图所示:
(6)选择低阈值ThresholdLow = 0.2 * max(max(Gmag1)),高阈值ThresholdHigh = 0.22* max(max(Gmag1)),得到图像如下图所示:
结果分析
使用小的阈值,保留的像素值过多,将得到大量的边缘点,出现大量的错误检测如图4-8。
使用大的阈值,保留的像素值不足,得到少量的边缘点,出现许多空隙如图4-9。
实验代码
function [img_0,Gmag,Gmag1,Gmag2] = ex4_MyCanny_2(img)
% Canny图像边缘检测
% img:待检测图像
% img_0:高斯滤波后图像,Gmag:图像梯度幅值图像,Gmag1:非极大值抑制抑制后图像,Gmag2:双阈值提取边缘点图像
% 转为灰度图像
img = rgb2gray(img);
% 高斯滤波器平滑
W = fspecial('gaussian',[5,5],1);
img_0 = imfilter(img, W, 'replicate');
% 梯度幅值和梯度方向计算
[Gmag,Gdir] = ex4_MyImgradient_1(img_0);
% 非极大值抑制
Gmag1 = ex4_MyNMS_2(Gmag,Gdir);
% figure,imshow(Gmag1),title("非极大值抑制");
% 双阈值提取边缘点
Gmag2 = ex4_MyDoubleThreshold(Gmag1);
function [grad,theta] = ex4_MyImgradient_1(img)
% grad:图像梯度,theta:图像梯度方向
% img:待处理图像
% img = rgb2gray(img);
% 获取图像大小
[m,n]=size(img);
% % 检测竖直边缘模板
template_col = [-1,0,1;-2,0,2;-1,0,1];
% 检测水平边缘模板
template_row = [-1,-2,-1;0,0,0;1,2,1];
% 利用自定义均值滤波函数进行计算
grad_col_double = ex4_MyFilter_1(img,template_col,1);
grad_row_double = ex4_MyFilter_1(img,template_row,1);
% 梯度幅值
grad = (grad_col_double .^2 + grad_row_double .^2) .^(0.5);
% 梯度方向
theta = atan(grad_col_double ./ grad_row_double);
for i = 1:m
for j = 1:n
if grad_row_double(i,j) == 0 && grad_col_double(i,j) >= 0
theta(i,j) = pi/2;
elseif grad_row_double(i,j) == 0 && grad_col_double(i,j) <= 0
theta(i,j) = 3 * pi/2;
end
end
end
% arctan(x)函数值域为(-pi/2,pi/2),根据grad_col_double和grad_row_double将其映射到[0,2pi]
for i = 2 : m - 1
for j = 2 : n - 1
% 方向在第二象限
if grad_row_double(i,j) < 0 && grad_col_double(i,j) >= 0
theta(i,j) = theta(i,j) + pi;
% 方向在第三象限
elseif grad_row_double(i,j) < 0 && grad_col_double(i,j) <= 0
theta(i,j) = theta(i,j) + pi;
% 方向在第四象限
elseif grad_row_double(i,j) > 0 && grad_col_double(i,j) <= 0
theta(i,j) = theta(i,j) + 2 * pi;
end
end
end
% 转为角度制
theta = rad2deg(theta);
function Gmag1 = ex4_MyNMS_2(Gmag,Gdir)
% Gmag1:非极大值抑制后图像梯度
% Gmag:图像梯度,Gdir:图像梯度方向
template_0 = [0,0,0;1,1,1;0,0,0];
template_45 = [0,0,1;0,1,0;1,0,0];
template_90 = [0,1,0;0,1,0;0,1,0];
template_135 = [1,0,0;0,1,0;0,0,1];
[m,n] = size(Gmag);
Gmag1 = Gmag;
for i = 2:m - 1
for j = 2:n - 1
id = ex4_MyDir_2(Gdir(i,j));
temp = Gmag(i - 1:i + 1,j - 1:j + 1);
if id == 1
result = template_0 .* temp;
elseif id == 2
result = template_45 .* temp;
elseif id == 3
result = template_90 .* temp;
elseif id ==4
result = template_135 .* temp;
end
if max(max(result)) ~= Gmag(i,j)
Gmag1(i,j) = 0;
end
end
end
function Gmag2 = ex4_MyDoubleThreshold(Gmag1)
% Gmag1:图像梯度
% Gmag2:经过双阈值检测后的图像梯度
[m,n] = size(Gmag1);
Gmag2 = zeros(m,n);%定义一个双阈值图像
Coef = [0.1,0.12];
% Coef = [0.01,0.05];
% Coef = [0.2,0.22];
ThresholdLow = Coef(1) * max(max(Gmag1));%低阈值
ThresholdHigh = Coef(2) * max(max(Gmag1));%高阈值
for i = 2 : m - 1
for j = 2 : n - 1
if (Gmag1(i, j) < ThresholdLow)
Gmag2(i,j) = 0;
elseif (Gmag1(i, j) > ThresholdHigh)
Gmag2(i,j) = 1 ;
%对ThresholdLow < Nms(i, j) < ThresholdHigh 使用8连通区域确定
elseif (Gmag1(i, j) < ThresholdHigh && Gmag1(i, j) > ThresholdLow)
su =[Gmag1(i-1,j-1), Gmag1(i-1,j), Gmag1(i-1,j+1);
Gmag1(i,j-1), Gmag1(i,j), Gmag1(i,j+1);
Gmag1(i+1,j-1), Gmag1(i+1,j), Gmag1(i+1,j+1)];
Max = max(su);
if Max>=ThresholdHigh
Gmag2(i,j) = 1 ;
end
end
end
end