图像处理之Canny边缘检测
理论介绍:
Canny边缘检测是一种流行的边缘检测算法. 它由John F. Canny于1986年开发. 它是一个多阶段算法, 我们将经历每个阶段.
- 降噪
由于边缘检测易受图像中的噪声影响, 因此第一步是使用5x5高斯滤波器去除图像中的噪. - 寻找图像的强度梯度
然后在水平和垂直方向上用Sobel内核对平滑后的图像进行滤波, 以获得水平方向和垂直方向
的一阶导数. 从这两个图像中, 我们可以找到每个像素的边缘梯度和方向, 渐变方向始终垂直于边缘. 边缘方向角度四舍五入为四个角度中的一个, 表示垂直, 水平和两个对角线(0°,45°,90°和135°). 落入每个颜色区域的边缘方向将被设置为特定角度值,例如, 在[0°,22.5°]或[157.5°,180°]中的θ映射到0°. 如下所示
- 非最大抑制
应用梯度计算后, 从梯度值中提取的边缘仍然非常模. 关于标准3, 应该只对边缘有一个准确的响应. 因此, 非最大抑制可以帮助抑制所有梯度值(通过将它们设置为0), 除了局部最大值, 其指示具有最强烈的强度值变化的位置. 梯度图像中每个像素的算法是:
- 将当前像素的边缘强度与正和负梯度方向上的像素的边缘强度进行比较.
- 如果当前像素的边缘强度与具有相同方向的掩模中的其他像素相比是最大的(例如, 指向y方向的像素将与垂直轴上方和下方的像素进行比较), 该值将被保留. 否则, 该值将被抑制.
- 滞后阈值
这个阶段决定哪些边缘都是边缘, 哪些边缘不是边缘. 为此, 我们需要两个阈值, minVal和maxVal. 强度梯度大于maxVal的任何边缘肯定是边缘, 而minVal以下的边缘肯定是非边缘, 因此被丢弃. 位于这两个阈值之间的人是基于其连通性的分类边缘或非边缘. 如果它们连接到“可靠边缘”像素, 则它们被视为边缘的一部分. 否则, 他们也被丢弃.
边缘A高于maxVal, 因此被视为"确定边缘". 虽然边C低于maxVal, 但它连接到边A, 因此也被视为有效边, 我们得到完整的曲线. 但是边缘B虽然高于minVal并且与边缘C的区域相同, 但它没有连接到任何"可靠边缘", 因此被丢弃. 因此, 我们必须相应地选择minVal和maxVal才能获得正确的结果.
算法原型:
在OpenCV-Python中Canny函数的原型为:
edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])
必要参数:
- 第一个参数是需要处理的原图像, 该图像必须为单通道的灰度图;
- 第二个参数是minVal, 最小边缘阈值
- 第三个参数是maxVal, 最大边缘阈值
推荐的minVal和maxVal阈值之间的比例为1:3或者1:2, 可选参数中apertureSize就是Sobel算子的大小. 而L2gradient参数是一个布尔值, 如果为真, 则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放), 否则使用L1范数(直接将两个方向导数的绝对值相加).
代码展示:
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
edges = cv2.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
结果展示:
原始图像:
处理后图像: