作为对比,先看一下Sobel的原理:
Sobel的原理:
索贝尔算子(Sobeloperator)是图像处理中的算子之一,主要用作边缘检测。在技术上,它是一离散性差分算子,用来运算图像亮度函数的梯度之近似值。在图像的任何一点使用此算子,将会产生对应的梯度矢量或是其法矢量.
该算子包含两组3x3的矩阵,分别为横向及纵向,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。如果以A代表原始图像,Gx及Gy分别代表经横向及纵向边缘检测的图像
Canny边缘检测算子的matlab实现
在以上例子中,如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。
在边沿检测中,常用的一种模板是Sobel 算子。Sobel 算子有两个,一个是检测水平边沿的 ;另一个是检测垂直平边沿的。与 和 相比,Sobel算子对于象素的位置的影响做了加权,因此效果更好。
Sobel算子另一种形式是各向同性Sobel(IsotropicSobel)算子,也有两个,一个是检测水平边沿的 ,另一个是检测垂直平边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。由于建筑物图像的特殊性,我们可以发现,处理该类型图像轮廓时,并不需要对梯度方向进行运算,所以程序并没有给出各向同性Sobel算子的处理方法。
由于Sobel算子是滤波算子的形式,用于提取边缘,可以利用快速卷积函数, 简单有效,因此应用广泛。美中不足的是,Sobel算子并没有将图像的主体与背景严格地区分开来,换言之就是Sobel算子没有基于图像灰度进行处理,由于Sobel算子没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。在观测一幅图像的时候,我们往往首先注意的是图像与背景不同的部分,正是这个部分将主体突出显示,基于该理论,我们给出了下面阈值化轮廓提取算法,该算法已在数学上证明当像素点满足正态分布时所求解是最优的
=================黑丽丽的分割线啊,开始Canny吧=======
Canny的原理:
(1)图象边缘检测必须满足两个条件:一能有效地抑制噪声;二必须尽量精确确定边缘的位置。
(2)根据对信噪比与定位乘积进行测度,得到最优化逼近算子。这就是Canny边缘检测算子。
(3)类似与Marr(LoG)边缘检测方法,也属于先平滑后求导数的方法
step1:用高斯滤波器平滑图象;
step2:用一阶偏导的有限差分来计算梯度的幅值和方向;
step3:对梯度幅值进行非极大值抑制
step4:用双阈值算法检测和连接边缘
<span style="color:#6600cc;"><strong>I=rgb2gray(imread('9.jpg')); subplot(121);imshow(I);title('原图'); BW=edge(I,'canny'); subplot(122);imshow(BW);title('canny边缘处理');</strong></span>
<strong><span style="font-size:18px;"><span style="color:#6600cc;">clear all; close all; clc; img=rgb2gray(imread('9.jpg')); subplot(241);imshow(img);title('原图') [m n]=size(img); img=double(img); %%canny边缘检测的前两步相对不复杂,所以我就直接调用系统函数了 %%高斯滤波 w=fspecial('gaussian',[5 5]); img=imfilter(img,w,'replicate'); subplot(242);imshow(uint8(img));title('高斯滤波') %%sobel边缘检测 w=fspecial('sobel'); img_w=imfilter(img,w,'replicate'); %求横边缘 w=w';%转置 img_h=imfilter(img,w,'replicate'); %求竖边缘 img=sqrt(img_w.^2+img_h.^2); %注意这里不是简单的求平均,而是平方和在开方。我曾经好长一段时间都搞错了 subplot(243);imshow(uint8(img));title('sobel边缘检测') %%下面是非极大抑制 new_edge=zeros(m,n); for i=2:m-1 for j=2:n-1 Mx=img_w(i,j); My=img_h(i,j); if My~=0 o=atan(Mx/My); %边缘的法线弧度 elseif My==0 && Mx>0 o=pi/2; else o=-pi/2; end %Mx处用My和img进行插值 adds=get_coords(o); %边缘像素法线一侧求得的两点坐标,插值需要 M1=My*img(i+adds(2),j+adds(1))+(Mx-My)*img(i+adds(4),j+adds(3)); %插值后得到的像素,用此像素和当前像素比较 adds=get_coords(o+pi);%边缘法线另一侧求得的两点坐标,插值需要 M2=My*img(i+adds(2),j+adds(1))+(Mx-My)*img(i+adds(4),j+adds(3)); %另一侧插值得到的像素,同样和当前像素比较 isbigger=(Mx*img(i,j)>M1)*(Mx*img(i,j)>=M2)+(Mx*img(i,j)<M1)*(Mx*img(i,j)<=M2); %如果当前点比两边点都大置1 if isbigger new_edge(i,j)=img(i,j); end end end subplot(244);imshow(uint8(new_edge));title('非极大抑制') %%下面是滞后阈值处理 up=120; %上阈值 low=100; %下阈值 set(0,'RecursionLimit',10000); %设置最大递归深度 for i=1:m for j=1:n if new_edge(i,j)>up &&new_edge(i,j)~=255 %判断上阈值 new_edge(i,j)=255; new_edge=connect(new_edge,i,j,low); end end end subplot(245);imshow(new_edge==255);title('滞后阈值处理') </span></span></strong><pre name="code" class="plain"><span style="color:#009900;">function nedge=connect(nedge,y,x,low) %种子定位后的连通分析 neighbour=[-1 -1;-1 0;-1 1;0 -1;0 1;1 -1;1 0;1 1]; %八连通搜寻 [m n]=size(nedge); for k=1:8 yy=y+neighbour(k,1); xx=x+neighbour(k,2); if yy>=1 &&yy<=m &&xx>=1 && xx<=n if nedge(yy,xx)>=low && nedge(yy,xx)~=255 %判断下阈值 nedge(yy,xx)=255; nedge=connect(nedge,yy,xx,low); end end end end</span>
<span style="color:#3333ff;">function re=get_coords(angle) %angle是边缘法线角度,返回法线前后两点 sigma=0.000000001; x1=ceil(cos(angle+pi/8)*sqrt(2)-0.5-sigma); y1=ceil(-sin(angle-pi/8)*sqrt(2)-0.5-sigma); x2=ceil(cos(angle-pi/8)*sqrt(2)-0.5-sigma); y2=ceil(-sin(angle-pi/8)*sqrt(2)-0.5-sigma); re=[x1 y1 x2 y2]; end</span>