MATLAB的边缘检测函数中隐含的细化(⾮极⼤值抑制)算法前段时间做了⼀个车牌检测识别的项⽬,我的任务是将MATLAB中的算法移植成C++代码。在车牌区域提取的过程中,⽤到了⽔平⽅向的Sobel算⼦检测垂直边缘,⼀开始我直接把MATLAB中的
bw = edge(I, 'sobel', 'vertical');
语句改写成OpenCV中的
cv::Mat sobel_kernel = (cv::Mat_<float>(3,3) << -0.125, 0, 0.125,
-0.25, 0, 0.25,
-0.125, 0, 0.125);
cv::Mat edges;
cv::filter2D(gray_img, edges, pe(), sobel_kernel);
之后,整个检测算法产⽣了⼀些意想不到的输出。追根溯源,我发现问题的根源就是在这个边缘检测步骤⾥:MATLAB的edge函数产⽣的是⼀个细化的⼆值边缘,⽽OpenCV中输出的是模板卷积后的浮点型的梯
度值,若直接对其阈值化,将产⽣⼀个粗边缘,如下图所⽰(从左到右分别为edge函数输出边缘,OpenCV中直接使⽤Sobel算⼦及阈值化产⽣的边缘,原图)
研究了⼀下edge的实现代码,我发现这么⼀个函数
computeEdgesWithThinning函数实现了⾮极⼤值抑制和阈值化的效果,这个函数的实现⽅式已经被MATLAB封装,⽆法查看。⼀番波折之后,我模拟出⼀个效果基本⼀致的细化及阈值化算法(默认的阈值T为4乘以每个点梯度的模的平⽅的均值):
设 M(i, j) 为某点的梯度的模的平⽅
M(i, j) ⼤于阈值 T 且:
若 M(i, j) > M(i - 1, j) 且 M(i, j) > M(i + 1, j)
或者 M(i, j) > M(i, j - 1) 且 M(i, j) > M(i, j + 1)
则将输出边缘图像的 (i, j) 位置设为 1
简要地说,就是判断⼀个点的梯度是否是⽔平或者垂直⽅向的上的局部极⼤值,当然,梯度值⾸先得⼤
于阈值。经过实验,加上这个⾮极⼤值抑制的步骤后,输出图⽚与MATLAB的edge函数产⽣的边缘图⽚基本⼀致,下⾯整个边缘检测加细化的MATLAB实现代码(只检测垂直的边缘)
function e = sobel_thin(img)
op = fspecial('sobel') / 8;
x_mask = op';
a = im2double(img);
scale = 4;
bx = imfilter(a,x_mask,'replicate');
b = bx.*bx;
cutoff = 4 * mean2(b);
[m, n] = size(b);
for r = 1 : m
for c=1 : n
if ((c - 1) < 1)
b1 = true;
else
b1 = (b(r, c - 1) <= b(r, c));
end正则化损伤识别matlab
if (c + 1) > n
b2 = true;
else
b2 = (b(r, c) > b(r, c + 1));
end
if ((r - 1) < 1)
b3 = true;
else
b3 = (b(r - 1, c) <= b(r, c));
end
if ((r+1) > m)
b4 = true;
else
b4 = (b(r, c) > b(r + 1, c));
end
e(r, c) = (b(r, c) > cutoff) &  ((b1 & b2) | (b3 & b4));
end
end

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。