1. Canny介绍

Canny算子与Marr(LoG)边缘检测方法类似,也属于是先平滑后求导数的方法。John Canny研究了最优边缘检测方法所需的特性,给出了评价边缘检测性能优劣的三个指标:

  • 1  好的信噪比,即将非边缘点判定为边缘点的概率要低,将边缘点判为非边缘点的概率要低;
  • 2  高的定位性能,即检测出的边缘点要尽可能在实际边缘的中心;
  • 3  对单一边缘仅有唯一响应,即单个边缘产生多个响应的概率要低,并且虚假响应边缘应该得到最大抑制。

2. Canny检测实现过程

第一步:灰度化 

第二步:高斯滤波 

首先生成二维高斯分布矩阵:

然后与灰度图像进行卷积实现滤波:

第三步:计算梯度值和方向 

求变化率时,对于一元函数,即求导;对于二元函数,求偏导。 数字图像处理中,用一阶有限差分近似求取灰度值的梯度值(变化率)
             (即:使差商(Δf/Δx)近似取代微商(∂f/∂x)。求灰度的变化率,分别取x和y方向上相邻像素做差,代替求取x和y

方向一阶偏导) 。

其中f为图像灰度值,P代表X方向梯度幅值,Q代表Y方向 梯度幅值,M是该点幅值Θ是梯度方向,也就是角度。

注:图像梯度方向与边缘方向互相垂直:

第四步:非极大值抑制(NMS)

             通俗意义上是指寻找像素点局部最大值。沿着梯度方向,比较它前面和后面的梯度值。在沿其方向上邻域的梯度幅值最大,则保留;否则,抑制

具体参考此文:canny 非极大值抑制 NMS

可以进行插值来提高结果。

第五步:双阈值的选取、边缘连接

  • 选取高阈值T H 和低阈值T L ,比率为2:1或3:1。(一般取T=0.3 或 0.2T=0.1 )
  • 取出非极大值抑制后的图像中的最大梯度幅值,重新定义高低阈值。即:T H ×Max,T L ×Max  。(当然可以自己给定)
  • 将小于TL 的点抛弃,0;将大于T H 的点立即标记(这些点就是边缘点),1
  • 将大于TL ,小于TH 的点使用8连通区域确定(即:T,成为边缘点,1)  。

3. Canny检测Python实现

具体实现略有不同,例如:

高斯矩阵的实现过程、梯度幅值的实现过程、非极大值抑制的角度选取(可以选0,45,90,135)、边缘检测的实现过程。

