opencv學習記錄之圖像梯度


 

圖像的梯度計算的是圖像變化的速度,對於邊緣部分呢灰度值變換大,梯度值也大,相反則灰度值變化小,梯度值小

圖像梯度值嚴格說應該需要求導數,但是圖像梯度一般通過計算像素值的差,來得到梯度的近似值

以下介紹三種算子的使用Sobel算子、Scharr算子和Laplacian算子

 

Sobel算子是一種離散的微分算子,該算子結合了高斯平滑處理和微分求導運算。 該算子利用局部差尋找邊緣

Sobel算子如下所示

-1 0 1
-2 0 2
-1 0 1

                            圖一

-1 -2 -1
0 0 0
1 2 1

                            圖二    

 將Sobel算子圖一和原始圖像卷積可以得到水平方向的像素值變化,與圖二卷積的到垂直方向的像素值變化

P1 P2 P3
P4 P5 P6
P7 P8 P9

如果要計算P5的水平方向的偏導數,則需要Sobel算子及P5鄰域點

公式為:P5x = (P3 - P1 ) + 2 * ( P6 - P4 ) + ( P9 - P7 )

用P5右側的像素點減左側的像素點,因為P4和P6離P5較近,所以權值為2,其他為1

垂直方向類似,垂直是下減上

函數形式

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

dst目標圖像

src原始圖像

ddepth 輸出圖像的深度,

dx x方向上的求導階數

dy  y方向上的求導階數

ksize 代表Sobel核的大小,該值為-1時,會使用Scharr算子進行計算

scale計算導數值時采用的縮放因子,默認為1,沒有縮放

delta加在目標圖像dst上的值,默認為0

borderType 邊界樣式 (上篇博客提到過不再重復)

 

可以將ddepth設置為-1,在計算時可能得到的結果時錯誤的,

如果處理的圖像是8位圖類型,且ddepth為-1 意味着指定運算結果也是8位圖類型,所有負數都自動處理為0

為了避免信息丟失在計算是要先使用更高的數據類型嗯 cv2.CV_64F,在通過取絕對值將其映射位8位圖類型

所以通常要將ddepth設置位cv2.CV_64F

如下代碼所示

1 import cv2                                                                       
2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
3 Sobelx = cv2.Sobel(o , -1 , 1 , 0) 
4 cv2.imshow("original" , o) 
5 cv2.imshow("x" , Sobelx)
6 cv2.waitKey()
7 cv2.destroyAllWindows()

 

原圖

 

 

效果圖 

 

 

如上圖所示在8位灰度圖中因為黑色的像素值位0,而白色為255,當使用Sobel算子后,對其水平方向計算近似偏導數

右側減左側,右側邊緣得到的是正數所以可以正常顯示,而左側的邊緣得到的是負數被處理為0后便顯示黑色不能得到准確的結果

 

將ddepth設置為cv2.CV_64F后 還要取絕對值才能獲得所需的圖像,則需要絕對值函數 cv2.convertScaleAbs()

dx = 1 , dy = 0

1 import cv2                                                                       
2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
3 Sobelx = cv2.Sobel(o , cv2.CV_64F , 1 ,0)
4 Sobelx = cv2.convertScaleAbs(Sobelx)
5 cv2.imshow("original" , o) 
6 cv2.imshow("x" , Sobelx)
7 cv2.waitKey()
8 cv2.destroyAllWindows()

 

如圖   可以獲得完整邊緣信息

 

 

 

垂直方向的邊緣信息 dx = 0 . dy = 1

1 import cv2                                                                       
2 o = cv2.imread("example.bmp" , cv2.IMREAD_UNCHANGED)
3 Sobely = cv2.Sobel(o , cv2.CV_64F , 0 , 1) 
4 Sobely = cv2.convertScaleAbs(Sobely)
5 cv2.imshow("original" , o) 
6 cv2.imshow("y" , Sobely)
7 cv2.waitKey()
8 cv2.destroyAllWindows()

 

如圖

 

 

 

當dx =1 , dy = 1 

1 import cv2                                                                       
2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
3 Sobelxy = cv2.Sobel(o , cv2.CV_64F , 1 , 1) 
4 sobelxy = cv2.convertScaleAbs(Sobelxy)
5 cv2.imshow("original" , o) 
6 cv2.imshow("xy" , Sobelxy)
7 cv2.waitKey()
8 cv2.destroyAllWindows()

 

 

 

 沒有達到我們想要的結果,而是只留下幾個點

 

若想要x,y方向都顯示邊緣需要兩個方向分別處理,然后向疊加

import cv2                                                                       
o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE )
Sobelx = cv2.Sobel(o , cv2.CV_64F , 1 , 0)   
Sobely = cv2.Sobel(o , cv2.CV_64F , 0 , 1)   
Sobelx = cv2.convertScaleAbs(Sobelx)         
Sobely = cv2.convertScaleAbs(Sobely)         
Sobelxy = cv2.addWeighted(Sobelx , 0.5 , Sobely , 0.5 , 0) 
cv2.imshow("original" , o) 
cv2.imshow("xy" , Sobelxy)
cv2.waitKey()  
cv2.destroyAllWindows()

 

 

 

 

 

 

Scharr算子

在使用3x3的Sobel算子是精度可能不高,Scharr速度與Sobel算子一樣 ,但精度更高

Scharr算子通常為

-3 0 3
-10 0 10
-3 0 3

 

 

-3 -10 -3
0 0 0
3 10 3

函數形式為

dst = cv2.Scharr( src , ddepth , dx , dy [ , scale [ ,delta [, borderType]]])

與Sobel相似少了Ksize參數, 即當Sobel中ksize = -1 時會使用Scharr算子計算

函數cv2.Scharr()與cv2.Sobel()相似

但有一些約束條件

dx >= 0 && dy >=0 && dx + dy == 1

x方向和y方向的邊緣疊加

 1 import cv2                                                                       
 2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
 3 Scharrx = cv2.Scharr(o , cv2.CV_64F , 1 , 0) 
 4 Scharry = cv2.Scharr(o , cv2.CV_64F , 0 , 1) 
 5 Scharrx = cv2.convertScaleAbs(Scharrx)
 6 Scharry = cv2.convertScaleAbs(Scharry)
 7 Scharrxy = cv2.addWeighted(Scharrx , 0.5 , Scharry , 0.5 , 0) 
 8 cv2.imshow("original" , o) 
 9 cv2.imshow("xy" , Scharrxy)
10 cv2.waitKey()
11 cv2.destroyAllWindows()

 

 

 

Sobel和Scharr的比較

原圖

 

 

 Sobel

 

 

 Scharr

 

 

 

 

 

Laplacian算子

該算子是一個二階導數算子,具有旋轉不變性,可以滿足不同方向的圖像邊緣銳化(邊緣檢測)的要求,

通常情況下算子的系數和要為0

Laplacian算子 

0 1 0
1 -4 1
0 1 0

 

p1 p2 p3
p4 p5 p6
p7 p8 p9

P5點的近似導數值

P5lap =( P2 + P4 + P6 + P8 ) - 4* P5

該結果可能是正數也可能是負數,需要對計算結果取絕對值

函數形式

dst = cv2.Laplacian(src , ddepth , [,ksize [ ,scale [, delta [.borderType]]]])

dst 目標圖像

src原始圖像

ddepth目標時圖像的深度

ksize二階導數的核尺寸大小

scale  計算Laplacian值的縮放比例因子

delta 夾道目標圖像上的可選值

borderType 邊界樣式

1 import cv2                                                                       
2 o = cv2.imread("example.bmp" , cv2.IMREAD_GRAYSCALE)
3 Laplacian = cv2.Laplacian(o , cv2.CV_64F)
4 Laplacian = cv2.convertScaleAbs(Laplacian)
5 cv2.imshow("original" , o) 
6 cv2.imshow("Laplacina" , Laplacian)
7 cv2.waitKey()
8 cv2.destroyAllWindows()

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM