前言
本節將要介紹OpenCV 提供的三種不同的梯度濾波器,或者說高通濾波器:Sobel,Scharr 和 Laplacian。
總的來說:Sobel,Scharr 其實就是求一階或二階導數。Scharr 是對 Sobel(使用小的卷積核求解求解梯度角度時)的優化。而Laplacian 是求二階導數。
一、Sobel算子
其API如下:
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
函數返回其處理結果。
前四個是必須的參數:
第一個參數是需要處理的圖像;
第二個參數是圖像的深度,-1表示採用的是與原圖像相同的深度。目標圖像的深度必須大於等於原圖像的深度;
第三、四參數:dx和dy表示的是求導的階數,0表示這個方向上沒有求導,一般爲0、1、2。
其後是可選的參數:
dst不用解釋了;
ksize是Sobel算子的大小,必須爲1、3、5、7。
scale是縮放導數的比例常數,默認情況下沒有伸縮係數;
delta是一個可選的增量,將會加到最終的dst中,同樣,默認情況下沒有額外的值加到dst中;
borderType是判斷圖像邊界的模式。這個參數默認值爲cv2.BORDER_DEFAULT。
注意:第二個參數在代碼中通常使用的卻是 cv2.CV_16S,cv2.CV_64F。這是爲什麼呢?想象一下一個從黑到白的邊界的導數是整數,而一個從白到黑的邊界點導數卻是負數。如果原圖像的深度是np.int8 時,所有的負值都會被截斷變成 0,換句話說就是把把邊界丟失掉。所以如果這兩種邊界你都想檢測到,最好的的辦法就是將輸出的數據類型設置的更高,比如 cv2.CV_16S,cv2.CV_64F 等。取絕對值然後再把它轉回到 cv2.CV_8U。
import cv2
import numpy as np
filenames = '/longmao.png'
img = cv2.imread(filenames)
cv2.imshow('orginal',img)
#sobel處理
imgx = cv2.Sobel(img,cv2.CV_16S,1,0,ksize=3)
imgy = cv2.Sobel(img,cv2.CV_16S,0,1,ksize=3)
#轉回uint8
imgx_uint8 = cv2.convertScaleAbs(imgx)
imgy_uint8 = cv2.convertScaleAbs(imgy)
#x,y方向組合
img = cv2.addWeighted(imgx_uint8,0.5,imgy_uint8,0.5,0)
cv2.imshow('sobelimg',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
結果:
二、Scharr算子
基本和Sobel算子一樣,只是沒有了超參數ksize,使用固定的3*3ksize。
#scharr處理
sobelimgx = cv2.Scharr(img,cv2.CV_16S,1,0)
sobelimgy = cv2.Scharr(img,cv2.CV_16S,0,1)
三、Laplacian 算子
圖像中的邊緣區域,像素值會發生“跳躍”,對這些像素求導,在其一階導數在邊緣位置爲極值,這就是Sobel算子使用的原理——極值處就是邊緣。如下圖:
如果對像素值求二階導數,會發現邊緣處的導數值爲0。如下:
Laplace函數實現的方法是先用Sobel 算子計算二階x和y導數,再求和
#laplace處理
laplace = cv2.Laplacian(img,cv2.CV_16S,ksize=3)
#轉回uint8
laplace_img = cv2.convertScaleAbs(laplace)
結果: