Matlab Notes_图像的边缘检测

发布时间 2023-06-30 22:49:43作者: swankwi

[声明:本文非原创,只是整理,方便检索]

原本打开matlab软件只是为了给一张图片去除背景,巧合之下在网络上找到以下边缘检测相关知识的文章,特在此加以整理,希望能节省诸君一些翻找资料的时间,可以把宝贵时间用来学习知识上面。(以下两幅图分别为代码运行前的原图和运行后的结果图,原图来自:Universe Today

JupiterEarthComp.jpg   JupiterEarthComp-Bm.png

首先是 @郑泽文 在知乎上的文章“数字图像处理:边缘检测(Edge detection)”[1],里面介绍了数字图像处理的基础知识与算法,基本边缘检测算子和高斯滤波器,最后总结部分还给出了Canny边缘检测算法的完整Matlab代码。类似的介绍也在 @mender 在博客园上的文章“canny边缘检测学习笔记”[2] 里有很详细的介绍,互为补充。以下为摘抄自 [1] 的代码主程序段:

EdgeDetec

function Td=EdgeDetec
tic
eI=imread('JupiterEarthComp.jpg');
eIg=rgb2gray(eI);                             % 读取rgb图像并转化为灰度图
sigma=1;                                      % 设定高斯标准差 sigma=1
filterExtent = ceil(4*sigma);                 % 根据高斯标准差计算滤波器长度
x = -filterExtent:filterExtent;               % 生成一维高斯核 gK=gaussKernel
c = 1/(sqrt(2*pi)*sigma);
gK = c * exp(-(x.^2)/(2*sigma^2));   
gK = gK/sum(gK);                              % 标准化
                                              % 对图像进行高斯滤波平滑 Smooth
BS1=imfilter(eIg,gK,'conv','replicate');      % 沿着X轴卷积
BS2=imfilter(BS1,gK','conv','replicate');     % 沿着Y轴卷积
DgK = gradient(gK);                           % 梯度 DgK=derivGaussKernel 
negVals = DgK < 0;
posVals = DgK > 0;
DgK(posVals) = DgK(posVals)/sum(DgK(posVals));
DgK(negVals) = DgK(negVals)/abs(sum(DgK(negVals)));
Bdx = double(imfilter(BS2, DgK, 'conv','replicate'));
Bdy = double(imfilter(BS2, DgK', 'conv','replicate'));
mag=hypot(Bdx,Bdy); 
magmax = max(mag(:));
if magmax>0
    magGrad = mag / magmax;                   % 梯度标准化
end
[m,n]=size(eIg);
counts=imhist(magGrad, 64);
highThresh = find(cumsum(counts) > 0.7*m*n, 1 ,'first' ) / 64;
lowThresh = 0.4*highThresh;
Bm = thinAndThreshold(Bdx, Bdy, magGrad, lowThresh, highThresh);
figure('Name','  Canny图像边缘检测')      
subplot(121);   imshow(eIg);     xlabel('原Gray图像');
subplot(122);  imshow(Bm);  xlabel('Canny边缘检测');
fprintf('\n高阈值TL: %f \n', highThresh);
fprintf('\n低阈值TH: %f \n', lowThresh);
imwrite(Bm,'JupiterEarthComp-Bm.png');
Td=toc;

以上命名为 EdgeDetec.m 的主程序段运行前需要保存以下几个函数:【thinAndThreshold.m】,cannyFLM.m】,和【nonMaximalSupp.m】,它们分别来自 [1], [2], 和 @Sajid Khan 在 MathWorks 问答区的回答“what is code for non-maxima suppression of a grey image”[3]. 不过它们稍有被改动(见代码注释文). 其中的关键代码 cannyFindLocalMaxima, 也即cannyFLM.m】被【nonMaximalSupp.m】调用,而后者又被【thinAndThreshold.m】调用.

thinAndThreshold.m
 function H = thinAndThreshold(dx, dy, magGrad, lowThresh, highThresh)
%-% [Modified-01] E = cannyFindLocalMaxima(dx,dy,magGrad,lowThresh);  % 非极大值抑制
E = nonMaximalSupp(dx,dy,magGrad,lowThresh,highThresh);  % 非极大值抑制
if ~isempty(E)
    [rstrong,cstrong] = find(magGrad>highThresh & E);
    if ~isempty(rstrong) 
        H = bwselect(E, cstrong, rstrong, 8);            % 选定强边缘8连通目标
        H = bwmorph(H, 'thin', 1);                       % 边缘细化
    else
        H = false(size(E));
    end
else
    H = false(size(E));
end
end

 

cannyFLM.m
 function idxLocalMax = cannyFLM(direction,ix,iy,mag)
%-% [Modified-02] function idxLocalMax = cannyFindLocalMaxima(direction,ix,iy,mag)
[m,n] = size(mag);
switch direction
 case 1
  idx = find((iy<=0 & ix>-iy)  | (iy>=0 & ix<-iy));
 case 2
  idx = find((ix>0 & -iy>=ix)  | (ix<0 & -iy<=ix));
 case 3
  idx = find((ix<=0 & ix>iy) | (ix>=0 & ix<iy));
 case 4
  idx = find((iy<0 & ix<=iy) | (iy>0 & ix>=iy));
end

if ~isempty(idx)
  v = mod(idx,m);
  extIdx = (v==1 | v==0 | idx<=m | (idx>(n-1)*m));
  idx(extIdx) = [];
end
 
ixv = ix(idx);  
iyv = iy(idx);   
gradmag = mag(idx);


switch direction
 case 1
  d = abs(iyv./ixv);
  gradmag1 = mag(idx+m).*(1-d) + mag(idx+m-1).*d; 
  gradmag2 = mag(idx-m).*(1-d) + mag(idx-m+1).*d; 
 case 2
  d = abs(ixv./iyv);
  gradmag1 = mag(idx-1).*(1-d) + mag(idx+m-1).*d; 
  gradmag2 = mag(idx+1).*(1-d) + mag(idx-m+1).*d; 
 case 3
  d = abs(ixv./iyv);
  gradmag1 = mag(idx-1).*(1-d) + mag(idx-m-1).*d; 
  gradmag2 = mag(idx+1).*(1-d) + mag(idx+m+1).*d; 
 case 4
  d = abs(iyv./ixv);
  gradmag1 = mag(idx-m).*(1-d) + mag(idx-m-1).*d; 
  gradmag2 = mag(idx+m).*(1-d) + mag(idx+m+1).*d; 
end
idxLocalMax = idx(gradmag>=gradmag1 & gradmag>=gradmag2); 
nonMaximalSupp.m
 function H = nonMaximalSupp(dx, dy, magGrad, lowThresh, highThresh) 
magmax = max(magGrad(:));
    if magmax > 0
        magGrad = magGrad / magmax;
    end
[row, col] = size(magGrad);
E = false(row, col);
idxStrong = [];
for dir = 1:4
    %-% [Modified-03] idxLocalMax = cannyFindLocalMaxima(dir,dx,dy,magGrad);
    idxLocalMax = cannyFLM(dir,dx,dy,magGrad);
    idxWeak = idxLocalMax(magGrad(idxLocalMax) > lowThresh);
    E(idxWeak)=1;
    idxStrong = [idxStrong; idxWeak(magGrad(idxWeak) > highThresh)]; %#ok<AGROW>
end
[m,n] = size(E);
if ~isempty(idxStrong)         % result is all zeros if idxStrong is empty
    rstrong = rem(idxStrong-1, m)+1;
    cstrong = floor((idxStrong-1)/m)+1;
    H = bwselect(E, cstrong, rstrong, 8);
else
    H = zeros(m, n);
end

最后, 关于Canny Detector的详细介绍也可参见@BY Dwiandiyanta 的文章:http://e-journal.uajy.ac.id/5540/1/TF66808.pdf,又或者wikipedia关于Edge Detection的详细介绍.