0.参考
Canny 边缘检测 — OpenCV 2.3.2 documentation
OpenCV-Python教程(8、Canny边缘检测)_sunny2038的专栏-CSDN博客
1.原理
Canny 边缘检测算法 是 John F. Canny 于 1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的 最优算法, 最优边缘检测的三个主要评价标准是:
- 低错误率: 标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。
- 高定位性: 标识出的边缘要与图像中的实际边缘尽可能接近。
- 最小响应: 图像中的边缘只能标识一次。
2.步骤
(1)消除噪声。
使用高斯平滑滤波器卷积降噪。 下面显示了一个 的高斯内核示例:
(2)计算梯度幅值和方向。
此处,按照Sobel滤波器的步骤:
a.运用一对卷积阵列 (分别作用于 x 和y 方向):
b.使用下列公式计算梯度幅值和方向:
梯度方向近似到四个可能角度之一(一般 0, 45, 90, 135)
(3)非极大值抑制
这一步排除非边缘像素,仅仅保留了一些细线条(候选边缘)
(4)滞后阈值
最后一步,Canny 使用了滞后阈值,滞后阈值需要两个阈值(高阈值和低阈值):
a.如果某一像素位置的幅值超过高阈值,该像素被保留为边缘像素。
b.如果某一像素位置的幅值小于低阈值,该像素被排除。
c.如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高闽值的像素时被保留。
Canny 推荐的高低阈值比在2:1到3:1之间。
3.Canny函数接口
cv.Canny(
image,
threshold1,
threshold2[, edges[, apertureSize[, L2gradient]]]
)
-> edges
cv.Canny(
dx,
dy,
threshold1,
threshold2[, edges[, L2gradient]]
)
-> edges
Parameters
image 需要处理的原图像,该图像必须为单通道的灰度图; dx
16-bit x derivative of input image (CV_16SC1 or CV_16SC3). dy 16-bit y derivative of input image (same type as dx). edges output edge map; single channels 8-bit image, which has the same size as image . threshold1 first threshold for the hysteresis procedure. threshold2 second threshold for the hysteresis procedure. L2gradient a flag, indicating whether a more accurate L2 norm =(dI/dx)2+(dI/dy)2−−−−−−−−−−−−−−−−√ should be used to calculate the image gradient magnitude ( L2gradient=true ), or whether the default L1 norm =|dI/dx|+|dI/dy| is enough ( L2gradient=false ).
其中较大的阈值2用于检测图像中明显的边缘,但一般情况下检测的效果不会那么完美,边缘检测出来是断断续续的。所以这时候用较小的第一个阈值用于将这些间断的边缘连接起来。
可选参数中apertureSize就是Sobel算子的大小。而L2gradient参数是一个布尔值,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),否则使用L1范数(直接将两个方向导数的绝对值相加)。
具体的算法可参见清华大学出版社的《图像处理与计算机视觉算法及应用(第2版) 》第二章,其中有Canny算法的详细描述及实现。
函数返回一副二值图,其中包含检测出的边缘。
4.测试代码
Canny函数内部并没有对图像进行很好地降噪,因此为了保证结果更准确,我们在调用Canny函数前常常会先通过高斯滤波降噪。
import cv2
import numpy as np
# 获取照片路径
path=r"C:\Users\Nobody\Desktop\Hand.JPG"
# 读取灰度照片
img=cv2.imread(path,0)
# 缩放
img1=cv2.resize(img,None,fx=0.5,fy=0.5)
# 高斯滤波
img_gaus=cv2.GaussianBlur(img1,(3,3),0)
# canny算子
img_canny=cv2.Canny(img_gaus,50,160)
imgs=np.hstack([img1,img_gaus,img_canny])
cv2.imshow('multi pic',imgs)
cv2.waitKey()
结果输出: