首頁 > 軟體

python中的opencv 影象梯度

2022-06-01 22:01:08

影象梯度

影象梯度計算的是影象變化的速度。對於影象的邊緣部分,其灰度值變化較大,梯度值也較大;相反,對於影象中比較平滑的部分,其灰度值變化較小,相應的梯度值也較小。影象梯度計算需要求導數,但是影象梯度一般通過計算畫素值的差來得到梯度的近似值(近似導數值)。(差分,離散)

Sobel運算元、Scharr運算元和Laplacian運算元的使用。

Sobel理論基礎

Sobel運算元是一種離散的微分運算元,該運算元結合了高斯平滑和微分求導運算。該運算元利用區域性差分尋找邊緣,計算所得的是一個梯度的近似值。

濾波器通常是指由一幅影象根據畫素點(x, y)臨近的區域計算得到另外一幅新影象的演演算法。

濾波器是由鄰域及預定義的操作構成的,濾波器規定了濾波時所採用的形狀以及該區域內畫素值的組成規律。濾波器也被稱為“掩模”、“核”、“模板”、“視窗”、“運算元”等。一般訊號領域將其稱為“濾波器”,數學領域將其稱為“核”。

線性濾波器: 濾波的目標畫素點的值等於原始畫素值及其周圍畫素值的加權和。這種基於線性核的濾波,就是所熟悉的折積。

計算水平方向偏導數的近似值

將Sobel運算元與原始影象src進行折積計算,可以計算水平方向上的畫素值變化情況。

例如,當Sobel運算元的大小為3×3時,水平方向偏導數Gx的計算方式為:

計算垂直方向偏導數的近似值

當Sobel運算元的大小為3×3時,垂直方向偏導數Gy的計算方式為:

Sobel運算元及函數使用

使用函數cv2.Sobel()實現Sobel運算元運算,其語法形式為:

dst = cv2.Sobel( src, ddepth, dx, dy[, ksize[, scale[, delta[, borderType]]]] ) 
  • dst代表目標影象
  • src代表原始影象
  • ddepth代表輸出影象的深度

  • dx代表x方向上的求導階數。
  • dy代表y方向上的求導階數。
  • ksize代表Sobel核的大小。該值為-1時,則會使用Scharr運算元進行運算。
  • scale代表計算導數值時所採用的縮放因子,預設情況下該值是1,是沒有縮放的。
  • delta代表加在目標影象dst上的值,該值是可選的,預設為0。
  • borderType代表邊界樣式。

注意點:引數ddepth

在函數cv2.Sobel()的語法中規定,可以將函數cv2.Sobel()內ddepth引數的值設定為-1,讓處理結果與原始影象保持一致。但是,如果直接將引數ddepth的值設定為-1,在計算時得到的結果可能是錯誤的。

在實際操作中,計算梯度值可能會出現負數。如果處理的影象是8位元圖型別,則在ddepth的引數值為-1時,意味著指定運算結果也是8位元圖型別,那麼所有負數會自動截斷為0,發生資訊丟失。為了避免資訊丟失,在計算時要先使用更高的資料型別cv2.CV_64F,再通過取絕對值將其對映為cv2.CV_8U(8位元圖)型別。

通常要將函數cv2.Sobel()內引數ddepth的值設定為“cv2.CV_64F”。要將偏導數取絕對值,以保證偏導數總能正確地顯示出來。在OpenCV中,使用函數cv2.convertScaleAbs()對引數取絕對值,

該函數的語法格式為:

dst = cv2.convertScaleAbs( src [, alpha[, beta]] )
  • dst代表處理結果。
  • src代表原始影象。
  • alpha代表調節係數,該值是可選值,預設為1。
  • beta代表調節亮度值,該值是預設值,預設為0。

該函數的作用是將原始影象src轉換為256色點陣圖,其可以表示為:

dst=saturate(src*alpha+beta)

式中,saturate()表示計算結果的最大值是飽和值,例如: 當“src*alpha+beta”的值超過255時,其取值為255。

**例子:**使用函數cv2.convertScaleAbs()對一個亂陣列取絕對值。

import cv2
import numpy as np 
img=np.random.randint(-256,256, size=[4,5], dtype=np.int16)
rst=cv2.convertScaleAbs(img)
print("img=n", img)
print("rst=n", rst)

方向

