Canny Edge Detection
Canny 边缘检测是一种多阶段算法,可减少噪声、检测亮度的剧烈变化,并生成细线状边缘图,用于计算机视觉。
Canny 边缘检测是一种多阶段图像处理算法,可识别亮度的剧烈变化,并将这些变化转换为细线状二值边缘图。它能减少噪声、定位强度变化,并将可靠的边缘像素连接成轮廓。在计算机视觉中,这些轮廓描述了图像结构,可用于形状分析和测量。
John Canny 于 1983 年提出了这种方法,并在 1986 年的论文 A Computational Approach to Edge Detection 中进行了阐述。该方法的设计兼顾三个目标:检测真实边缘、准确定位边缘,以及确保每条边缘只产生一个响应。“Canny edge detector”是该算法的另一个名称。
Canny 边缘检测的工作原理#
该算法将数据预处理与滤波和连通性分析结合起来。五个阶段各司其职:
- 降噪: 高斯平滑会根据距离为相邻像素加权平均,从而抑制可能产生多余边缘的波动。
- 梯度估算: 水平和垂直导数衡量亮度变化的快慢。将两者结合可得到边缘强度,以及垂直于边界的方向。OpenCV 在此阶段使用 Sobel 导数。
- 边缘细化: 非极大值抑制会沿梯度方向保留局部梯度峰值,从而生成窄脊线,而非宽条带。
- 双阈值处理: 高阈值用于识别强边缘,低阈值用于剔除较弱的响应。介于两个阈值之间的像素会被列为候选像素。
- 滞后连接: 如果候选像素通过其他候选像素与强边缘相连,就会被保留。孤立的候选像素则会被移除。
阈值、平滑处理与失效模式#
这些阈值作用于梯度强度,而非原始亮度或模型置信度。降低阈值会保留更多细节和噪声;提高阈值则会去除较弱的边界。提高高阈值还会减少可用于滞后连接的强边缘种子点。
高斯尺度控制着另一种权衡。更强的平滑处理可以抑制噪声,但也会去除精细结构。在 scikit-image 的噪声方块示例中,改变高斯标准差会影响方块周围残留的噪声量。
在裂纹检测中,粗糙的混凝土表面会产生不需要的纹理边缘和不完整的裂纹轮廓。提高阈值可以去除一些伪边缘,但也会丢失真实裂纹的一些部分。
Sobel 用于估算强度导数;Canny 则结合了梯度估算、平滑处理、细化和基于连通性的筛选。Canny 的细化阶段会比较相邻像素,而目标检测中的 NMS会比较相互重叠的预测框。
使用 Python 进行 Canny 边缘检测#
使用 pip install opencv-python numpy 安装依赖项。此示例使用 OpenCV 保存公交车样例的边缘图:
from urllib.request import urlopen
import cv2
import numpy as np
with urlopen("https://ultralytics.com/images/bus.jpg") as response:
encoded = np.frombuffer(response.read(), dtype=np.uint8)
gray = cv2.imdecode(encoded, cv2.IMREAD_GRAYSCALE)
# 计算强度梯度前先平滑图像。
smoothed = cv2.GaussianBlur(gray, (5, 5), 1.4)
edges = cv2.Canny(smoothed, 50, 150, L2gradient=True)
cv2.imwrite("canny_edges.png", edges)保存的 PNG 显示了保留的边缘,白色边缘呈现在黑色背景上。在 OpenCV 边缘检测工作流中,Canny 的第二个和第三个参数分别指定低阈值和高阈值。L2gradient=True 使用欧几里得梯度幅值;默认设置则使用水平和垂直导数绝对值之和。这些选择会改变梯度值,进而影响阈值行为。
应用场景与相关视觉任务#
Canny 支持几何特征提取:scikit-image 的线检测示例先对一张摄影师照片应用 Canny,再通过概率霍夫变换提取直线线段。Canny 提供边缘像素;霍夫投票则将这些像素归组为直线。目标检测会分配类别和边界框,而实例分割会将像素分配给单个对象。
Ultralytics YOLO26分割会返回用于对象分离的掩码,这些掩码可用于选取图像区域,分别进行 Canny 处理。这种方法将学习式对象选择与经典边界提取相结合。
在生成式 AI中,ControlNet使用 Canny 图作为扩散模型的空间条件。其 Canny 条件实现会将提取的轮廓与文本提示结合起来,引导 Stable Diffusion 1.5 生成图像。










