基於Python的Opencv學習

基於Python的Opencv學習第十天

今天爲大家介紹一下圖像梯度的相關知識,先來看一下soble算子的內容。

一.sobel算子

1.sobel算子的理論基礎
sobel可以理解爲計算不同方向的梯度。如圖,我們可以採用中間的卷積核與原圖像進行相乘,從而可以得到x方向的梯度。
在這裏插入圖片描述
在這裏,P5的x方向的梯度值可以用如下算式表示:

P5x=(p3-p1)+2×(p6-p4)+(p9-p7)

這裏因爲P4和P6兩個值距離P5較近,所以提高比例爲2。其實計算水平方向梯度就是選取卷積核右邊的一列數減去左邊的一列數,從而得到水平方向的梯度,也即是水平方向的sobel算子。

至於垂直方向的邊界,同水平方向,如圖:
在這裏插入圖片描述
在這裏,P5的y方向的梯度值可以用如下算式表示:

P5y=(p7-p1)+2×(p8-p2)+(p9-p3)

至於解釋和水平方向的解釋相同。
分別得到兩個方向的梯度值後,我們通過平方開根號運算得到P5點的近似梯度值
在這裏插入圖片描述
但爲了方便計算,得到簡化版本:
在這裏插入圖片描述
以P5點爲例,其sobel算子的梯度值爲:

P5sobel=|p5x|+|p5y|
這樣就可以得到某一點的梯度值。

2.sobel算子的函數
在opencv中提供寫好的soble()函數來進行梯度運算,具體語法如下:

dst=cv2.Sobel(src,ddepth,dx,dy,[ksize])

這裏參數解釋如下:

ddepth:處理結果的圖像深度

通常情況下,將該參數的值設置爲-1,讓處理結果與原圖像保持一致。但在soble算子計算梯度時候需要做一點變化。
在這裏插入圖片描述
如圖所示,A和B兩條邊界左右像素點的值不同(256色位圖中,白色點像素值爲255,黑色點像素值爲0),在求x軸方向的sobel算子時候,其右側像素值和左側像素值的差值不爲零,是邊界。但在其他列中,右側像素值與左側像素值的差值均爲零,不是邊界,這就是sobel的具體解釋。

但我們在計算A邊界時候,右側值爲0,左側值爲255,差值爲負數,在圖像深度設爲-1時,我們得到結果會把負值取爲0,就得不到想要的結果,這時,我們需要填上另外一個更高的數據類型cv2.CV_64F,取絕對值後,再轉換爲np.uint8(cv2.CV_8U)類型。

來看另一個函數cv2.convertScaleAbs(src,[,alpha[,betal]])這個作用是將原始圖像src轉換爲256色位圖(即給負數值取絕對值,從而不會在np.uint8類型中直接截斷取0。這個函數還可以直接調整爲:

dst=cv2.convertScaleAbs(原始圖像)

dx:計算x軸方向的邊界
dy:計算y軸方向的邊界

計算x方向梯度:【dx=1,dy=0】
計算y方向梯度:【dx=0,dy=1】

在計算sobel結果時候,我們有兩種方法:
在這裏插入圖片描述
一般是採用方式2,待會會在代碼演示中看出來結果。

利用方式2計算dst時候,我們並不需要直接相加,而是通過cv2.addWeighted(src1,alpha,src2,beta,gamma)來實現計算兩幅圖像的權重和。具體語法如下:

dst=cv2.addWeighted(src1,alpha,src2,beta,gamma)

參數含義是:
src1:原圖像1
alpha:原圖像1需要採用的比重
src2:原圖像2
beta:原圖像2需要採用的比重
gamma:修正值(一般取0,不做修正)
示例:dst=cv2.addWeighted(src1,0.5,src2,0.5,0)

ksize:核大小(一般這個參數不用,opencv默認設置爲3(三行三列),如果需要用的話,需要給這個參數設置爲奇數)
來看代碼和結果:

import cv2
import numpy as np
a=cv2.imread(r"C:\Users\LT010407\Desktop\lena.jpg")
sobelx=cv2.Sobel(a,cv2.CV_64F,1,0)
sobely=cv2.Sobel(a,cv2.CV_64F,0,1)
sobelx=cv2.convertScaleAbs(sobelx)
sobely=cv2.convertScaleAbs(sobely)
sobelxy=cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
sobel11=cv2.Sobel(a,cv2.CV_64F,1,1)
cv2.imshow("a",a)
cv2.imshow("soblex",sobelx)
cv2.imshow("sobley",sobely)
cv2.imshow("soblexy",sobelxy)
cv2.imshow("soble11",sobel11)

在這裏插入圖片描述
這裏分別得到了x軸方向和y軸方向的sobel梯度的圖像
在這裏插入圖片描述
這是採用兩種不同方法得到的結果,可以看出採用方式2得到的纔是正確的結果。

二.scharr算子及其函數

在使用33的sobel算子時,可能結果不太準確,所以需要使用scharr算子,這樣效果更好。這幅圖是scharr算子在計算x軸和y軸方向的梯度時候33卷積核的係數,可以看到這裏係數與sobel算子的係數不同,得到的邊界的結果更準確。(x軸方向是右邊像素值減去左邊像素值,y軸方向是下邊像素值減去上邊像素值)運算和sobel算子相同。
在這裏插入圖片描述
在這裏插入圖片描述
這裏我們可以看到兩種算子的係數不同。sobel算子和scharr算子的運算強度和運算速度是一樣的,但是scharr算子進行的運算結果更準確。

Scharr()函數

在使用scharr算子進行梯度運算時,需要使用scharr()函數。

dst=Scharr(src,ddpeth,dx,dy)

這裏相關參數和Sobel()函數一致,不做贅述。

同樣在處理圖像深度時,還需要用cv2.CV_64F參數:

dst=Scharr(src,cv2.CV_64F,dx,dy)
dst=cv2.convertScaleAbs(dst)

注意:dx,dy需要滿足條件:
dx>=0&&dy>=0&&dx+dy==1

這裏注意的就是dx與dy的值加起來需要等於1。

示例:dst=Scharr(src,ddpeth,dx=1,dy=0)
dst=Scharr(src,ddpeth,dx=0,dy=1)
不能參與形式爲:
dst=Scharr(src,ddpeth,dx=1,dy=1)

分別得到x軸方向和y軸方向兩個方向的梯度值之後,我們繼續使用addWeighted()函數給兩個方向的梯度值加起來。

Scharr是對Sobel算子的改進,所以我們可以在Sobel算子裏面修改參數來得到和Scharr算子一致的效果:
在這裏插入圖片描述

import cv2
import numpy as np
a=cv2.imread(r"C:\Users\LT010407\Desktop\lena.jpg")
scharrx=cv2.Scharr(a,cv2.CV_64F,1,0)
scharry=cv2.Scharr(a,cv2.CV_64F,0,1)
scharrx=cv2.convertScaleAbs(scharrx)
scharry=cv2.convertScaleAbs(scharry)
scharrxy=cv2.addWeighted(scharrx,0.5,scharry,0.5,0)

cv2.imshow("a",a)
cv2.imshow("scharrx",scharrx)
cv2.imshow("scharry",scharry)
cv2.imshow("scharrxy",scharrxy)

在這裏插入圖片描述
在這裏插入圖片描述
這裏可以看到代碼和結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章