圖像梯度原理:簡單來說就是求導
OpenCV提供了三種不同的梯度濾波器,或者說高通濾波器:Sobel,Scharr和Laplacian。Sobel和Scharr是求一階或二階導數。Scharr是對Sobel(使用小的卷積核求解梯度角度時)的優化,Laplacian是求二階導數。
1.Sobel算子和Scharr算子
Sobel算子是高斯平滑與微分操作的結合體,它的抗噪音能力很好。可以設定求導的方向(xorder或yorder)。還可以設定使用的卷積核的大小(ksize),如果ksize=-1,會使用3x3的Scharr濾波器,效果會更好,若速度相同,在使用3x3濾波器時盡量使用Scharr。
3x3的Scharr濾波器卷積核如下:
X方向
| -3 | 0 | 3 |
| --- | --- | --- |
| -10 | 0 | 10 |
| -3 | 0 | 3 |
Y方向
| -3 | -10 | -3 |
| --- | --- | --- |
| 0 | 0 | 0 |
| 3 | 10 | 3 |
2.Laplacian算子
拉普拉斯算子可以使用二階導數的形式定義,可假設其離散實現類似于二階Sobel導數,事實上OpenCV在計算拉普拉斯算子時直接調用Sobel算子。
拉普拉斯濾波器使用的卷積核:

示例:用以上三種濾波器對同一幅圖像進行操作,卷積核使用為5x5。
~~~
import cv2
import numpy
from matplotlib import pyplot as plt
img = cv2.imread('1024.jpg',0)
laplacian = cv2.Laplacian(img,cv2.CV_64F)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
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()
~~~

**一個重要的事!**
當我們可以通過參數-1來設定輸出圖像的深度(數據類型)與原圖像保持一致,但是我們在代碼中使用的卻是cv2.CV_64F。這是為什么?想象一下一個從黑到白的邊界的導數是正數,而一個從白到黑的邊界的導數卻是負數。如果原圖像的深度是np.int8時,所有的負值都會被截斷變成0。換句話就是把邊界丟失掉。
所以如果這兩種邊界你都想檢測到,最好的辦法就是將輸出的數據類型設置的更高,比如cv2.CV_16S等,取絕對值然后再把它轉回到cv2.CV_8U。