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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【OpenCV 】Sobel 导数/Laplace 算子/Canny 边缘检测

發布時間:2023/11/27 生活经验 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【OpenCV 】Sobel 导数/Laplace 算子/Canny 边缘检测 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

canny邊緣檢測見OpenCV 【七】————邊緣提取算子(圖像邊緣提取)——canny算法的原理及實現

?

1 Sobel 導數

1.1.1 原因

  1. 上面兩節我們已經學習了卷積操作。一個最重要的卷積運算就是導數的計算(或者近似計算).

  2. 為什么對圖像進行求導是重要的呢? 假設我們需要檢測圖像中的 邊緣 ,如下圖:

    你可以看到在 邊緣 ,相素值顯著的 改變 了。表示這一 改變 的一個方法是使用 導數 。 梯度值的大變預示著圖像中內容的顯著變化。

  3. 用更加形象的圖像來解釋,假設我們有一張一維圖形。下圖中灰度值的”躍升”表示邊緣的存在

  4. 使用一階微分求導我們可以更加清晰的看到邊緣”躍升”的存在(這里顯示為高峰值)

  5. 從上例中我們可以推論檢測邊緣可以通過定位梯度值大于鄰域的相素的方法找到(或者推廣到大于一個閥值).

1.1.2 原因

假設被作用圖像為 :

  1. 在兩個方向求導:

    1. 水平變化: 將 與一個奇數大小的內核 進行卷積。比如,當內核大小為3時, 的計算結果為:

    2. 垂直變化: 將:math:I 與一個奇數大小的內核 進行卷積。比如,當內核大小為3時, 的計算結果為:

  2. 在圖像的每一點,結合以上兩個結果求出近似 梯度:

    有時也用下面更簡單公式代替:

Note

?

當內核大小為 時, 以上Sobel內核可能產生比較明顯的誤差(畢竟,Sobel算子只是求取了導數的近似值)。 為解決這一問題,OpenCV提供了 Scharr 函數,但該函數僅作用于大小為3的內核。該函數的運算與Sobel函數一樣快,但結果卻更加精確,其內核為:

關于( Scharr )的更多信息請參考OpenCV文檔。在下面的示例代碼中,你會發現在 Sobel 函數調用的上面有被注釋掉的 Scharr 函數調用。 反注釋Scharr調用 (當然也要相應的注釋掉Sobel調用),看看該函數是如何工作的。

1.2 代碼

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
?
using namespace cv;
?
/** @function main */
int main(int argc, char** argv)
{
?Mat src, src_gray;Mat grad;char* window_name = "Sobel Demo - Simple Edge Detector";int scale = 1;int delta = 0;int ddepth = CV_16S;
?int c;
?/// 裝載圖像src = imread("C:\\Users\\guoqi\\Desktop\\ch7\\4.jpg", 1);
?if (!src.data){return -1;}
?GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);/// 轉換為灰度圖cvtColor(src, src_gray, CV_RGB2GRAY);/// 創建顯示窗口namedWindow(window_name, CV_WINDOW_AUTOSIZE);
?/// 創建 grad_x 和 grad_y 矩陣Mat grad_x, grad_y;Mat abs_grad_x, abs_grad_y;/// 求 X方向梯度//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );Sobel(src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT);convertScaleAbs(grad_x, abs_grad_x);//將中間結果轉換到 CV_8U:/// 求Y方向梯度//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );Sobel(src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT);convertScaleAbs(grad_y, abs_grad_y);
?/// 合并梯度(近似)addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);
?imshow(window_name, grad);waitKey(0);return 0;
}

?

1.3 實現結果

?

2 Laplace 算子

2.1 原理

  1. 前一節我們學習了 Sobel 算子 ,其基礎來自于一個事實,即在邊緣部分,像素值出現”跳躍“或者較大的變化。如果在此邊緣部分求取一階導數,你會看到極值的出現。正如下圖所示:

  2. 如果在邊緣部分求二階導數會出現什么情況?

    你會發現在一階導數的極值位置,二階導數為0。所以我們也可以用這個特點來作為檢測圖像邊緣的方法。 但是, 二階導數的0值不僅僅出現在邊緣(它們也可能出現在無意義的位置),但是我們可以過濾掉這些點。

Laplacian 算子

  1. 從以上分析中,我們推論二階導數可以用來 檢測邊緣 。 因為圖像是 “2維”, 我們需要在兩個方向求導。使用Laplacian算子將會使求導過程變得簡單。

  2. Laplacian 算子 的定義:

  1. OpenCV函數 Laplacian 實現了Laplacian算子。 實際上,由于 Laplacian使用了圖像梯度,它內部調用了 Sobel 算子。

Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );

函數接受了以下參數:

  • src_gray: 輸入圖像。

  • dst: 輸出圖像

  • ddepth: 輸出圖像的深度。 因為輸入圖像的深度是 CV_8U ,這里我們必須定義 ddepth = CV_16S 以避免外溢。

  • kernel_size: 內部調用的 Sobel算子的內核大小,此例中設置為3。

  • scale, deltaBORDER_DEFAULT: 使用默認值。

2.2 代碼

  • 裝載圖像

  • 使用高斯平滑消除噪聲, 將圖像轉換到灰度空間。

  • 使用Laplacian算子作用于灰度圖像,并保存輸出圖像。

  • 輸出結果。

    ?

    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>
    ?
    using namespace cv;
    ?
    /** @函數 main */
    int main( int argc, char** argv )
    {Mat src, src_gray, dst;int kernel_size = 3;int scale = 1;int delta = 0;int ddepth = CV_16S;char* window_name = "Laplace Demo";
    ?int c;
    ?/// 裝載圖像src = imread( argv[1] );
    ?if( !src.data ){ return -1; }
    ?/// 使用高斯濾波消除噪聲GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
    ?/// 轉換為灰度圖cvtColor( src, src_gray, CV_RGB2GRAY );
    ?/// 創建顯示窗口namedWindow( window_name, CV_WINDOW_AUTOSIZE );
    ?/// 使用Laplace函數Mat abs_dst;
    ?Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );convertScaleAbs( dst, abs_dst );
    ?/// 顯示結果imshow( window_name, abs_dst );
    ?waitKey(0);
    ?return 0;}

2.3 實現結果

3?Canny 邊緣檢測?

3.1代碼

#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;}

3.2?createTrackbar控制下的canny

總結

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

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