訂閱
糾錯(cuò)
加入自媒體

數(shù)字圖像處理:邊緣檢測(cè)

序言

在之前的文章中,我介紹了傅里葉變換,這次我將介紹另一種圖像處理方法,邊緣檢測(cè)。在openCV中,有很多函數(shù)可以讓我們找到圖像的邊緣,在這篇文章中,我將挑選出比較有代表性的Sobal算子Laplacian算子進(jìn)行介紹。

邊緣檢測(cè)

既然我們要檢測(cè)邊緣,首先我們需要了解邊緣是什么。

最簡(jiǎn)單的邊緣

以上圖為例,我們可以看到黑白的分界線就是我們要找的邊緣,也就是像素之間的急劇變化。

拉普拉斯算子

原則拉普拉斯算子使用對(duì)圖像進(jìn)行微分的方法來(lái)提取邊緣。具體推導(dǎo)方法如下。

以與正面相似的圖片為例,取其中一條橫線,加以區(qū)分。

可以看出,在邊緣的交界處,經(jīng)過(guò)微分后,會(huì)出現(xiàn)一個(gè)明顯的峰值。我們可以設(shè)置一個(gè)閾值,這樣如果微分后的圖像超過(guò)這個(gè)閾值,就會(huì)判斷為邊緣,進(jìn)行后續(xù)處理。

但是這種方法不夠嚴(yán)謹(jǐn),所以也可以對(duì)圖像進(jìn)行兩次微分。而二階導(dǎo)數(shù)結(jié)果中的Z點(diǎn),也就是“過(guò)零”,就是我們要找的邊。

在了解了基本原理之后,我們需要從數(shù)學(xué)上推導(dǎo)出 Laplacian 所需的掩碼應(yīng)該是什么樣子。從上面的介紹可以看出,最重要的部分就是對(duì)圖像進(jìn)行區(qū)分,但其實(shí)這在圖像中并不難,只要從下一個(gè)網(wǎng)格的像素中減去上一個(gè)網(wǎng)格的像素,即可以得到斜率,它是一階導(dǎo)數(shù)。

數(shù)學(xué)表達(dá)式

在知道如何推導(dǎo)一階微分之后,同樣可以推導(dǎo)出二階微分。在這里,我們將跳過(guò)推導(dǎo)過(guò)程,直接查看結(jié)果。

二階微分的數(shù)學(xué)公式

至此,我們得到了我們需要的拉普拉斯掩碼。

拉普拉斯算子掩碼

實(shí)施

我們可以使用 openCV 中提供的拉普拉斯運(yùn)算函數(shù):

dst = cv2.Laplacian(src, ddepth, ksize)

src :要處理的圖像。

dst :輸出圖像。

ddepth :圖像的深度。有許多標(biāo)志可以使用。最常用的是cv2.CV_8U和cv2.CV_16S。

ksize :掩碼的大小。

import cv2


def main():

# read image

gray_img = cv2.imread("./lenna.jpg", 0)

cv2.imshow("img",gray_img)


# Try masks of different sizes

for n in range(1, 4):

 # 使用拉普拉斯算子

 kernel_size = 1+(n*2)

 gray_lap = cv2.Laplacian(gray_img, cv2.CV_16S, ksizekernel_size)

# Convert image format to uint8

 abs_lap = cv2.convertScaleAbs(gray_lap)

# display image

 cv2.imshow(f"{1+n*2}_lap_img",abs_lap)

 cv2.waitKey(0)

 cv2.destroyAllWindows()

# save image

 cv2.imwrite(f"./result/Laplacian/Laplacian_{1+n*2}.png",abs_lap)

if __name__ == "__main__":

main()

結(jié)果

Sobal 算子

原則

下圖是 Sobal 算子使用的掩碼。左邊是水平方向的邊緣檢測(cè),右邊是垂直方向的邊緣檢測(cè)。

然后使用這個(gè)掩碼對(duì)圖像進(jìn)行卷積得到邊緣圖像。

實(shí)施

就像拉普拉斯算子一樣,openCV 也提供了書面的 Sobal 函數(shù)。

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

src :要處理的圖像。

dst :輸出圖像。

ddepth :圖像的深度。有許多標(biāo)志可以使用。最常用的是cv2.CV_8U和cv2.CV_16S。

dx, dy :選擇要在水平或垂直方向進(jìn)行的操作,選擇1, 0/0, 1。

ksize :掩碼的大小。

在Sobal操作之后,convertScaleAbs通常會(huì)執(zhí)行一個(gè)操作,將圖像轉(zhuǎn)換回可以正常顯示的格式。

dst = cv2.convertScaleAbs(src)

示例程序

import cv2

def main():

# read image

gray_img = cv2.imread("./lenna.jpg", 0)

cv2.imshow("img",gray_img)

# Try masks of different sizes

for n in range(1, 4):
 

 # 使用 sobel 算子

 kernel_size = 1+(n*2)

 x = cv2.Sobel(gray_img, cv2.CV_16S, 1, 0, ksize=kernel_size)

 y = cv2.Sobel(gray_img, cv2.CV_16S, 0, 1, ksize=kernel_size)

# Convert image format to uint8

absX = cv2.convertScaleAbs(x)

absY = cv2.convertScaleAbs(y)

# Add the results from both directions to form a complete contour

 dst = cv2.a(chǎn)ddWeighted(absX, 0.5, absY,0.5,0)
 

 # display image

 cv2.imshow(f"{1+n*2}_x",absX)

 cv2.imshow(f"{1+n*2}_y",absY)

 cv2.imshow(f"{1+n*2}_x+y",dst)

 cv2.waitKey(0)

 cv2.destroyAllWindows()
 

 # save image

 cv2.imwrite(f"./result/Sobal/Sobal_{1+n*2}_x.png",absX)

 cv2.imwrite(f"./result/Sobal/Sobal_{1+n*2}_y.png",absY)

 cv2.imwrite(f"./result/Sobal/Sobal_{1+n*2}_x+y.png",dst)

if __name__ == "__main__":

main()

輸入

結(jié)果(內(nèi)核大小 = 3)

結(jié)果(內(nèi)核大小 = 5)

結(jié)果(內(nèi)核大小 = 7)

參考

image.png


       原文標(biāo)題 : 數(shù)字圖像處理:邊緣檢測(cè)

聲明: 本文由入駐維科號(hào)的作者撰寫,觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

    人工智能 獵頭職位 更多
    掃碼關(guān)注公眾號(hào)
    OFweek人工智能網(wǎng)
    獲取更多精彩內(nèi)容
    文章糾錯(cuò)
    x
    *文字標(biāo)題:
    *糾錯(cuò)內(nèi)容:
    聯(lián)系郵箱:
    *驗(yàn) 證 碼:

    粵公網(wǎng)安備 44030502002758號(hào)