在函數cv2.Sobel()中,引數dx表示x軸方向的求導階數,引數dy表示y軸方向的求導階數。引數dx和dy通常的值為0或者1,最大值為2。如果是0,表示在該方向上沒有求導。當然,引數dx和引數dy的值不能同時為0。

引數dx和引數dy可以有多種形式的組合,主要包含:

  • 計算x方向邊緣(梯度):dx=0, dy=1。
  • 計算y方向邊緣(梯度):dx=1, dy=0。
  • 引數dx與引數dy的值均為1:dx=1, dy=1。
  • 計算x方向和y方向的邊緣疊加:通過組合方式實現。

例子

“dx=1, dy=0”。當然,也可以設定為“dx=2, dy=0”。此時,會僅僅獲取垂直方向的邊緣資訊,

此時的語法格式為:

dst = cv2.Sobel( src , ddepth , 1 , 0 ) 

“dx=0, dy=1”。當然,也可以設定為“dx=0, dy=2”。此時,會僅僅獲取水平方向的邊緣資訊,

此時的語法格式為:

dst = cv2.Sobel( src , ddepth , 0 , 1 ) 

“dx=1, dy=1”,也可以設定為“dx=2, dy=2”,或者兩個引數都不為零的其他情況。此時,會獲取兩個方向的邊緣資訊,

此時的語法格式為:

dst = cv2.Sobel( src , ddepth , 1 , 1 )

計算x方向和y方向的邊緣疊加

如果想獲取x方向和y方向的邊緣疊加,需要分別獲取水平方向、垂直方向兩個方向的邊緣圖,然後將二者相加。

dx= cv2.Sobel( src , ddepth , 1 , 0 )
dy= cv2.Sobel( src , ddepth , 0 , 1 )
dst=cv2.addWeighted( src1 , alpha , src2 , beta , gamma )

例子:

使用函數cv2.Sobel()獲取影象水平方向的完整邊緣資訊

將引數ddepth的值設定為cv2.CV_64F,並使用函數cv2.convertScaleAbs()對cv2.Sobel()的計算結果取絕對值。

import cv2
o = cv2.imread('Sobel4.bmp', cv2.IMREAD_GRAYSCALE)
Sobelx = cv2.Sobel(o, cv2.CV_64F,0,1)
Sobelx = cv2.convertScaleAbs(Sobelx)
cv2.imshow("original", o)
cv2.imshow("x", Sobelx)
cv2.waitKey()
cv2.destroyAllWindows()

計算函數cv2.Sobel()在水平、垂直兩個方向疊加的邊緣資訊。

import cv2
o = cv2.imread('Sobel4.bmp', cv2.IMREAD_GRAYSCALE)
Sobelx = cv2.Sobel(o, cv2.CV_64F,1,0)
Sobely = cv2.Sobel(o, cv2.CV_64F,0,1)
Sobelx = cv2.convertScaleAbs(Sobelx)
Sobely = cv2.convertScaleAbs(Sobely)
Sobelxy =  cv2.addWeighted(Sobelx,0.5, Sobely,0.5,0)
cv2.imshow("original", o)
cv2.imshow("xy", Sobelxy)
cv2.waitKey()
cv2.destroyAllWindows()

Scharr運算元及函數使用

在離散的空間上,有很多方法可以用來計算近似導數,在使用3×3的Sobel運算元時,可能計算結果並不太精準。

OpenCV提供了Scharr運算元,該運算元具有和Sobel運算元同樣的速度,且精度更高。

可以將Scharr運算元看作對Sobel運算元的改進,其核通常為:

OpenCV提供了函數cv2.Scharr()來計算Scharr運算元,其語法格式如下:

dst = cv2.Scharr( src, ddepth, dx, dy[, scale[, delta[, borderType]]] ) 
  • dst代表輸出影象。
  • src代表原始影象。
  • ddepth代表輸出影象深度。該值與函數cv2.Sobel()中的引數ddepth的含義相同
  • dx代表x方向上的導數階數。
  • dy代表y方向上的導數階數。
  • scale代表計算導數值時的縮放因子,該項是可選項,預設值是1,表示沒有縮放。
  • delta代表加到目標影象上的亮度值,該項是可選項,預設值為0。
  • borderType代表邊界樣式。

在函數cv2.Sobel()中,如果ksize=-1,則會使用Scharr濾波器。

如下語句:

