Python OpenCV canny检测

边缘检测 canny

canny原理来源:https://www.cnblogs.com/mmmmc/p/10524640.html

一、 Canny边缘检测算法的发展历史
  Canny算子是28岁的John Canny在1986年提出的,该文章发表在PAMI顶级期刊(1986. A computational approach to edge detection. IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 8, 1986, pp. 679-698)。现在老大爷目前(61岁)在加州伯克利做machine learning,主页(http://www.cs.berkeley.edu/~jfc/),大爷就是大爷。

边缘检测是从图像中提取有用的结构信息的一种技术,如果学过信息论就会知道,一面充满花纹的墙要比一面白墙的信息量大很多,没学过也没关系,直观上也能理解:充满花纹的图像要比单色图像信息更丰富。为什么要检测边缘?因为我们需要计算机自动的提取图像的底层(纹理等)或者高层(时间地点人物等)的信息,边缘可以说是最直观、最容易发现的一种信息了。Canny提出了一个对于边缘检测算法的评价标准,包括:

  1.    以低的错误率检测边缘,也即意味着需要尽可能准确的捕获图像中尽可能多的边缘。
    
  2.    检测到的边缘应精确定位在真实边缘的中心。
    
  3.    图像中给定的边缘应只被标记一次,并且在可能的情况下,图像的噪声不应产生假的边缘。
    

简单来说就是,检测算法要做到:边缘要全,位置要准,抵抗噪声的能力要强。

接下来介绍最经典的canny边缘检测算法,很多边缘检测算法都是在此基础上进行改进的,学习它有利于一通百通。

二、实现步骤
  step1:高斯平滑滤波
没有哪张图片是没有噪声的。————鲁迅

滤波是为了去除噪声,选用高斯滤波也是因为在众多噪声滤波器中,高斯表现最好(表现怎么定义的?最好好到什么程度?),你也可以试试其他滤波器如均值滤波、中值滤波等等。一个大小为(2k+1)x(2k+1)的高斯滤波器核(核一般都是奇数尺寸的)的生成方程式由下式给出:

下面是一个sigma = 1.4,尺寸为3x3的高斯卷积核的例子,注意矩阵求和值为1(归一化):

举个例子:若图像中一个3x3的窗口为A,要滤波的像素点为e,则经过高斯滤波之后,像素点e的亮度值为:

其中*为卷积符号,sum表示矩阵中所有元素相加求和,简单说,就是滤波后的每个像素值=其原像素中心值及其相邻像素的加权求和。图像卷积是图像处理中非常重要且广泛使用的操作,一定要理解好。

其中高斯卷积核的大小将影响Canny检测器的性能。尺寸越大,去噪能力越强,因此噪声越少,但图片越模糊,canny检测算法抗噪声能力越强,但模糊的副作用也会导致定位精度不高,一般情况下,推荐尺寸55,33也行。

step2: 计算梯度强度和方向
边缘的最重要的特征是灰度值剧烈变化,如果把灰度值看成二元函数值,那么灰度值的变化可以用二元函数的”导数“(或者称为梯度)来描述。由于图像是离散数据,导数可以用差分值来表示,差分在实际工程中就是灰度差,说人话就是两个像素的差值。一个像素点有8邻域,那么分上下左右斜对角,因此Canny算法使用四个算子来检测图像中的水平、垂直和对角边缘。算子是以图像卷积的形式来计算梯度,比如Roberts,Prewitt,Sobel等,这里选用Sobel算子来计算二维图像在x轴和y轴的差分值(这些数字的由来?),将下面两个模板与原图进行卷积,得出x和y轴的差分值图,最后计算该点的梯度G和方向θ

计算梯度的模和方向属于高等数学部分的内容,如果不理解应该补习一下数学基本功,图像处理经常会用到这个概念。

这部分我实现了下,首先了解opencv的二维滤波函数:dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

dst:  输出图片

src:  输入图片

ddepth: 输出图片的深度, 详见 combinations,如果填-1,那么就跟与输入图片的格式相同。

kernel: 单通道、浮点精度的卷积核。

以下是默认参数:

anchor:内核的基准点(anchor),其默认值为(-1,-1)表示位于kernel的中心位置。基准点即kernel中与进行处理的像素点重合的点。举个例子就是在上面的step1中,e=HA得到的e是放在原像素的33的哪一个位置,一般来说都是放在中间位置,设置成默认值就好。

delta :在储存目标图像前可选的添加到像素的值,默认值为0。(没用过)

borderType:像素向外逼近的方法,默认值是BORDER_DEFAULT,即对全部边界进行计算。(没用过)

import numpy as np
import cv2 as cv

original = cv.imread('p4.jpg')
print(original.shape)
cv.imshow('1',original)
#边缘检测,canny 效果比较好。目的让边缘更加突出。
canny=cv.Canny(original,50,50)
cv.imshow('canny',canny)

cv.waitKey()

你可能感兴趣的:(Python OpenCV canny检测)