OpenCV(cv::Canny())

做梦当财神發表於2024-11-21

目錄
  • 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 範數)
);

引數:

  1. image:輸入的單通道影像(通常是灰度圖)。如果輸入的是彩色影像,需要先轉換為灰度圖(例如使用 cv::cvtColor())。

  2. edges:輸出的單通道影像,表示檢測到的邊緣。邊緣的畫素值是 0 或 255(非邊緣為 0,邊緣為 255)。

  3. threshold1threshold2

    • threshold1 是低閾值,用於非最大值抑制。
    • threshold2 是高閾值,用於邊緣連線。
    • 典型設定是 threshold1 較小,threshold2 較大(比如 50 和 150)。邊緣畫素梯度值高於 threshold2 的點被認為是“強邊緣”,低於 threshold1 的點被忽略,介於兩者之間的點只有與強邊緣連線時才被保留。
  4. apertureSize :Sobel 運算元核心的大小,用於計算影像梯度,必須是奇數且大於等於 3(如 3, 5, 7)。預設值為 3。

  5. L2gradient

    • 如果為 true,梯度幅值使用 L2 範數(即 \(\sqrt{(G_x)^2 + (G_y)^2}\))。
    • 如果為 false,梯度幅值使用 L1 範數(即 \(|G_x| + |G_y|\))。
    • L2 範數計算更精確,但也更耗時。


2. 工作原理

Canny 邊緣檢測主要包含以下步驟:

  1. 高斯平滑:對輸入影像進行高斯濾波,減少噪聲對邊緣檢測的影響。

  2. 計算梯度:使用 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) \]

  3. 非最大值抑制 (NMS):對梯度幅值影像進行細化,僅保留區域性梯度幅值最大的畫素點。

  4. 雙閾值檢測:使用 threshold1threshold2 將畫素分類為:

    • 強邊緣:大於 threshold2
    • 弱邊緣:介於 threshold1threshold2 之間。
    • 非邊緣:小於 threshold1
  5. 邊緣跟蹤:從強邊緣出發,連線與之相鄰的弱邊緣,形成完整邊緣。



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. 實際應用

  1. 特徵提取:邊緣檢測通常是許多計算機視覺任務的第一步,比如目標檢測、影像分割和物體識別。

  2. 輪廓檢測:使用 cv::Canny() 檢測邊緣後,可以結合 cv::findContours() 提取影像中的輪廓。

  3. 影像匹配:邊緣檢測結果可以作為影像配準、影像拼接等任務的特徵。



5. 注意事項

  1. 噪聲敏感性:如果輸入影像噪聲較多,應先應用高斯濾波或雙邊濾波去噪,否則可能導致虛假邊緣。

  2. 閾值選擇threshold1threshold2 的選擇會顯著影響結果,可透過實驗調整,也可以結合 Otsu 方法自動計算閾值。

  3. 單通道輸入cv::Canny() 只能處理單通道影像,需預處理為灰度圖。



6. 輸出結果示例

如果輸入影像是自然影像(例如風景圖),cv::Canny() 輸出會是邊緣線條清晰的二值影像。透過合理調整閾值,可以控制邊緣的密集程度。



相關文章