原理
梯度簡單來說就是求導邻吭。OpenCV 提供了三種不同的梯度濾波器格嗅,或者說高通濾波器:Sobel,Scharr 和 Laplacian臭脓。我們會意義介紹他們酗钞。Sobel腹忽,Scharr 其實就是求一階或二階導數(shù)来累。Scharr 是對 Sobel(使用小的卷積核求解求解梯度角度時)的優(yōu)化。Laplacian 是求二階導數(shù)窘奏。
1.? Sobel 算子和 Scharr 算子
Sobel 算子是高斯平滑與微分操作的結(jié)合體嘹锁,所以它的抗噪聲能力很好。你可以設(shè)定求導的方向(xorder 或 yorder)着裹。還可以設(shè)定使用的卷積核的大辛旎(ksize)。如果 ksize=-1骇扇,會使用 3x3 的 Scharr 濾波器摔竿,它的的效果要比 3x3 的 Sobel 濾波器好(而且速度相同,所以在使用 3x3 濾波器時應(yīng)該盡量使用 Scharr 濾波器)少孝。3x3 的 Scharr 濾波器卷積核如下:
2.? Laplacian 算子
拉普拉斯算子可以使用二階導數(shù)的形式定義继低,可假設(shè)其離散實現(xiàn)類似于二階 Sobel 導數(shù),事實上稍走,OpenCV 在計算拉普拉斯算子時直接調(diào)用 Sobel 算子袁翁。計算公式如下:
拉普拉斯濾波器使用的卷積核:
下面的代碼分別使用以上三種濾波器對同一幅圖進行操作。使用的卷積核都是 5x5 的婿脸。
img = cv2.imread('opencv_logo.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()
一個重要的事!
在查看上面這個例子的注釋時不知道你有沒有注意到:當我們可以通過參數(shù) -1 來設(shè)定輸出圖像的深度(數(shù)據(jù)類型)與原圖像保持一致粱胜,但是我們在代碼中使用的卻是 cv2.CV_64F。這是為什么呢狐树?想象一下一個從黑到白的邊界的導數(shù)是整數(shù)焙压,而一個從白到黑的邊界點導數(shù)卻是負數(shù)。如果原圖像的深度是np.int8 時,所有的負值都會被截斷變成 0涯曲,換句話說就是把把邊界丟失掉答憔。所以如果這兩種邊界你都想檢測到,最好的的辦法就是將輸出的數(shù)據(jù)類型設(shè)置的更高掀抹,比如 cv2.CV_16S虐拓,cv2.CV_64F 等。取絕對值然后再把它轉(zhuǎn)回到 cv2.CV_8U傲武。下面的示例演示了輸出圖片的深度不同造成的不同效果蓉驹。
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)