- 1. 函式定義
- 2. 工作原理
- 3. 示例程式碼
- 4. 實際應用
- 5. 注意事項
- 6. 輸出結果示例
cv::Canny()
是 OpenCV 中用於邊緣檢測的函式,基於 John F. Canny 於 1986 年提出的經典 Canny 邊緣檢測演算法。它是一種多階段邊緣檢測方法,能夠有效檢測出影像中的邊緣,同時減少噪聲和虛假邊緣。
1. 函式定義
void cv::Canny(
InputArray image, // 輸入影像(單通道,通常是灰度圖)
OutputArray edges, // 輸出影像,邊緣檢測結果
double threshold1, // 第一閾值,用於低閾值過濾
double threshold2, // 第二閾值,用於高閾值過濾
int apertureSize = 3, // Sobel 運算元核心大小,預設值為 3,必須為奇數
bool L2gradient = false // 是否使用更精確的 L2 範數計算梯度幅值,預設為 false(使用 L1 範數)
);
引數:
-
image
:輸入的單通道影像(通常是灰度圖)。如果輸入的是彩色影像,需要先轉換為灰度圖(例如使用cv::cvtColor()
)。 -
edges
:輸出的單通道影像,表示檢測到的邊緣。邊緣的畫素值是 0 或 255(非邊緣為 0,邊緣為 255)。 -
threshold1
和threshold2
threshold1
是低閾值,用於非最大值抑制。threshold2
是高閾值,用於邊緣連線。- 典型設定是
threshold1
較小,threshold2
較大(比如 50 和 150)。邊緣畫素梯度值高於threshold2
的點被認為是“強邊緣”,低於threshold1
的點被忽略,介於兩者之間的點只有與強邊緣連線時才被保留。
-
apertureSize
:Sobel 運算元核心的大小,用於計算影像梯度,必須是奇數且大於等於 3(如 3, 5, 7)。預設值為 3。 -
L2gradient
- 如果為
true
,梯度幅值使用 L2 範數(即 \(\sqrt{(G_x)^2 + (G_y)^2}\))。 - 如果為
false
,梯度幅值使用 L1 範數(即 \(|G_x| + |G_y|\))。 - L2 範數計算更精確,但也更耗時。
- 如果為
2. 工作原理
Canny 邊緣檢測主要包含以下步驟:
-
高斯平滑:對輸入影像進行高斯濾波,減少噪聲對邊緣檢測的影響。
-
計算梯度:使用 Sobel 運算元計算影像在水平方向 (\(G_x\)) 和垂直方向 (\(G_y\)) 的梯度,並透過梯度幅值和方向:
\[G = \sqrt{G_x^2 + G_y^2} \quad \text{或} \quad G = |G_x| + |G_y| \]\[\theta = \arctan\left(\frac{G_y}{G_x}\right) \] -
非最大值抑制 (NMS):對梯度幅值影像進行細化,僅保留區域性梯度幅值最大的畫素點。
-
雙閾值檢測:使用
threshold1
和threshold2
將畫素分類為:- 強邊緣:大於
threshold2
。 - 弱邊緣:介於
threshold1
和threshold2
之間。 - 非邊緣:小於
threshold1
。
- 強邊緣:大於
-
邊緣跟蹤:從強邊緣出發,連線與之相鄰的弱邊緣,形成完整邊緣。
3. 示例程式碼
#include <opencv2/opencv.hpp>
#include <iostream>
int main() {
// 讀取影像並轉換為灰度圖
cv::Mat src = cv::imread("example.jpg", cv::IMREAD_GRAYSCALE);
if (src.empty()) {
std::cerr << "Image not found!" << std::endl;
return -1;
}
// 輸出邊緣影像
cv::Mat edges;
// 應用 Canny 邊緣檢測
double lowThreshold = 50;
double highThreshold = 150;
int kernelSize = 3;
cv::Canny(src, edges, lowThreshold, highThreshold, kernelSize, true);
// 顯示結果
cv::imshow("Original Image", src);
cv::imshow("Canny Edges", edges);
cv::waitKey(0);
return 0;
}
4. 實際應用
-
特徵提取:邊緣檢測通常是許多計算機視覺任務的第一步,比如目標檢測、影像分割和物體識別。
-
輪廓檢測:使用
cv::Canny()
檢測邊緣後,可以結合cv::findContours()
提取影像中的輪廓。 -
影像匹配:邊緣檢測結果可以作為影像配準、影像拼接等任務的特徵。
5. 注意事項
-
噪聲敏感性:如果輸入影像噪聲較多,應先應用高斯濾波或雙邊濾波去噪,否則可能導致虛假邊緣。
-
閾值選擇:
threshold1
和threshold2
的選擇會顯著影響結果,可透過實驗調整,也可以結合 Otsu 方法自動計算閾值。 -
單通道輸入:
cv::Canny()
只能處理單通道影像,需預處理為灰度圖。
6. 輸出結果示例
如果輸入影像是自然影像(例如風景圖),cv::Canny()
輸出會是邊緣線條清晰的二值影像。透過合理調整閾值,可以控制邊緣的密集程度。