opencv邊緣檢測sobel算子

人眼怎麼識別圖像邊緣?

好比有一幅圖,圖裏面有一條線,左邊很亮,右邊很暗,那人眼就很容易識別這條線做爲邊緣.也就是像素的灰度值快速變化的地方.html

sobel算子


對於f(t),其導數f'(t)反映了每一處的變化趨勢.在變化最快的位置其導數最大. sobel算子的思路就是模擬求一階導數.python

sobel算子是一個離散差分算子.它計算圖像像素點亮度值的近似梯度.
圖像是二維的,即沿着寬度/高度兩個方向.
咱們使用兩個卷積覈對原圖像進行處理:c++

  • 水平方向

    很好理解,原始像素灰度值-->(右邊像素值-左邊像素值),反映了水平方向的變化狀況.api

  • 垂直方向
    ide

這樣的話,咱們就獲得了兩個新的矩陣,分別反映了每一點像素在水平方向上的亮度變化狀況和在垂直方向上的亮度變換狀況.函數

綜合考慮這兩個方向的變化,咱們使用

反映某個像素的梯度變化狀況.
有時候爲了簡單起見,也直接用絕對值相加替代.
code

opencv裏可使用了以下的卷積核,能夠"放大像素的變化狀況".

能夠參考這個函數Scharrhtm

opencv實現

import cv2 as cv
def test():
    src = cv.imread("/home/sc/disk/keepgoing/opencv_test/sidetest.jpeg")
    src = cv.GaussianBlur(src, (3, 3), 0)
    gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
    grad_x = cv.Sobel(gray, -1, 1, 0, ksize=3)
    grad_y = cv.Sobel(gray, -1, 0, 1, ksize=3)
    
    grad  = cv.addWeighted(grad_x, 0.5, grad_y, 0.5, 0)
    
    cv.imshow("origin",src)
    cv.imshow("grad",grad)
    cv.waitKey()
    
test()

首先是高斯模糊去噪.某種意義上說高斯模糊是和sobel相反的過程.高斯模糊平滑了某點像素與周邊像素的差別.那爲何還要先高斯去噪呢?blog

噪聲就是像素的強度相對於真值有個突變。從時域上講,經過高斯濾波能讓一個像素的強度與周圍的點相關,就減少了突變的影響;從頻域上講,突變引入了高頻份量,而高斯濾波器能夠濾除高頻份量。ip

高斯去噪是爲了防止把噪點也檢測爲邊緣.

而後計算grad_x,grad_y.即對原圖作水平方向/垂直方向的sobel卷積核卷積

grad_x = cv.Sobel(gray, -1, 1, 0, ksize=3)
    grad_y = cv.Sobel(gray, -1, 0, 1, ksize=3)

sobel api

注意區分c++版本和python版本api. 在上述代碼中,第二個參數-1表明咱們但願輸出的圖像矩陣和原圖有一樣的depth,第3/4個參數分別表明在x/y方向作一階差分.取值0或1.
ksize必須爲奇數.

tips:一般咱們使用( xorder = 1, yorder = 0, ksize = 3) or ( xorder = 0, yorder = 1, ksize = 3)來計算水平/垂直方向的一階差分矩陣.ksize=3用的是標準sobel卷積核.若是ksize傳入FILTER_SCHARR,則使用的是以下卷積核:

最後將兩個矩陣疊加,綜合考慮水平和垂直方向的像素灰度值變化強度.獲得邊緣.

grad  = cv.addWeighted(grad_x, 0.5, grad_y, 0.5, 0)

完整代碼處理效果以下

ksize採用cv.FILTER_SCHARR效果以下:

grad_x = cv.Sobel(gray, -1, 1, 0, ksize=cv.FILTER_SCHARR)
    grad_y = cv.Sobel(gray, -1, 0, 1, ksize=cv.FILTER_SCHARR)

相關文章
相關標籤/搜索