opencv邊緣檢測-拉普拉斯算子


sobel算子一文說了,索貝爾算子是模擬一階求導,導數越大的地方說明變換越劇烈,越有可能是邊緣.

那如果繼續對f'(t)求導呢?

可以發現"邊緣處"的二階導數=0. 我們可以利用這一特性去尋找圖像的邊緣. 注意有一個問題,二階求導為0的位置也可能是無意義的位置

拉普拉斯算子推導過程

以x方向求解為例:
一階差分:f'(x) = f(x) - f(x - 1)
二階差分:f''(x) = f'(x+1) - f'(x) = (f(x + 1) - f(x)) - (f(x) - f(x - 1))
化簡后:f''(x) = f(x - 1) - 2 f(x)) + f(x + 1)
提取前面的系數:[1, -2, 1]

同理得到y方向的系數[1,-2,1]

這樣的話,疊加起來就得到了拉普拉斯矩陣

opencv實現

Laplacian api

默認的ksize=1,和ksize=3效果是一樣的,都是用的上述拉普拉斯矩陣去卷積原圖像

關於filter具體是什么,可以通過函數getDerivKernels得到

dx,dy代表求導的階數.

def cal_filter(dx,dy,ksize):
    kx, ky=cv.getDerivKernels(dx, dy, ksize)
    print(kx)
    print(ky)
                                                                  
cal_filter(2,2,1)   
cal_filter(2,2,3) 
cal_filter(2,2,5)

輸出為
可以看到ksize=1和ksize=3其實是一樣的.

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)
    
    dst1 = cv.Laplacian(gray, -1,3)
    dst2 = cv.Laplacian(gray, -1,1)
    
    cv.imshow("origin",src)
    cv.imshow("dst1",dst1)
    cv.imshow("dst2",dst2)
    if 27 == cv.waitKey():
        cv.destroyAllWindows()

test()

效果如下:

sobel和laplace都是比較簡單的邊緣檢測算法,目前比較常用的是canny,后面的博文會寫到.
在搜索各種邊緣檢測算法的適用場景時,發現大部分文章都只講了opencv里如何實現,並且都是互相抄來抄去.下面給出個人認為講的不錯的兩個link
https://blog.csdn.net/xiaojiegege123456/article/details/7714863
https://dsp.stackexchange.com/questions/74/what-factors-should-i-consider-in-choosing-an-edge-detection-algorithm

二階導數還可以說明灰度突變的類型。在有些情況下,如灰度變化均勻的圖像,只利用一階導數可能找不到邊界,此時二階導數就能提供很有用的信息。二階導數對噪聲也比較敏感,解決的方法是先對圖像進行平滑濾波,消除部分噪聲,再進行邊緣檢測。不過,利用二階導數信息的算法是基於過零檢測的,因此得到的邊緣點數比較少,有利於后繼的處理和識別工作

總結一下就是:拉普拉斯對噪聲更敏感,但是對邊緣灰度變化不大的圖像,檢測效果比索貝爾算子要好一些.比如下圖中牛和樹的灰度變換並不是特別強.

實際使用中最常用的還是canny算法.后面的博文會再做介紹.


免責聲明!

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



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