@Canny算子中的非最大值抑制(NMS)实现
canny算子中的非极大值抑制是在对图像进行梯度求取之后,在梯度方向进行的运算,也就是说此处的非极大值抑制是在对图像进行梯度求取后,在生成的梯度矩阵上求取的极大值。
注:canny算法在进行非极大值抑制之前需要先进行滤波和梯度求取。
该算法的实现流程:
假设原始图像A为4*4的矩阵,如下:
- 进行梯度计算,经过梯度求取后B为:
计算方法为:
dx(i,j) = A(i,j+1) - A(i,j);
dy(i,j) = A(i+1, j) - A(i,j);
B(i,j) = sqrt(dx(i,j)*dx(i,j) + dy(i,j)*dy(i,j));
代码实现为:
A=[2,3,4,6; 5,7,2,1; 4,6,9,6; 5,7,3,2];
[height, width] = size(A);
dx = zeros(height, width);
dy = zeros(height, width);
d = zeros(height, width);
for i = 1:height-1
for j = 1:width-1
dx(i,j) = A(i,j+1) - A(i,j);
dy(i,j) = A(i+1, j) - A(i,j);
d(i,j) = sqrt(dx(i,j)*dx(i,j) + dy(i,j)*dy(i,j));
end
end
该算法对于后一列和最后一行没有求取其梯度值。
- 非极大值抑制(NMS)
在梯度矩阵B上进行非极大值运算处理,可以直接比较中心点0,90,45,135四个方向的梯度值,若该点是最大值,则保留。否则为0,即假设在梯度矩阵中的某点为中心点C(i,j),则该点的取值为C(i,j) 是否满足在(C(i,j), C(i,j+1), C(i+1,j), C(i+1, j+1))为最大值,若是保留,否则为0。
但由于实际图像中的像素点是离散的二维矩阵,处于真正中心位置C出的梯度方向的两侧的点不一定存在,或者说存在一个亚像素点,而这个不存在的点以及这个点的梯度值就必须通过两侧的点插值得到。 这句话我的理解是,以中心点C的梯度方向做一条斜线,用斜线与周围梯度值的交点 和 中心点C的梯度值比较 判断其是否为最大值。
来个图说明一下:
C 为中心点,梯度值为d(i,j);
在x方向的梯度为dx(i,j);
在y方向的梯度值为:dy(i,j);
则过C点的梯度方向线共有4中情况:
1) |dy|>|dx|,且dxdy>0; 2) |dy|>|dx|,且dxdy<0; 3) |dy|<|dx|,且dxdy>0; 4) |dy|<|dx|,且dxdy<0.
四种情况在图中显示如下所示:
其中: q1,q2,q3,q4分别代表与在梯度矩阵中与C相关的相邻点。
当|dy|>|dx|时,共有2种情况:1)和2),此时weight=|dx|/|dy|.
由线与线之间的相交关系,结合三角形,即可求得:
d1 = weight*q1+(1-weight)q2;
d2 = weightq3+(1-weight)q4;
当|dx|>|dy|时,共有2种情况:3)和4),此时weight=|dy|/|dx|.
同理,d1 = weightq1+(1-weight)q2; d2 = weightq3+(1-weight)*q4;
然后,比较d(i,j)>=d1,且d(i,j)>=d2是否成立,若满足,保留d,否则d=0。
流程图如下:
本文以MATLAB库中的图片rice.png为例,结果如下:
原始图片:
高斯滤波处理后:
求梯度后:
非极大值抑制之后:
详细代码如下:
clear all; close all; clc
I = imread('rice.png');
% I = rgb2gray(I);
I = im2double(I);
[height, width] = size(I);
figure; imshow(I);title('I')
%高斯卷积核
conv = zeros(5, 5);
sigma = 1;
sigma_2 = sigma * sigma;
sum = 0;
for i=1:5
for j=1:5
conv(i,j) = exp((-(i-3)*(i-3) - (j-3)*(j-3)) / (2*sigma_2))/(2*3.14*sigma_2);
sum = sum+conv(i,j);
end
end
conv = conv./sum %标准化的高斯卷积核
%对图像进行高斯滤波处理
J = conv2(I, conv, 'same');
figure; imshow(J);title('高斯滤波处理');
%添加sobel算子
% s=[1 2 1; 0 0 0; -1 -2 -1];
% H = conv2(J1, s,'same');
% V = conv2(J1, s','same');
% J = sqrt(H.*H + V.*V);
% % J1 = uint8(J1);
% figure;imshow(J);title('sobel提取边缘');
%求梯度
dx = zeros(height, width);
dy = zeros(height, width);
d = zeros(height, width);
for i = 1:height-1
for j = 1:width-1
dx(i,j) = J(i,j+1) - J(i,j);
dy(i,j) = J(i+1, j) - J(i,j);
d(i,j) = sqrt(dx(i,j)*dx(i,j) + dy(i,j)*dy(i,j));
end
end
figure;imshow(d*10);title('求梯度后的结果')
%局部非极大值抑制
K = zeros(height, width);
for i=2:height-1
for j = 2:width-1
if d(i,j) == 0
K(i,j) = 0;
else
gradX = dx(i,j);
gradY = dy(i,j);
gradTemp = d(i,j);
if abs(gradY)>abs(gradX)
weight = abs(gradX)/abs(gradY);
grad2 = d(i-1,j);
grad4 = d(i+1,j);
if gradX*gradY>0
grad1 = d(i-1,j-1);
grad3 = d(i+1,j+1);
else
grad1 = d(i-1,j+1);
grad3 = d(i+1,j-1);
end
else
weight = abs(gradY)/abs(gradX);
grad2 = d(i,j-1);
grad4 = d(i,j+1);
if gradX*gradY>0
grad1 = d(i+1, j-1);
grad3 = d(i-1, j+1);
else
grad1 = d(i-1, j-1);
grad3 = d(i+1, j+1);
end
end
gradTemp1 = weight*grad1 + (1-weight)*grad2;
gradTemp2 = weight*grad3 + (1-weight)*grad4;
if gradTemp >=gradTemp1 && gradTemp >= gradTemp2
K(i,j) = gradTemp;
else
K(i,j) = 0;
end
end
end
end
figure;imshow(K*10);title('非极大值自己')
figure;imhist(K);title('直方图')
本文重点介绍了 canny算子中的梯度求取和非极大值抑制的实现过程。该文为作者在学习过程中对该部分的理解,希望对您能有所帮助。如有问题,敬请各位指点。