canny 算子python实现

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边缘检测算法

时间: 2024-08-30 16:40:47

canny 算子python实现的相关文章

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

本篇文章中,我们将一起学习OpenCV中边缘检测的各种算子和滤波器--Canny算子,Sobel算子,Laplace算子以及Scharr滤波器.文章中包含了五个浅墨为大家准备的详细注释的博文配套源代码.在介绍四块知识点的时候分别一个,以及最后的综合示例中的一个.文章末尾提供配套源代码的下载. **** 给大家分享一个OpenCv中写代码是节约时间的小常识.其实OpenCv中,不用nameWindow,直接imshow就可以显示出窗口.大家看下文的示例代码就可以发现,浅墨在写代码的时候并没有用na

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

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/25560901 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 知乎:http://www.zhihu.com/people/mao-xing-yun 邮箱: [email protected] 写作当前博文时配套使用的OpenCV版本: 2.4.9 本篇文章中,我们将一起学习OpenCV中

【opencv入门之九】Opencv边缘检测:Canny算子,Sobel算子,Laplace算子,Scharr滤波器

参考网站: http://blog.csdn.net/poem_qianmo/article/details/25560901 1.边缘检测步骤 1)滤波:边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感.( 通常用高斯滤波 ) 2)增强:增强边缘的基础是确定图像各点领域强度的变化值.增强算法可以将图像灰度点领域强度值有显著变化的点凸显出来.( 可以通过计算梯度幅值来确定 ) 3)检测:经过增强的图像,往往领域中有很多点的梯度值比较大,而特定的应用中,这些点并不是我们要找

Opencv图像识别从零到精通(21)-----canny算子边缘检测

最后来看看canny算子,这个是被成为最好的算子,因为过程多,有准测,后面会列出来,也是边缘检测的最后一个,所以这里作为结尾,来看看各个边缘检测的效果. 边缘检测结果比较 Roberts算子检测方法对具有陡峭的低噪声的图像处理效果较好,但是利用roberts算子提取边缘的结果是边缘比较粗,因此边缘的定位不是很准确. Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果较好,sobel算子对边缘定位不是很准确,图像的边缘不止一个像素. Prewitt算子检测方法对灰度渐变和噪声较多的图像处理效

OpenCV2学习笔记(七):使用Canny算子检测轮廓

在:http://blog.csdn.net/liyuefeilong/article/details/43927909 中,主要讨论了使用sobel算子和拉普拉斯变换进行边缘检测.其中主要使用了了对梯度大小进行阈值化以得到二值的边缘图像的方法.在一幅图像中,边缘往往包含着重要的视觉信息,因为它们描绘出图像元素的轮廓.然而,仅仅使用简单的二值边缘图像有两大缺陷: 使用这种方法检测得到的边缘过粗,这意味着难以实现物体的精确定位. 难以找到这样的阀值,既能足够低检测到所有重要的边缘,同时也不至于包含

Canny 算子 c++

.功能简介及其运行 (一).功能:该程序实现了canny算子求图片的边缘,其中主要包括七大部分: 1.对传入的彩色图片二值化 2.对二值化后的图片进行高斯滤波 3.使用sobel算子对滤波之后的图形分别求x,y方向上的梯度 4.计算出梯度幅值 5.对梯度图像做非极大抑制 6.对非极大抑制后的图像做双阈值处理 7.对双阈值处理后的图像进行连接操作(处理阈值中间的点) (二).运行:注意要在release文件夹下运行exe 运行程序后终端会显示所用到的sobel算子矩阵和高斯滤波矩阵,同时会弹出多张

Opencv对图像做边缘检测——canny算子

图像的边缘检测的原理是检测出图像中所有灰度值变化较大的点,而且这些点连接起来就构成了若干线条,这些线条就可以称为图像的边缘. Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法.Canny 边缘检测的数学原理和算法实现这里就不再了,有兴趣的读者可以查阅专业书籍,本文主要介绍如何在OpenCV中对图像进行Canny 边缘检测,下面就来看看这个函数的原型. 一. 主要函数 1.1 cvCanny 函数功能:采用Canny方法对图像进行边缘检测 函数原型:

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

过程: 1.      彩色图像转换为灰度图像    2.      对图像进行高斯模糊    3.      计算图像梯度,根据梯度计算图像边缘幅值与角度(这里其实用到了微分边缘检测算子来计算梯度幅值方向) 求x,y两个方向的梯度 求幅值与角度 4.      非最大信号压制处理(边缘细化) 也就是把角度分成4个值 得到角度之后,比较中心像素角度上相邻两个像素,如果中心像素小于其中任意一个,则舍弃该边缘像素点,否则保留. 5.      双阈值边缘连接处理 双阈值选择与边缘连接方法通过假设两个

python+opencv实现机器视觉基础技术(边缘提取,图像滤波,边缘检测算子,投影,车牌字符分割)

目录 一:边缘提取 1.对图像进行阈值分割并反色 2.边缘提取 二:图像滤波 1.读取原图 2.均值滤波 3.中值滤波 4.高斯滤波 5.高斯边缘检测 三:边缘检测算子 1.显示原图 2.对图像进行反色 3.对图像用sobel方法进行边缘检测 4.对图像用robert方法进行边缘检测 四:投影 1.显示原图 2.垂直方向投影 3.水平方向投影 五:车牌字符分割 1.读取原图 2.灰度转换 3.反色 4.阈值分割 5.投影 6.字符识别匹配分割 ??机器视觉是人工智能正在快速发展的一个分支.简单说