# -*- coding: utf-8 -*-
"""
Created on Thu Dec 7 21:12:41 2017 @author: L.P.S
""" import matplotlib.pyplot as plt
import numpy as np
import math img = plt.imread('G:\\360downloads\\lps.png') sigma1 = sigma2 = 1
sum = 0 gaussian = np.zeros([5, 5])
for i in range(5):
for j in range(5):
gaussian[i,j] = math.exp(-1/2 * (np.square(i-3)/np.square(sigma1) #生成二维高斯分布矩阵
+ (np.square(j-3)/np.square(sigma2)))) / (2*math.pi*sigma1*sigma2)
sum = sum + gaussian[i, j] gaussian = gaussian/sum
# print(gaussian) def rgb2gray(rgb):
return np.dot(rgb[...,:3], [0.299, 0.587, 0.114]) # step1.高斯滤波
gray = rgb2gray(img)
W, H = gray.shape
new_gray = np.zeros([W-5, H-5])
for i in range(W-5):
for j in range(H-5):
new_gray[i,j] = np.sum(gray[i:i+5,j:j+5]*gaussian) # 与高斯矩阵卷积实现滤波 # plt.imshow(new_gray, cmap="gray") # step2.增强 通过求梯度幅值
W1, H1 = new_gray.shape
dx = np.zeros([W1-1, H1-1])
dy = np.zeros([W1-1, H1-1])
d = np.zeros([W1-1, H1-1])
for i in range(W1-1):
for j in range(H1-1):
dx[i,j] = new_gray[i, j+1] - new_gray[i, j]
dy[i,j] = new_gray[i+1, j] - new_gray[i, j]
d[i, j] = np.sqrt(np.square(dx[i,j]) + np.square(dy[i,j])) # 图像梯度幅值作为图像强度值 # plt.imshow(d, cmap="gray") # setp3.非极大值抑制 NMS
W2, H2 = d.shape
NMS = np.copy(d)
NMS[0,:] = NMS[W2-1,:] = NMS[:,0] = NMS[:, H2-1] = 0
for i in range(1, W2-1):
for j in range(1, H2-1): if d[i, j] == 0:
NMS[i, j] = 0
else:
gradX = dx[i, j]
gradY = dy[i, j]
gradTemp = d[i, j] # 如果Y方向幅度值较大
if np.abs(gradY) > np.abs(gradX):
weight = np.abs(gradX) / np.abs(gradY)
grad2 = d[i-1, j]
grad4 = d[i+1, j]
# 如果x,y方向梯度符号相同
if gradX * gradY > 0:
grad1 = d[i-1, j-1]
grad3 = d[i+1, j+1]
# 如果x,y方向梯度符号相反
else:
grad1 = d[i-1, j+1]
grad3 = d[i+1, j-1] # 如果X方向幅度值较大
else:
weight = np.abs(gradY) / np.abs(gradX)
grad2 = d[i, j-1]
grad4 = d[i, j+1]
# 如果x,y方向梯度符号相同
if gradX * gradY > 0:
grad1 = d[i+1, j-1]
grad3 = d[i-1, j+1]
# 如果x,y方向梯度符号相反
else:
grad1 = d[i-1, j-1]
grad3 = d[i+1, j+1] gradTemp1 = weight * grad1 + (1-weight) * grad2
gradTemp2 = weight * grad3 + (1-weight) * grad4
if gradTemp >= gradTemp1 and gradTemp >= gradTemp2:
NMS[i, j] = gradTemp
else:
NMS[i, j] = 0 # plt.imshow(NMS, cmap = "gray") # step4. 双阈值算法检测、连接边缘
W3, H3 = NMS.shape
DT = np.zeros([W3, H3])
# 定义高低阈值
TL = 0.2 * np.max(NMS)
TH = 0.3 * np.max(NMS)
for i in range(1, W3-1):
for j in range(1, H3-1):
if (NMS[i, j] < TL):
DT[i, j] = 0
elif (NMS[i, j] > TH):
DT[i, j] = 1
elif ((NMS[i-1, j-1:j+1] < TH).any() or (NMS[i+1, j-1:j+1]).any()
or (NMS[i, [j-1, j+1]] < TH).any()):
DT[i, j] = 1 plt.imshow(DT, cmap = "gray")

4. 实验结果

                                     

原图                                                       双阈值:0.1*max, 0.3*max                                双阈值:0.2*max, 0.3*max

参考:

算法解剖系列-Canny边缘检测原理及实现

Canny边缘检测详解及编程实现

Canny算子中的非极大值抑制(Non-Maximum Suppression)分析

canny算子中非极大值抑制算法的理解

canny算子原理以及实现

图像学习之如何理解方向梯度直方图(Histogram Of Gradient)

论文:一种改进非极大值抑制的Canny边缘检测算法

canny 算子python实现的更多相关文章

  1. python opencv Sobel、Laplace、canny算子的边缘提取 以及参数解析

    前提:各种算子不完全区分好坏,但根据我实际操作分析得到,有的算子之间效果大相径庭,但有的也很相似,也就是各有各的用法,这里按 Sobel.Laplace.canny三种算子作比较,看其结果: 一.  ...

  2. Canny算子边缘检测(cvCanny)

    Canny是常用的边缘检测方法,其特点是试图将独立边的候选像素拼装成轮廓. John Canny于1986年提出Canny算子,它与Marr(LoG)边缘检测方法类似,也属于是先平滑后求导数的方法. ...

  3. 【OpenCV新手教程之十二】OpenCV边缘检測:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/25560901 作者:毛星云(浅墨) ...

  4. [OpenCV入门教程之十二】OpenCV边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器合辑

    http://blog.csdn.net/poem_qianmo/article/details/25560901 本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog ...

  5. 学习 opencv---(11)OpenC 边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器

    本篇文章中,我们将一起学习OpenCV中边缘检测的各种算子和滤波器——Canny算子,Sobel算子,Laplace算子以及Scharr滤波器.文章中包含了五个浅墨为大家准备的详细注释的博文配套源代码 ...

  6. 边缘检测:Canny算子,Sobel算子,Laplace算子

    1.canny算子 Canny边缘检测算子是John F.Canny于 1986 年开发出来的一个多级边缘检测算法.更为重要的是 Canny 创立了边缘检测计算理论(Computational the ...

  7. Pass算子python 函数

    Pass算子python 函数 函数 函数是代码的一种组织形式 函数应该能完成一项特定的工作,而且一般一个函数只完成一项工作 有些语言,分函数和过程两个概念,通俗解释是,有返回结果的是函数,无返回结果 ...

  8. Canny算子

    Canny边缘检测算子是John F. Canny于1986年开发出来的一个多级边缘检测算法.更为重要的是Canny创立了“边缘检测计算理论”(computational theory of edge ...

  9. canny算子求图像边缘,edgebox那部分

    过程: 1.      彩色图像转换为灰度图像    2.      对图像进行高斯模糊    3.      计算图像梯度,根据梯度计算图像边缘幅值与角度(这里其实用到了微分边缘检测算子来计算梯度幅 ...

随机推荐

  1. Android canvast View 代码实例

    package com.app.canvastest; import android.content.Context; import android.graphics.Bitmap; import a ...

  2. [hdu6148][Valley Numer]

    hdu6148 思路 一个数位dp模板题,注意判断前导0.用一个bz来记录当前是应该增还是可增可减.然后排除不满足条件的情况并进行dp即可. 代码 #include<cstdio> #in ...

  3. C++中hpp的适用

    本文第一部分转载百度百科,在此感谢百度.第二部分示例为独立编写. hpp,其实质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的调用者只需要include该hpp文件即 ...

  4. CentOS 7 系统的初化始配置

    安装好CentOS7系统后我们要进行初始设置来让我们的服务器方便管理与使用,但是发现在7以前的版本都能输入的命令不能输入了,去官网查查才发发生了很大的变化,关于有哪些变化的可以点击这里查看,初始配置的 ...

  5. 【已解决】ERR_BLOCKED_BY_XSS_AUDITOR:Chrome 在此网页上检测到了异常代码:解决办法

    工作中,用Selenium自动化填表并获取结果时,程序一直安静的读取数据库,网页填表,获取结果,存库,但跑着跑着突然报错了. 排查后,原来不是Selenium的问题,是数据比较特殊,带了个双引号,如下 ...

  6. conda常用命令总结

    conda 一些背景历史以及如何安装这里就不说了,因为实在是漫天都在飞,随便都能找到相关的资料.我这里只是将平时常用到的 Conda 命令进行汇总,以备不时之需,因为我也是一个忘性极大的人,实在是记不 ...

  7. Spark进阶之路-Spark提交Jar包执行

    Spark进阶之路-Spark提交Jar包执行 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在实际开发中,使用spark-submit提交jar包是很常见的方式,因为用spark ...

  8. JAVA-大白话探索JVM-类加载过程(二)

    首先我们知道JVM是什么以及类加载器的作用 不清楚的可以看看JAVA-大白话探索JVM-类加载器(一) 现在我们来摸索下类的加载过程 首先,我们将类加载过程分为三步走 装载 链接 初始化 其中 链接 ...

  9. js格式化input输入框内容(每几位分一组,并使用特定字符分隔)

    <html> <head> <title></title> </head> <body> <input id=" ...

  10. CodeChef - CRYPCUR

    题目链接 AMRExchange is the latest cryptocurrency exchange that has become very popular among cryptocurr ...