Canny 边缘检测算法详解
文章目录
一、Canny 算法简介
Canny 边缘检测算法 是由 John F. Canny 于 1986 年提出的一种多阶段边缘检测算法,被认为是最优的边缘检测方法之一。
Canny 算法在噪声抑制、定位精度、单边缘响应等方面具有出色的性能,因此在计算机视觉、图像识别、目标检测等领域被广泛应用。
Canny 算法的目标是找到图像中灰度变化剧烈的区域,即边缘所在位置。
二、算法的五个主要步骤
Canny 算法可以分为以下五个步骤:
1️⃣ 高斯滤波(Gaussian Filtering)
目的: 去除噪声,平滑图像。
由于边缘检测对噪声非常敏感,首先需要使用高斯滤波器对图像进行平滑处理。
公式:
G ( x , y ) = 1 2 π σ 2 e − ( x 2 + y 2 ) / ( 2 σ 2 ) G(x, y) = \frac{1}{2\pi\sigma^2} e^{-(x^2 + y^2)/(2\sigma^2)} G(x,y)=2πσ21e−(x2+y2)/(2σ2)
实现示例(OpenCV):
import cv2
import numpy as np
img = cv2.imread('lena.jpg', 0)
blur = cv2.GaussianBlur(img, (5,5), 1.4)
2️⃣ 计算梯度幅值和方向
目的: 通过 Sobel 算子计算每个像素的梯度变化。
Sobel 算子:
G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] , G y = [ 1 2 1 0 0 0 − 1 − 2 − 1 ] G_x = \begin{bmatrix} -1 & 0 & 1\\ -2 & 0 & 2\\ -1 & 0 & 1 \end{bmatrix}, \quad G_y = \begin{bmatrix} 1 & 2 & 1\\ 0 & 0 & 0\\ -1 & -2 & -1 \end{bmatrix} Gx= −1−2−1000121 ,Gy= 10−120−210−1
梯度幅值与方向计算:
G
=
G
x
2
+
G
y
2
,
θ
=
tan
−
1
(
G
y
G
x
)
G = \sqrt{G_x^2 + G_y^2}, \quad \theta = \tan^{-1}\left(\frac{G_y}{G_x}\right)
G=Gx2+Gy2,θ=tan−1(GxGy)
实现示例:
Gx = cv2.Sobel(blur, cv2.CV_64F, 1, 0, ksize=3)
Gy = cv2.Sobel(blur, cv2.CV_64F, 0, 1, ksize=3)
magnitude = np.sqrt(Gx**2 + Gy**2)
angle = np.arctan2(Gy, Gx)
3️⃣ 非极大值抑制(Non-Maximum Suppression, NMS)
目的: 保留真实的边缘像素,抑制非边缘的像素响应。
该步骤会沿梯度方向判断当前像素是否为局部最大值。如果不是,则将其置零。
图解原理:
假设当前像素梯度方向为 45°,若其梯度值小于沿该方向相邻像素的梯度值,则不是边缘点。
4️⃣ 双阈值检测(Double Thresholding)
目的: 将边缘分为三类:
- 强边缘(Strong Edge): 梯度值 ≥ 高阈值
- 弱边缘(Weak Edge): 低阈值 ≤ 梯度值 < 高阈值
- 非边缘(Non Edge): 梯度值 < 低阈值
5️⃣ 边缘连接(Hysteresis Edge Tracking)
目的: 根据强边缘和弱边缘之间的连通性决定最终边缘。
如果弱边缘与强边缘相连,则保留,否则舍弃。
三、算法流程图
四、OpenCV 一行代码实现
OpenCV 已经封装了 Canny 算法,使用非常方便:
edges = cv2.Canny(img, threshold1=100, threshold2=200)
cv2.imshow('Canny Edge', edges)
cv2.waitKey(0)
参数说明:
threshold1
: 低阈值threshold2
: 高阈值- 通常建议:
threshold2 ≈ 2 * threshold1
五、效果展示(R 语言实现)
下图是一张使用 Canny 边缘检测算法得到的边缘检测结果图,清晰地描绘了人脸的轮廓、头发边缘甚至眼睛与服装的边界,可以说效果非常不错。
所用的 R 语言代码如下(使用到了 imager
库。其中的 “gray” 是一张人像的灰度图):
edges_px <- cannyEdges(gray)
save_seq_img(as.cimg(edges_px), "canny_edges")
R 语言的 imager
库的帮助文档中关于 cannyEdges
函数的信息是:
R Documentation - {imager} - cannyEdges
Canny edge detector Description If the threshold parameters are missing, they are determined automatically using a k-means heuristic. Use the alpha parameter to adjust the automatic thresholds up or down The thresholds are returned as attributes. The edge detection is based on a smoothed image gradient with a degree of smoothing set by the sigma parameter.Usage
cannyEdges(im, t1, t2, alpha = 1, sigma = 2)
Arguments
im
input image
t1
threshold for weak edges (if missing, both thresholds are
determined automatically)
t2
threshold for strong edges
alpha
threshold adjusment factor (default 1)
sigma
smoothingAuthor(s)
Simon BarthelmeExamples
cannyEdges(boats) %>% plot #Make thresholds less strict cannyEdges(boats,alpha=.4) %>% plot #Make thresholds more strict canny Edges(boats,alpha=1.4) %>% plot
[Package imager version 1.0.5 Index]
六、参数调优技巧
- 高斯核大小:越大,去噪越强,但边缘会模糊。
- 阈值选择:低阈值过小会导致噪声干扰,过大会丢失边缘。
- σ 参数(高斯标准差):通常取 1~1.5 效果较好。
七、总结
Canny 算法是一种经典且高效的边缘检测方法,兼顾了:
- 抗噪性
- 边缘精度
- 响应唯一性
在实践中,它是目标检测、图像分割、形状识别等任务的基础步骤。
💬 参考资料: