OpenCV-Python系列之拉普拉斯算子


我們在上一個教程中前面的例子學習了使用Sobel邊緣檢測。原理是利用邊緣區域像素值的跳變。通過求一階導數,可以使邊緣值最大化。如下圖所示:

image.png

那么,如果求二階導數會得到什么呢?

image.png

可以觀察到二階導數為0的地方。因此,可以利用該方法獲取圖像中的邊緣。然而,需要注意的是二級導數為0的不只出現在邊緣地方,還可能是一些無意義的位置,根據需要通過濾波處理該情況。

二階微分

現在我們來討論二階微分,它是拉普拉斯算子的基礎,與微積分中定義的微分略有不同,數字圖像中處理的是離散的值,因此對於一維函數的一階微分的基本定義是差值:

image.png

類似的,二階微分定義為:

image.png

將一維函數擴展到二維:

image.png

二階微分的定義保證了以下幾點:

1、在恆定灰度區域的微分值為0

2、在灰度台階或斜坡的起點處微分值非零

可以看出,二階微分可以檢測出圖像的邊緣、增強細節

拉普拉斯算子

從上面的解釋,可以看出二階導數可以擁有邊緣檢測。由於圖像是二維的,因此需要分別獲取兩個方向的導數。這里使用的是拉普拉斯算子來進行近似。

拉普拉斯算子用下面公式定義:

image.png

其中:

image.png

可以用多種方式將其表示為數字形式。對於一個3*3的區域,一般情況下被推薦最多的形式是:

image.png

實現上式的濾波器模板為:

image.png

我們可以發現,拉普拉斯算子不需要向Sobel算子那樣分別對x,y方向進行處理,它可以直接處理,現在我們來看看OpenCV中的拉普拉斯算子的函數原型:

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

如果看了上一個教程中對於Sobel算子的介紹,這里的參數應該不難理解。

前兩個是必須的參數:

第一個參數是需要處理的圖像;

第二個參數是圖像的深度,-1表示采用的是與原圖像相同的深度。目標圖像的深度必須大於等於原圖像的深度;

其后是可選的參數:

dst不用解釋了;

ksize是算子的大小,必須為1、3、5、7。默認為1。

scale是縮放導數的比例常數,默認情況下沒有伸縮系數;

delta是一個可選的增量,將會加到最終的dst中,同樣,默認情況下沒有額外的值加到dst中;

borderType是判斷圖像邊界的模式。這個參數默認值為cv2.BORDER_DEFAULT。

我們來看代碼:

import cv2
import numpy as np

img = cv2.imread("pie.png")
dst = cv2.Laplacian(img,cv2.CV_16S,ksize=3)
dst = cv2.convertScaleAbs(dst)
cv2.imshow("img",img)
cv2.imshow("res",dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

image.png

現在可以拿這個結果對比上一個教程的結果了,我們發現,這個結果要比上一個教程的結果好的多,對於邊緣檢測沒有大的偏差。

然而事實上,這只是對於簡單的圖像而言,而對於一幅復雜的圖像,那么邊緣提取就有點愛莫能助了,我們來看代碼:

import cv2
import numpy as np

img = cv2.imread("cat.jpg")
dst = cv2.Laplacian(img,cv2.CV_16S,ksize=3)
dst = cv2.convertScaleAbs(dst)
cv2.imshow("img",img)
cv2.imshow("res",dst)

cv2.waitKey(0)
cv2.destroyAllWindows()

image.png

可以看到,對於較為復雜的圖像,拉普拉斯算子的效果也並不是很好,由於二階微分一定的局限性,目前的邊緣檢測還不夠完美,我們需要一種綜合的算法,而這將在下一個教程中介紹到。


免責聲明!

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



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