OpenCV學習筆記(10)——圖像梯度


  • 學習圖像梯度,圖像邊界等

  梯度簡單來說就是求導。

  OpenCV提供了三種不同的梯度濾波器,或者說高通濾波器:Sobel,Scharr和Lapacian。Sobel,Scharr其實就是求一階或二階導。Scharr是對Sobel的部分優化。Laplacian是求二階導。

  

1.Sobel算子和Scharr算子

  Sobel算子是高斯平滑和微分操作的結合體,所以他的抗噪聲能力很好。你可以設定求導的方向(xorder 或 yorder)。還可以設定使用的卷積核大小(ksize)。當ksize=-1時,會使用3*3 的Scharr濾波器,他的效果要比3*3的Sobel濾波器好,而且速度相同,所以在使用3*3濾波器時應該盡量使用Scharr濾波器(一般就用Sobel算子即可)。3*3 的 Scharr濾波器卷積核如下所示:

  

2.Laplacian算子

  拉普拉斯算子可以使用二階導數的形式定義,可假設其離散實現類似於二階Sobel導數。事實上,OpenCV在計算拉普拉斯算子時直接調用Sobel算子,具體計算公式如下:

  

  拉普拉斯濾波器使用的卷積核: 

  

下面的例程將展示三種濾波器對同一副圖像進行操作產生的效果,其使用的卷積核大小都是5*5的


import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('7.png',0)


laplacian = cv2.Laplacian(img,cv2.CV_64F)#注意這里的depth參數!
#cv2.CV_64F 輸出圖像的深度(數據類型),可以使用-1,與原圖像保持一致

sobelx = cv2.Sobel(img, cv2.CV_64F,1,0,ksize=5)
#參數1,0表示在x方向求一階導數,最大可以求2階導數

sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
#同理0,1表示在y方向求一階導數,最大可以求二階導數

plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()

書上的例圖更為明顯的表現出區別:

 

這里解釋為什么要用cv2.CV_64F,當使用-1(或者cv2.CV_8U)(與原圖深度(數據類型)保持一致)時,輸出的圖像如下

 laplacian   sobelx

 

想象一下一個從黑到白的邊界的導數し整數,而一個從白到黑的邊界點的導數卻是負數。如果原圖像的深度是np.int8時,所有的負值都會截斷成為0,換句話說就是把邊界丟失掉了。因此如果想把兩種邊界都檢測到,最好的辦法就是將輸出的數據類型設置到更高,如cv2.CV_16S,cv2.CV_64F等,取絕對值然后再把它轉回到cv2.CV_8U(即把本來為負的部分轉為正的,在轉回uint8便可以顯示)

  

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM