日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV函数 Canny 检测边缘

發布時間:2025/4/16 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV函数 Canny 检测边缘 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
  • OpenCV函數?Canny?檢測邊緣.

原理

  • Canny 邊緣檢測算法?是 John F. Canny 于 1986年開發出來的一個多級邊緣檢測算法,也被很多人認為是邊緣檢測的?最優算法, 最優邊緣檢測的三個主要評價標準是:
    • 低錯誤率:?標識出盡可能多的實際邊緣,同時盡可能的減少噪聲產生的誤報。
    • 高定位性:?標識出的邊緣要與圖像中的實際邊緣盡可能接近。
    • 最小響應:?圖像中的邊緣只能標識一次。

    步驟

  • 消除噪聲。 使用高斯平滑濾波器卷積降噪。 下面顯示了一個??的高斯內核示例:

  • 計算梯度幅值和方向。 此處,按照Sobel濾波器的步驟:

  • 運用一對卷積陣列 (分別作用于??和??方向):

  • 使用下列公式計算梯度幅值和方向:

    梯度方向近似到四個可能角度之一(一般 0, 45, 90, 135)

  • 非極大值?抑制。 這一步排除非邊緣像素, 僅僅保留了一些細線條(候選邊緣)。

  • 滯后閾值: 最后一步,Canny 使用了滯后閾值,滯后閾值需要兩個閾值(高閾值和低閾值):

  • 如果某一像素位置的幅值超過?高?閾值, 該像素被保留為邊緣像素。
  • 如果某一像素位置的幅值小于?低?閾值, 該像素被排除。
  • 如果某一像素位置的幅值在兩個閾值之間,該像素僅僅在連接到一個高于?高?閾值的像素時被保留。
  • Canny 推薦的?高:低?閾值比在 2:1 到3:1之間。

  • 想要了解更多細節,你可以參考任何你喜歡的計算機視覺書籍。

  • 源碼

  • 本程序做什么?
    • 要求使用者輸入一個數字,設置?Canny Edge Detector?的低閾值 (通過trackbar)
    • 使用?Canny 邊緣檢測?產生一個?mask?(白線代表邊緣,黑色代表背景)。
    • 使用?mask?作為掩碼顯示原圖像。
  • 本教程的源碼如下,你也可以從?這里?下載
  • #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #include <stdlib.h> #include <stdio.h>using namespace cv;/// 全局變量Mat src, src_gray; Mat dst, detected_edges;int edgeThresh = 1; int lowThreshold; int const max_lowThreshold = 100; int ratio = 3; int kernel_size = 3; char* window_name = "Edge Map";/** * @函數 CannyThreshold * @簡介: trackbar 交互回調 - Canny閾值輸入比例1:3 */ void CannyThreshold(int, void*) {/// 使用 3x3內核降噪blur( src_gray, detected_edges, Size(3,3) );/// 運行Canny算子Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );/// 使用 Canny算子輸出邊緣作為掩碼顯示原圖像dst = Scalar::all(0);src.copyTo( dst, detected_edges);imshow( window_name, dst );}/** @函數 main */ int main( int argc, char** argv ) {/// 裝載圖像src = imread( argv[1] );if( !src.data ){ return -1; }/// 創建與src同類型和大小的矩陣(dst)dst.create( src.size(), src.type() );/// 原圖像轉換為灰度圖像cvtColor( src, src_gray, CV_BGR2GRAY );/// 創建顯示窗口namedWindow( window_name, CV_WINDOW_AUTOSIZE );/// 創建trackbarcreateTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );/// 顯示圖像CannyThreshold(0, 0);/// 等待用戶反應waitKey(0);return 0;}

    解釋

  • 創建程序中要用到的變量:

    Mat src, src_gray;Mat dst, detected_edges;int edgeThresh = 1;int lowThreshold;int const max_lowThreshold = 100;int ratio = 3;int kernel_size = 3;char* window_name = "Edge Map";注意:a. 我們首先設定高:低閾值比為 3:1 (通過變量 *ratio* ) b. 設定內核尺寸為 :math:`3` (Canny函數內部調用Sobel操作) c. 將低閾值的上限設定為 :math:`100`.
  • 裝載原圖像:

    /// 裝載圖像 src = imread( argv[1] );if( !src.data ){ return -1; }
  • 創建與?src?同類型和大小的矩陣(dst)

    dst.create( src.size(), src.type() );
  • 將輸入圖像轉換到灰度空間 (使用函數?cvtColor):

    cvtColor( src, src_gray, CV_BGR2GRAY );
  • 創建顯示窗口

    namedWindow( window_name, CV_WINDOW_AUTOSIZE );
  • 創建trackbar,來獲取用戶交互輸入的低閾值:

    createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );

    注意:

  • 通過trackbar控制的變量為?lowThreshold?,上限為?max_lowThreshold?(我們已經設定為100)
  • 每次用戶通過trackbar產生變動,回調函數?CannyThreshold?被調用.
  • 讓我們一步一步的來觀察?CannyThreshold?函數:

  • 首先, 使用 3x3的內核平滑圖像:

    blur( src_gray, detected_edges, Size(3,3) );
  • 其次,運用?Canny?尋找邊緣:

    Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );

    輸入參數:

    • detected_edges: 原灰度圖像
    • detected_edges: 輸出圖像 (支持原地計算,可為輸入圖像)
    • lowThreshold: 用戶通過 trackbar設定的值。
    • highThreshold: 設定為低閾值的3倍 (根據Canny算法的推薦)
    • kernel_size: 設定為 3 (Sobel內核大小,內部使用)
  • 填充?dst?圖像,填充值為0 (圖像全黑).

    dst = Scalar::all(0);
  • 最后, 使用函數?copyTo?標識被檢測到的邊緣部分 (背景為黑色).

    src.copyTo( dst, detected_edges);

    copyTo?將?src?圖像拷貝到?dst?. 但是,僅僅拷貝掩碼不為0的像素。既然Canny邊緣檢測的輸出是鑲嵌在黑色背景中的邊緣像素,因此其結果?dst圖像除了被檢測的邊緣像素,其余部分都為黑色。

  • 顯示結果:

    imshow( window_name, dst );
  • 結果

    • 在編譯上面的代碼之后, 我們可以運行結果,將圖片路徑輸入,如下圖:

    • 滑動標尺, 嘗試不同的閾值,我們得到如下結果:

    • 仔細觀察邊緣像素是如何疊加在黑色背景之上的。

    總結

    以上是生活随笔為你收集整理的OpenCV函数 Canny 检测边缘的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。