【小林的OpenCV基礎課 10】Canny邊緣檢測

新しい年が近づいてくる,みなさんに新年をお祈りします。

預祝同學們新年大吉(吧(づ ̄ 3 ̄)づ)


嗯,邊緣檢測,聽起來挺高大上的,感覺終於從之前的濾波和模糊中解脫出來了。

邊緣檢測,顧名思義,就是找出圖像中的各種邊緣(通常邊緣都是以曲線的形式呈現的),然後標出來。可是機器怎麼知道哪裡是邊緣呢?這就涉及到邊緣檢測的原理了。

這一話依舊分為三部分:

  • Canny邊緣檢測原理
  • 對應的函數講解
  • Demo時間

Canny邊緣檢測原理

同學們可以先閱讀【小林的OpenCV基礎課 番外】極簡邊緣運算元基礎知識來充充電。

Canny邊緣檢測的思想:

  • 通過求導求梯度確定所有的長得像「邊緣」的像素
  • 去掉最不像「邊緣」的像素
  • 區分強邊緣(保留)和弱邊緣(待定)

使用Canny邊緣檢測時對圖像的預處理:

  • 使用高斯濾波器濾除雜訊(導數對雜訊肥腸敏感)

具體的實現步驟(即Canny演算法是如何找出邊緣的):

  • 使用邊緣運算元求出x和y方向的一階導數值 G_{x}G_{y}
  • 計算梯度值 G=sqrt{G_{x}^{2}+G_{y}^{2}} 和方向角 	heta=arctanfrac{G_{y}}{G_{x}}
  • 非極大值抑制,將局部最大值之外的所有梯度值抑製為0,消除雜散效應
  • 雙閾值篩選強弱邊緣,a.如果邊緣像素的梯度值>高閾值,則將其標記為強邊緣像素;b.如果低閾值<邊緣像素的梯度值<高閾值,則將其標記為弱邊緣像素;c.如果邊緣像素的梯度值<低閾值,則會被抑制
  • 確定弱邊緣像素的去留,若其鄰域內有強鄰域像素,則該弱邊緣像素會變成強邊緣像素

對兩個方向求導

Canny函數講解

edges=cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]])

  • edges:輸出的邊緣圖,需要和源圖片有一樣的尺寸和類型
  • image:待處理的圖像
  • thresh1和thresh2:分別為低閾值和高閾值,建議高低閾值之比為3:1到2:1之間
  • aptertureSize:應用Sobel運算元的孔徑大小,有默認值3
  • L2gradient:計算圖像梯度幅值的標識,有默認值false

Demo時間

有同學小的時候喜歡把手按在紙上,用筆描出手的輪廓。小林這裡有一隻手的照片,我們要做出這隻手的邊緣圖像:

沒錯 還是那隻手

import cv2import numpy as npimg = cv2.imread(hand1.jpg)# 首先進行高斯濾波 濾除干擾blurImg = cv2.GaussianBlur(img, (9, 9), 0)cannyImg = cv2.Canny(blurImg, 50, 130)cv2.namedWindow(Canny)cv2.namedWindow(Blur)cv2.imshow(Canny, cannyImg)cv2.imshow(Blur, blurImg)cv2.waitKey()cv2.destroyAllWindows()

效果圖

嗯 作業!

1.請同學們使用一種簡單的方法將得到的邊緣圖像疊加到原圖上。提示:

  • 邏輯運算
  • 掩膜操作
  • 邊緣圖的像素值,可以在控制台中列印出像素值
  • BGR空間是如何呈現顏色的

小林將邊緣做成了紅色

2.同學們會想,如果對閾值化後的圖像進行邊緣檢測會不會效果好一點?

  • 試一試不就知道啦

這一話講解部分的Demo代碼和作業的Demo代碼已經同步至Github,分別對應Class 4 Image Processing文件夾下的C4 Canny.py和C4 HW Canny.py兩個文件。


最後的最後

如果喜歡小林的專欄,就收藏了吧!してください!


推薦閱讀:

3D卷積神經網路Note01

TAG:計算機視覺 | OpenCV | Python |