1. Sobel 算子:通過計算區域差分尋找邊緣,計算得到一個梯度的近似值,
濾波器(核):由一幅影像根據像素點(x,y)臨近的區域計算得到另外一張影像的演算法,濾波的目標像素的值等于原始像素及其周圍像素的加權和,這種基于線性核的濾波,就是卷積,
1. 計算水平方向偏導數的近似值

計算公式為:P5的水平方向偏導數 = (P3-P1) + 2(P6-P4) + (P9-P7) 為了避免計算出負數造成資訊丟失,需要時取絕對值,
計算程序為:最左邊的像素值 - 最右邊的像素值,但是中間一行的權重是最高的,乘以2,
2. 計算垂直方向的偏導數的近似值:
與上面唯一不同的是:1. 最下面的像素值 - 最上面的像素值,中間一行的權重是最高的,乘以2,
3. 算子介紹: dst=cv2.Sobel(src,outputImgDepth,dx,dy)
示例代碼:X方向Sobel處理
import cv2
o = cv2.imread('sobel4.bmp',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(o,-1,1,0) # 1,0表示X方向,反之0,1表示Y方向
cv2.imshow("original",o)
cv2.imshow("x",sobelx)
cv2.waitKey()
cv2.destroyAllWindows()
運行:

上面的結果可以看到,只能計算出255到0過渡的邊緣,但是如果需要得到兩條邊緣,就需要取絕對值,將-255轉化為255
需要用到convertScaleAbs函式轉成絕對值,
import cv2
o = cv2.imread('sobel4.bmp',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(o,cv2.CV_64F,1,0)
sobelx = cv2.convertScaleAbs(sobelx) # 轉回uint8
cv2.imshow("original",o)
cv2.imshow("x",sobelx)
cv2.waitKey()
cv2.destroyAllWindows()
運行:

上面只是X方向的,Y方向一樣,只要將Sobel函式中的xy調換順序即可,但是如果需要得到xy兩個方向的疊加邊緣,就需要使用addWeighted函式實作疊加,
示例代碼:
import cv2
o = cv2.imread('sobel4.bmp',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(o,cv2.CV_64F,1,0) # 先找x方向邊緣
sobely = cv2.Sobel(o,cv2.CV_64F,0,1) # 再找y方向邊緣
sobelx = cv2.convertScaleAbs(sobelx) # 轉回uint8
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0) #疊加邊緣(src1,src1Weighted,src2,src2Weighted,0)
cv2.imshow("original",o)
cv2.imshow("xy",sobelxy)
cv2.waitKey()
cv2.destroyAllWindows()
運行:

影像示例:
import cv2
a=cv2.imread("./gril.png",cv2.IMREAD_GRAYSCALE)
sobel=cv2.Sobel(a,-1,1,0)
sobelx=cv2.Sobel(a,cv2.CV_64F,1,0)
sobely=cv2.Sobel(a,cv2.CV_64F,0,1)
abs_sobelx=cv2.convertScaleAbs(sobelx)
abs_sobely=cv2.convertScaleAbs(sobely)
abs_sobelxy=cv2.addWeighted(abs_sobelx,1,abs_sobely,1,0) # 1= weighted
cv2.imshow("src",a)
cv2.imshow("abs_sobelx",abs_sobelx)
cv2.imshow("abs_sobely",abs_sobely)
cv2.imshow("both xy",abs_sobelxy)
cv2.waitKey()
cv2.destroyAllWindows()
運行:

2. Scharr算子:
用法和Sobel基本一致,唯一的區別就是卷積核不同,Scharr的細節更加豐富,精度更高,另外Scharr算子xy不能同時為1,否則會報例外,

下面示例將Sobel核Scharr算子做了比較:
import cv2
o = cv2.imread('lena.bmp',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(o,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(o,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx) # 轉回uint8
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
scharrx = cv2.Scharr(o,cv2.CV_64F,1,0)
scharry = cv2.Scharr(o,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx) # 轉回uint8
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
cv2.imshow("original",o)
cv2.imshow("sobelxy",sobelxy)
cv2.imshow("scharrxy",scharrxy)
cv2.waitKey()
cv2.destroyAllWindows()
運行:

3. Laplacian(拉普拉斯)算子:
類似于二階Sobel導數,需要計算兩個方向的梯度值,計算方式:P5 = (P2+P4+P6+P8) - 4 * P5,同樣需要取絕對值,

三種算子對比示例:
import cv2
o = cv2.imread('lena.bmp',cv2.IMREAD_GRAYSCALE)
# Sobel
sobelx = cv2.Sobel(o,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(o,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx) # 轉回uint8
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
# Scharr
scharrx = cv2.Scharr(o,cv2.CV_64F,1,0)
scharry = cv2.Scharr(o,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx) # 轉回uint8
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
# Laplacion
lap = cv2.Laplacian(o,cv2.CV_64F)
lapxy = cv2.convertScaleAbs(lap) # 轉回uint8
cv2.imshow("original",o)
cv2.imshow("sobelxy",sobelxy)
cv2.imshow("scharrxy",scharrxy)
cv2.imshow("lapxy",lapxy)
cv2.waitKey()
cv2.destroyAllWindows()
運行:

4. 總結:
Sobel 和 Scharr 算子都是分xy方向的,Scharr 的加權值比 Sobel 高,所以相鄰區域的像素值對其影響較大,但是同時細節更豐富,精度高,
Laplacian算子不分xy,對噪聲比較敏感,對邊緣也敏感,
OVER…
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290761.html
標籤:其他
上一篇:Python 深度學習AI - 利用訓練好的模型庫進行影像分割、一鍵摳圖實體演示,百度深度學習平臺飛漿paddlepaddle-gpu的安裝與使用
下一篇:計算機視覺中的注意力機制理解
