圖像邊緣檢測概論

一、概論

下面將學習opencv中邊緣檢測的各種算子和濾波器:

包括canny算子,sobel算子,scharr算子。

什麼叫做邊緣檢測呢?

邊緣檢測的目標是標識數字圖像中亮度變化明顯的點。圖像屬性中的顯著變化通常反應了屬性的重要事件和變化,包括:

(1) 、深度上的不連續

(2) 、表面方向的不連續

(3) 、物質屬性變化

(4) 、場景照明變化

邊緣檢測剔除了大量認爲與圖像特徵不相關的數據,只保留了圖像中較爲重要的屬性。邊緣檢測和視角有關,視角不一樣,邊緣檢測的結果就不一樣。

檢測方法:

許多邊緣檢測的方法,可以分爲兩類:基於搜索和基於零交叉

    對於基於搜索的邊緣檢測,首先計算邊緣強度,通常用一階導數表示,用計算值估計邊緣的局部方向。

    對於零交叉的方法,是找到由圖像得到的二階導數的零交叉點來定位邊緣。

   許多邊緣檢測的方法依賴於圖像梯度的計算,用不同種類的濾波器來估計x方向和y方向的梯度。

   計算一階導數:許多邊緣檢測都是基於高亮的一階導數,這樣就可以得到原始圖像亮度的梯度。用這個梯度我們可以在圖像的亮度梯度中尋找峯值,我們用l(x)表示點x的亮度,l’(x)表示點x的一階導數(亮度梯度),我們可以用下面的方法來計算亮梯度:

 

 

   計算二階導數:其他的邊緣檢測操作如基於亮度的二階導數,這在數學上就是求一階導數的變化率,也就是圖像亮度的變化率,在二階導數中檢測過零點將得到梯度中的最大值,在二階導數中的峯值檢測是邊線檢測,邊線是雙重邊緣,這樣我們就可以在邊緣的一邊看到一個亮度梯度,在另一邊看到相反的梯度,這樣如果圖像中有邊線出現的話,我們就能在亮度梯度上看到非常大的變化,我們可以通過在二階導數中尋找過零點來尋找邊線。我們用I(x)來表示點x的亮度,I``(x)表示點x的亮度的二階導數,那麼可以這樣計算:

 

 

 

所以,下面介紹邊緣檢測的一般步驟 :

(1) 、濾波:邊緣檢測算法是基於圖像亮度的一階導數和二階導數,但是導數的計算對噪聲很敏感,所以需要濾波器來改善圖像,但是我們需要注意,大多數濾波器都會在降低噪聲的同時導致邊緣強度的減弱。

(2) 、增強:增強邊緣的基礎是確定圖像各個點的鄰域強度的變化值,可以將鄰域強度值有顯著變化的點突出出來,便於安裝增強一般是通過計算梯度幅度來完成的。

(3) 、檢測:在圖像中有許多點的梯度幅度比較大,但是不都是我們需要的邊緣,所以應該檢測哪些點是邊緣,可以通過設定梯度幅度閾值來檢測。

(4) 、定位:確定邊緣位置,但是大多數應用只需要指出邊緣出現在圖像的哪些區域,不需要指出圖像邊緣的精確位置或者方向。

 

二、幾種邊緣檢測算子

 1、canny算子

   特點:

   (1)、低錯誤率:標識出儘可能多的實際邊緣,同時儘可能的減少噪聲產生的干擾

   (2)、高定位性:標誌出的邊緣和圖像中的邊緣儘可能的接近

  (3)、最小響應:圖像中的邊緣只能標誌一次,並且可能存在的噪聲不應該標誌爲邊緣

 

Canny邊緣檢測的步驟:

(1)、消除噪聲:可以使用高斯平滑濾波器卷積降噪

(2)、計算梯度幅值和方向

<1>、運用一對卷積陣列(分別作用於x方向和y方向)

 

     

     <2>、使用下面的公式計算梯度幅值和方向

 

 

梯度方向將近似到四個可能的角度:0,45,90,135

 

(3)、非極大值抑制:僅僅保留了一些有可能是邊緣的線條

(4)、滯後閾值:這是最後一步,滯後閾值需要兩個閾值,一個高閾值一個低閾值

  <1>、如果某一像素的幅值超過高閾值,保留

  <2>、如果小於低閾值,不保留

  <3>、在中間,只有當這個像素連接到一個高於高閾值的像素時才保留

----------高低閾值比大概應該在<2:1 or 3:1>--------

 

(5)、函數詳解:

```

void Canny(InputArray image,OutputArray edges, double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false )

```

· 第一個參數,InputArray類型的image,輸入圖像,即源圖像,填Mat類的對象即可,且需爲單通道8位圖像。

· 第二個參數,OutputArray類型的edges,輸出的邊緣圖,需要和源圖片有一樣的尺寸和類型。

· 第三個參數,double類型的threshold1,第一個滯後性閾值。

· 第四個參數,double類型的threshold2,第二個滯後性閾值。

· 第五個參數,int類型的apertureSize,表示應用Sobel算子的孔徑大小,其有默認值3。

· 第六個參數,bool類型的L2gradient,一個計算圖像梯度幅值的標識,有默認值false。

 

2 、sobel算子

   (1)、分別在x和y兩個方向求導

      <1>、水平變化,用I與一個奇數大小的內核做卷積,比如當內核大小爲3x3時,可以這樣就算Gx:

      <2>、垂直變化,用I與一個奇數大小的內核做卷積,比如當內核大小爲3x3時,可以這樣計算Gy:

 

 

 

 

   (2)、在圖像的每一個點,結合上面兩個方向上的計算結果求出近似梯度:

也可以使用更簡單的公式來計算:

 

   (2)、函數詳解:

void Sobel (

InputArray src,//輸入圖

 OutputArray dst,//輸出圖

 int ddepth,//輸出圖像的深度

 int dx,

 int dy,

 int ksize=3,

 double scale=1,

 double delta=0,

 int borderType=BORDER_DEFAULT );

 

· 第一個參數,InputArray 類型的src,爲輸入圖像,填Mat類型即可。

· 第二個參數,OutputArray類型的dst,即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。

· 第三個參數,int類型的ddepth,輸出圖像的深度,支持如下src.depth()和ddepth的組合:

o 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F

o 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_64F, 取ddepth = -1/CV_64F

· 第四個參數,int類型dx,x 方向上的差分階數。

· 第五個參數,int類型dy,y方向上的差分階數。

· 第六個參數,int類型ksize,有默認值3,表示Sobel核的大小;必須取1,3,5或7。

· 第七個參數,double類型的scale,計算導數值時可選的縮放因子,默認值是1,表示默認情況下是沒有應用縮放的。我們可以在文檔中查閱getDerivKernels的相關介紹,來得到這個參數的更多信息。

· 第八個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。

· 第九個參數, int類型的borderType,我們的老朋友了(萬年是最後一個參數),邊界模式,默認值爲BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate處得到更詳細的信息。

 

3、laplace算子

 

定義:

 

函數詳解:

 void Laplacian(InputArray src,OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, intborderType=BORDER_DEFAULT );

· 第一個參數,InputArray類型的image,輸入圖像,即源圖像,填Mat類的對象即可,且需爲單通道8位圖像。

· 第二個參數,OutputArray類型的edges,輸出的邊緣圖,需要和源圖片有一樣的尺寸和通道數。

· 第三個參數,int類型的ddept,目標圖像的深度。

· 第四個參數,int類型的ksize,用於計算二階導數的濾波器的孔徑尺寸,大小必須爲正奇數,且有默認值1。

· 第五個參數,double類型的scale,計算拉普拉斯值的時候可選的比例因子,有默認值1。

· 第六個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。

· 第七個參數, int類型的borderType,邊界模式,默認值爲BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate()處得到更詳細的信息。

 

  4、濾波器

void Scharr(

InputArray src, //源圖

 OutputArray dst, //目標圖

 int ddepth,//圖像深度

 int dx,// x方向上的差分階數

 int dy,//y方向上的差分階數

 double scale=1,//縮放因子

 double delta=0,// delta值

 intborderType=BORDER_DEFAULT )// 邊界模式

 

· 第一個參數,InputArray 類型的src,爲輸入圖像,填Mat類型即可。

· 第二個參數,OutputArray類型的dst,即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。

· 第三個參數,int類型的ddepth,輸出圖像的深度,支持如下src.depth()和ddepth的組合:

o 若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F

o 若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F

o 若src.depth() = CV_64F, 取ddepth = -1/CV_64F

· 第四個參數,int類型dx,x方向上的差分階數。

· 第五個參數,int類型dy,y方向上的差分階數。

· 第六個參數,double類型的scale,計算導數值時可選的縮放因子,默認值是1,表示默認情況下是沒有應用縮放的。我們可以在文檔中查閱getDerivKernels的相關介紹,來得到這個參數的更多信息。

· 第七個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。

· 第八個參數, int類型的borderType,我們的老朋友了(萬年是最後一個參數),邊界模式,默認值爲BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate處得到更詳細的信息。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章