OpenCV Canny 边缘检测算法原理与 C++ 实现
目标
在本教程中,您将学习如何:
- 使用 OpenCV 函数
Canny实现 Canny 边缘检测器。 - 理解 Canny 算法的核心步骤及其参数设置。
- 编写完整的 C++ 代码进行实时边缘检测演示。
理论背景
Canny 边缘探测器 由 John F. Canny 于 1986 年开发。该算法被广泛认为是边缘检测的'最佳'标准之一,旨在满足以下三个主要准则:
- 错误率低:这意味着仅对存在的边缘进行良好检测,尽量减少漏检和误检。
- 良好的本地化:检测到的边缘像素必须尽可能接近实际边缘像素的位置。
- 最小响应:每个边缘在图像中只能有一个检测器响应,避免重复响应。
算法步骤详解
1. 高斯滤波去噪
首先,过滤掉图像中的任何噪声。噪声会干扰边缘检测的准确性。通常使用高斯滤波器(Gaussian Filter)来实现平滑处理。
2. 计算图像强度梯度
为了找到边缘,我们需要计算图像的梯度幅值和方向。这类似于 Sobel 算子的操作:
- 应用一对卷积掩模(分别在 x 和 y 方向),计算梯度的近似值。
- 通过以下公式找到梯度强度和方向:
- 梯度强度 $G = \sqrt{G_x^2 + G_y^2}$
- 梯度方向 $\theta = \arctan(G_y / G_x)$
3. 非极大值抑制 (Non-Maximum Suppression)
这一步将梯度幅值图像细化为单像素宽的边缘。它沿着梯度方向检查当前像素是否为其邻域内的局部最大值。如果不是,则将其抑制为零。这将删除不被视为边缘一部分的像素,只保留细线(候选边缘)。
4. 滞后阈值 (Hysteresis Thresholding)
这是最后一步。Canny 算法使用了两个阈值:上限(High Threshold)和下限(Low Threshold)。
- 如果像素梯度高于上限阈值,则接受该像素作为强边缘点。
- 如果像素梯度低于下限阈值,则拒绝该值(视为噪声)。
- 如果像素梯度介于两个阈值之间,则仅当它连接到高于上限阈值的像素时,才会被接受(弱边缘点)。否则也被拒绝。
Canny 建议上下限比例通常在 2:1 到 3:1 之间。
代码示例 (C++)
以下是基于 OpenCV 的完整 C++ 实现代码。该程序允许用户通过滑动条调整下限阈值,实时观察边缘检测效果。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
Mat src, src_gray;
Mat dst, detected_edges;
int lowThreshold = 0;
const max_lowThreshold = ;
ratio = ;
kernel_size = ;
* window_name = ;
{
(src_gray, detected_edges, (, ), );
(detected_edges, detected_edges, lowThreshold, lowThreshold * ratio, kernel_size);
dst = Scalar::();
src.(dst, detected_edges);
(window_name, dst);
}
{
(argc < ) {
cout << << argv[] << << endl;
;
}
src = (argv[], IMREAD_COLOR);
(src.()) {
cout << << endl;
;
}
(src, src_gray, COLOR_BGR2GRAY);
(window_name, WINDOW_AUTOSIZE);
(, window_name, &lowThreshold, max_lowThreshold, CannyThreshold);
(, );
();
;
}


