Canny算法是边缘检测的一个经典算法,比单纯用一些微分算子来检测的效果要好很多,其优势有以下几点:

  1. 边缘误检与漏检率低。
  2. 边缘定位准确,且边界较细。
  3. 自带一定的滤噪功能,或者说,对噪声的敏感度要比单纯算子低。
  4. 具有多个可调整参数,可影响算法的时间与时效。

  但是Canny相比单纯算子来说计算量偏大,下面简单介绍算法的过程。

图像去噪: 

    这一步不是必须的,一般噪声少的图,让Canny自己应付就行。若噪声较多,一般采用高斯滤波。滤波后,噪声灰度下降,对边缘的影响

  小于噪点。

获取梯度强度与方向: 

    用一阶微分算子获取梯度强度和方向,如sobel算子,强度与方向公式如下:

    

    要用两个矩阵分别存储强度和方向,其中方向公式需要根据具体算子情况更改正负号,最终使上下左右、45度方向可以区分开来。例如下图所示,

    这里将上下放在(60,90)和(-90,-60)区间,因为它们在非极大抑制时取的都是上下邻域;将左右放在(-30,30)区间,因为它们抑制时取的是

    左右邻域;将处于斜向上对角线的梯度角放在(30,60),它们在抑制时取45度的两个邻域;将斜向下对角线上的梯度角放在(-60,-30),它们在

    抑制时取-45度的两个邻域。

    

非极大抑制:

    该步骤目的是删除非边缘像素,主要做法是对每个像素点,与它梯度方向的相邻两像素作灰度比较(比如左右两个像素),如果该像素点

  灰度比它两个相邻像素都大,则保留其灰度值,否则抑制(赋值0)。

双阈值处理:

    设定一个高阈值和低阈值,对灰度大于高阈值的像素点,确认为强边缘,赋值255,低于低阈值的点赋值0,介于之间的点保留其灰度值,作为弱边缘。

滞后边界追踪:

    这一步主要是处理弱边缘,总的思路是找到每一个弱边缘的连通域,判断该连通域与强边缘有无相邻,如果存在至少一个像素与强边缘相邻,则将该连

  通域都作为强边缘(赋值255),如果没有一个像素与强边缘相邻,则将整个连通域视为噪声(赋值0)。

    所以,关键在于找到连通域,通常有DFS与BFS两种算法可以处理连通域问题,这里采用BFS算法,思路如下:

    1.扫描整个图像,判断每个像素是否为弱边缘,如果是,进入步骤2(查找连通域)。

    2.用connect数组保存组成连通域的所有点;用weak数组保存待检查八领域的弱点;用checked数组标记已被扫描过的弱点(也就是连通域里的点),标

       记1表示已扫描;用变量real_edge记录是否有检测到强点。将刚才判定的弱边缘点压入connect、weak,checked相应位置标记为1。进入步骤3。

    3.创建new_weak用来保存新的待检测八领域的弱点。依次对weak中每个待检测点,遍历其八领域,找到所有未被checked标记的新弱点,压入new_weak

       、connect,checked相应位置标记为1,同时检查八领域内是否有强边缘,有则标记real_edge=1。对weak所有待检测点检查完后,如果new_weak不为

      空,则将new_weak赋给weak,重复步骤3;如果new_weak为空,则表示一个连通域寻找完毕,进入步骤4。

    4.如果real_edge=1,则将连通域每个点的灰度赋值255,否则赋值0;弹出connect、weak、checked中所有点。

    5.重复步骤1-4,直道图像扫描完毕。

    

  经过以上这些步骤,Canny算法就已经实现了。我们要做的就是根据图像调整双阈值和滤波强度。下面是Canny的一个处理实例,其中给出了单纯sobel检测和

Canny检测的效果。通过下图可以知道,Canny检测的边缘要薄的多,细节处理更好,噪声也更少。

 

  

  以下是matlab代码实现:

  

%canny前先高斯滤波
function edge=canny(gaussianimg,lthres,hthres)
sobel_operator_x=[-,,;
-,,;
-,,];
sobel_operator_y=[-,-,-;
,,;
,,];
%梯度强度
diff_x=filter2(sobel_operator_x,gaussianimg);
diff_y=filter2(sobel_operator_y,gaussianimg);
diff=uint8(sqrt((diff_x.^+diff_y.^)/));
%梯度方向
[sizex,sizey]=size(gaussianimg);
angle=zeros(sizex,sizey);
edge=uint8(zeros(sizex,sizey));
for i=:sizex
for j=:sizey
angle(i,j)=atan(-diff_y(i,j)/diff_x(i,j))/pi*;
end
end
%非极大抑制,排除非边缘像素
for i=:sizex-
for j=:sizey-
if (angle(i,j)>||angle(i,j)<-)
break;
elseif angle(i,j)>= || angle(i,j)<=-
if (diff(i,j)>diff(i-,j)&&diff(i,j)>=diff(i+,j))
edge(i,j)=uint8(diff(i,j));
end
elseif (angle(i,j)<=-)
if (diff(i,j)>diff(i-,j-)&&diff(i,j)>=diff(i+,j+))
edge(i,j)=uint8(diff(i,j));
end
elseif angle(i,j)>=
if (diff(i,j)>diff(i-,j+)&&diff(i,j)>=diff(i+,j-))
edge(i,j)=uint8(diff(i,j));
end
elseif angle(i,j)<||angle(i,j)>-
if (diff(i,j)>diff(i,j-)&&diff(i,j)>=diff(i,j+))
edge(i,j)=uint8(diff(i,j));
end
end
end
end %双阈值
for i=:sizex
for j=:sizey
if (edge(i,j)>=hthres)
edge(i,j)=; %一定为边缘
elseif (edge(i,j)<=lthres)
edge(i,j)=; %一定为非边缘
end
end
end %候选边缘,与已确定边缘相连才认为是边缘
for i=:sizex-
for j=:sizey-
if (edge(i,j)>&&edge(i,j)<)
real_edge=;%边缘真假标志
checked=zeros(sizex,sizey);%标记已经扫描过的弱点
weak=zeros(,);%存储需要查看八领域的弱点
connect=zeros(,);%存储一条联通的所有弱点
weak_length=;
connect_length=;
%压入第一个弱边缘点
weak(weak_length,:)=[i,j];
connect(connect_length,:)=[i,j];
checked(i,j)=;
while(weak_length>)
new_weak=zeros(,);
new_weak_length=;
for k=:weak_length
%搜索当前弱点的八领域
x=weak(k,);y=weak(k,);
if (x>=&&x<=sizex-&&y>=&&y<=sizey-)
for m=x-:x+
for n=y-:y+
if edge(m,n)>&&edge(m,n)<&&checked(m,n)==%领域有弱点且未被扫描过
new_weak_length=new_weak_length+;
connect_length=connect_length+;
new_weak(weak_length,:)=[m,n];%压入新弱点集合
connect(connect_length,:)=[m,n]; %压入连通域
checked(m,n)=; %标记已扫描
elseif edge(m,n)==
real_edge=; %边缘为真,等待连通域全部被识别
end
end
end
end
end
weak_length=new_weak_length;%当前深度的弱点集合全部检查过八领域,开始检查新一深度的弱点集合
weak=new_weak;%如果新集合没有弱点,则跳出while
end
%一个连通域已在connect里形成
for z=:connect_length
edge(connect(z,),connect(z,))=uint8((* real_edge));
end end
end
end
end

  

Canny算法检测边缘的更多相关文章

  1. Kosaraju 算法检测有向图的强连通性

    给定一个有向图 G = (V, E) ,对于任意一对顶点 u 和 v,有 u --> v 和 v --> u,亦即,顶点 u 和 v 是互相可达的,则说明该图 G 是强连通的(Strong ...

  2. opencv目标检测之canny算法

    canny canny的目标有3个 低错误率 检测出的边缘都是真正的边缘 定位良好 边缘上的像素点与真正的边缘上的像素点距离应该最小 最小响应 边缘只能标识一次,噪声不应该标注为边缘 canny分几步 ...

  3. [CLPR] 定位算法探幽 - 边缘和形态学

    一. 引言 如何从一副图片中找到车牌? 这是机器视觉的一个应用. 理所当然地, 思考的角度是从车牌本身的信息入手, 为了讨论方便, 下面均以长窄型蓝白车牌为例. 下图就是这样一张车牌的基本信息. 一眼 ...

  4. [算法]检测空间三角形相交算法(Devillers & Guigue算法)

    #pragma once //GYDevillersTriangle.h /* 快速检测空间三角形相交算法的代码实现(Devillers & Guigue算法) 博客原地址:http://bl ...

  5. Iconfinder 如何杜绝盗版,哈希算法检测图像重复

    原地址:http://blog.jobbole.com/65914/ 本文由 伯乐在线 - 小鱼 翻译自 Silviu Tantos.欢迎加入技术翻译小组.转载请参见文章末尾处的要求. [伯乐在线导读 ...

  6. miller_rabin算法检测生成大素数的RSA算法实现

      import math from functools import reduce #用于合并字符 from os import urandom #系统随机的字符 import binascii # ...

  7. Python3实现Two-Pass算法检测区域连通性

    技术背景 连通性检测是图论中常常遇到的一个问题,我们可以用五子棋的思路来理解这个问题五子棋中,横.竖.斜相邻的两个棋子,被认为是相连接的,而一样的道理,在一个二维的图中,只要在横.竖.斜三个方向中的一 ...

  8. Halcon使用MeasurePos来实现检测边缘点

    (1)为了提高性能,测量句柄只需要初始化一次: 参数:测量矩形的中心点行坐标,测量矩形中心的列坐标,测量矩形的角度,测量矩形的宽,测量矩形的高,待处理图像的宽,待处理图像的高,使用的算法,输出测量句柄 ...

  9. 【OpenCV, C++】实现向下光栅追踪检测边缘

    设计函数如下: 其中 void gratingdetect(Mat &graysrc, Mat &graydst, int high, int low); 参数列表中,第一项是输入的灰 ...

随机推荐

  1. 【转】Spring的IOC原理(通俗易懂)

    1. IoC理论的背景 我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由Ñ个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 如果我们打开机械式手表的后盖,就会看到与上 ...

  2. BOI 2003 团伙

    洛谷 P1892 [BOI2003]团伙 洛谷传送门 题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋 ...

  3. 使用jdk 容器镜像注意默认编码问题

    最近在使用一个开源数据pipeline 处理的工具的时候,发现了jdk容器镜像编码的一些问题 以下是一个简单的描述 问题 使用了streamsets 工具,使用容器运行,默认使用了adoptopenj ...

  4. [RN] React Native 使用 realm 数据库

    React Native 使用 realm  数据库 realm 是一款专为移动 ​ 端开发的高性能数据库,其宣称自己是最快的 react-native 数据库. realm 整体的优点有这么四点: ...

  5. generator(生成器)

    什么是generator函数: 在js中,一个函数一旦执行,就会运行到最后或者遇到return时结束,运行期间不会有其它代码能打断它,也不能从外部再传入值到函数体内. generator函数的出现就可 ...

  6. [LeetCode] 198. House Robber 打家劫舍

    You are a professional robber planning to rob houses along a street. Each house has a certain amount ...

  7. JaCoCo覆盖率计数器

    覆盖率计数器 JaCoCo使用一组不同的计数器来计算覆盖率指标.所有这些计数器都是从Java类文件里获取信息,这些类文件包含Java 字节码指令和调试信息.即使没有可用源代码情况下,这种方法可以实时有 ...

  8. WPF 目录树绑定 与 遍历

    定义树节点,(编译环境VS2017) public class GBTreeNode : INotifyPropertyChanged { private string _deviceId = str ...

  9. 是时候解决 students's Test 假设检验(显著性检验)了

    T test 由来已久 T 检验的概念 假设检验的步骤 假设检验可以分为三步: 建立检验假设和确定检验水准 单侧检验与双侧检验 选定检验方法和计算检验统计量 确定P值和做出推断结论 假设检验的两类错误 ...

  10. 使用VUECLI3

    $ yarn global add @vue/cli // OR $ npm install @vue/cli -g 然后在加入下面的代码 $ vue create my-app $ cd my-ap ...