dst=cv2.Scharr(src, ddepth, dx, dy)

dst=cv2.Sobel(src, ddepth, dx, dy, -1)

是等價的。函數cv2.Scharr()和函數cv2.Sobel()的使用方式基本一致。引數ddepth的值應該設定為“cv2.CV_64F”,並對函數cv2.Scharr()的計算結果取絕對值,才能保證得到正確的處理結果。

具體語句為:

dst=Scharr(src, cv2.CV_64F, dx, dy)
dst= cv2.convertScaleAbs(dst)

在函數cv2.Scharr()中,要求引數dx和dy滿足條件:

  • dx >= 0 && dy >= 0 && dx+dy == 1
  • 和Sobel 不同, Scharr 的dx+dy 必須為1

引數dx和引數dy的組合形式有:

  • 計算x方向邊緣(梯度):dx=0, dy=1。
  • 計算y方向邊緣(梯度): dx=1, dy=0。
  • 計算x方向與y方向的邊緣疊加:通過組合方式實現。

例子

計算x方向邊緣(梯度):dx=1, dy=0

dst=Scharr(src, ddpeth, dx=1, dy=0) 

計算y方向邊緣(梯度):dx=0, dy=1

dst=Scharr(src, ddpeth, dx=0, dy=1)

計算x方向與y方向的邊緣疊加

將兩個方向的邊緣相加

dx=Scharr(src, ddpeth, dx=1, dy=0) 
dy=Scharr(src, ddpeth, dx=0, dy=1)
Scharrxy=cv2.addWeighted(dx,0.5, dy,0.5,0)

引數dx和dy的值不能都為1

Sobel運算元和Scharr運算元的比較

Sobel運算元的缺點是,當其核結構較小時,精確度不高,而Scharr運算元具有更高的精度。

Sobel運算元和Scharr運算元的核結構:

Laplacian運算元及函數使用

Laplacian(拉普拉斯)運算元是一種二階導數運算元,其具有旋轉不變性,可以滿足不同方向的影象邊緣銳化(邊緣檢測)的要求。

通常情況下,其運算元的係數之和需要為零。

一個3×3大小的Laplacian運算元

Laplacian運算元類似二階Sobel導數,需要計算兩個方向的梯度值。

計算結果的值可能為正數,也可能為負數。所以,需要對計算結果取絕對值,以保證後續運算和顯示都是正確的。

在OpenCV內使用函數cv2.Laplacian()實現Laplacian運算元的計算,該函數的語法格式為:

dst = cv2.Laplacian( src, ddepth[, ksize[, scale[, delta[, borderType]]]] ) 
  • dst代表目標影象。
  • src代表原始影象。
  • ddepth代表目標影象的深度。
  • ksize代表用於計算二階導數的核尺寸大小。該值必須是正的奇數。
  • scale代表計算Laplacian值的縮放比例因子,該引數是可選的。預設情況下,該值為1,表示不進行縮放。
  • delta代表加到目標影象上的可選值,預設為0。
  • borderType代表邊界樣式。

該函數分別對x、y方向進行二次求導,具體為:

上式是當ksize的值大於1時的情況。當ksize的值為1時,Laplacian運算元計算時採用的3×3的核如下:

通過從影象內減去它的Laplacian影象,可以增強影象的對比度,此時其運算元為:

例子: 使用函數cv2.Laplacian()計算影象的邊緣資訊。

import cv2
o = cv2.imread('Laplacian.bmp', cv2.IMREAD_GRAYSCALE)
Laplacian = cv2.Laplacian(o, cv2.CV_64F)
Laplacian = cv2.convertScaleAbs(Laplacian)
cv2.imshow("original", o)
cv2.imshow("Laplacian", Laplacian)
cv2.waitKey()
cv2.destroyAllWindows()

運算元總結

Sobel運算元、Scharr運算元、Laplacian運算元都可以用作邊緣檢測

Sobel運算元和Scharr運算元計算的都是一階近似導數的值。通常情況下,可以將它們表示為:

  • Sobel運算元= |左-右| 或 |下-上|
  • Scharr運算元=|左-右| 或 |下-上|

Laplacian運算元計算的是二階近似導數值,可以將它表示為:

  • Laplacian運算元=|中-左| + |中-右| + |中-下| + |中-上|

到此這篇關於python中的opencv 影象梯度的文章就介紹到這了,更多相關python opencv 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com