Canny边缘检测对于边缘的提取有很好的效果。Canny边缘检测方法有以下3个最基本的目标:
1. 低错误率
所有的边缘都可以被检测到,没有检测到的错误边缘,即尽可能避免将不是边缘的像素点误认为是边缘。
信噪比(SNR)公式为:
可见,SNR越小,边缘的误检率就越小。式中,为边缘函数,
是边界为
的滤波器的脉冲响应,
是高斯噪声的均方根。
2. 边缘位置尽可能接近真实场景中的边缘,即定位边缘的精度要高
要求通过Canny边缘检测法检测到的边缘点和实际边缘中心的距离最小。公式为:
3. 最终得到的边缘宽度是单个像素的宽度
Canny边缘检测得到的边缘只有一个像素的宽度,如果边缘处有一个像素的边缘存在和多个像素的边缘存在,那么Canny边缘检测将会选择最小的边缘,即一个像素宽度的边缘。也就是说Canny边缘检测的脉冲响应导数的零交叉点平均距离要满足:
Canny边缘检测通过高斯函数的一阶导数去逼近求解,从而达到以上的目标。
高斯函数为:
Canny检测边缘的处理过程如下:
(1)用高斯滤波器对输入图像进行平滑处理
由于图像是二维的,在对图像进行平滑滤波的时候,选用二维高斯函数对和
执行卷积操作就可以得到平滑滤波后的图像。
(2)计算梯度的模和梯度方向
式中,和
分别是
方向和
方向上的一阶导数,
为梯度的模
求得和
之后可以求取梯度的方向:
(3) 对梯度的模应用非极大值抑制
是梯度的模,因此在
图像中有很多屋脊带,为了确保得到的边缘定位准确,需要对所得到的
进行细化,这一处理过程可以利用非极大值抑制来实现。非极大值抑制法的本质是将边缘的梯度方向划分为几个单独分离的方向区域,对于3*3的区域可以划分边缘的梯度方向为8个区域,每个区域为45°的范围。
在进行非极大值抑制的时候,首先要找到边缘的梯度方向在以上8个区域中的哪一个区域内,以确定要沿哪个方向和近邻值比较。确定梯度方向后,比较
的值和它沿梯度方向的两个领域值,如果领域值中有一个比
大,就说明该点不是局部最大值,
;如果
大于这两个领域值,则
。其中,
是对
图像进行非极大值抑制后的图像。
(4)双阈值处理和连通性分析
这一操作是为了减少错误的边缘点。采用普通的单阈值处理时,如果阈值选得太小,那么一些错误的边缘仍然会被保留下来;如果阈值选得太大,那么一些真实的边缘点将会被消除。Canny边缘检测通过双阈值处理克服了这些问题。首先选取合适的高低阈值和
,如果
,那么该点一定是边缘上的点;如果
,那么该点一定不是边缘上的点;如果
,那么就判断该点的8领域中有没有大于高阈值
的像素,如果有,那么该点就是边缘点,如果没有,那该点就不是边缘点。
OpenCV中的Canny边缘检测
将以上所有内容放在单个函数 cv2.Canny()中了。
# 导包
import cv2 as cv
from matplotlib import pyplot as plt
# 选一个实验用图
img1 = cv.imread('D:/hou/xiaohou1.jpg',0)
# 朋友脸大,给他缩小点
img = cv.resize(img1,(800,800))
# 来直接干Canny,设两个阈值100,200
edges = cv.Canny(img,100,200)
# 用matplotlib做个对比
# 原图
plt.subplot(121),plt.imshow(img,cmap='gray')
plt.title('original')
# Canny后的
plt.subplot(122),plt.imshow(edges,cmap='gray')
plt.title('Edge')
plt.show()
看看砍之后的效果图: