Canny()函数用作检测图像中的边缘。
实现
1. 降低噪音
因为边缘检测易受噪声的影响,故Canny函数会首先使用 5*5 的核进行高斯模糊处理
2. 找到高梯度的位置
使用 Sobel kernel 做横向和纵向的检测。
对 Sobel kernel 的解释(纵向为例):
显然,使用Sobel kernel可以计算像素间灰度值的梯度,梯度越大,则说明色差越大,则越有可能是某种边缘。
随后,将横向和纵向梯度相加,计算出实际梯度和角度
3. 使用非极大值抑制减少候选区
关于非极大值抑制不做过多解释,其作用是:如果多个候选区有重叠的部分,则只选取其中一个候选区即可。
4. 阈值筛选
显然,从梯度计算方式来看,其可能计算出各种大小值的梯度,如何判断哪些梯度可被视作为边缘则需要用户指定一个阈值。例如若用户指定阈值为100,则若检测梯度大于100,则其一定认为是边缘。若其梯度小于50(opencv规定下界阈值为上界的一半),则其一定不是边缘。对于大于50而小于100的部分,如果其与梯度大于100的边缘相连着的,则也认为其是边缘,否则,则不是边缘,丢弃。
上图中,A线超过maxVal的部分被认为一定是边缘,因为C线与A线相连,且其没有低于minVal,所以它也被认为是边缘。B处于两个阈值之间,但独立存在,故其不会被认为是边缘,丢弃。
参数
写本文的目的也是因为绝大部分中文博客互相抄来抄去,都抄的是错的。特别是哪个threshold1参数,几乎没看到对的
threshold1参数表示上述原理中第四步中的maxVal(上界阈值),它指的是梯度,而非绝大多数人说的像素值。
threshold2指的是minVal,也是梯度值
参考
本文大部分译自官网说明:https://docs.opencv.org/3.4/da/d22/tutorial_py_canny.html
api说明:https://docs.opencv.org/3.4/dd/d1a/group__imgproc__feature.html#ga04723e007ed888ddf11d9ba04e2232de