點擊上方“小白學視覺”,選擇加"星標"或“置頂”
重磅干貨,第一時間送達

如果我們環顧房間,我們會看到大量的物體,每一個都很容易區分,并有自己獨特的邊緣,我們區分物體的先天能力部分來自于我們的視覺系統檢測邊緣的能力,檢測邊緣是視覺的一項基本任務,盡管沒有它我們不會完全失明,但以前區分物體的簡單任務將變得非常具有挑戰性,電腦也是類似的,計算機要檢測物體,首先需要識別邊緣,
接下來讓我們進入 Canny 邊緣檢測器,
Canny 邊緣檢測器是一種用于識別影像邊緣的演算法,,它由 John F. Canny 于 1986 年開發,此后一直被廣泛使用,今天,我們將在開放的 Python 計算機視覺庫(OpenCV-python)的幫助下,詳細探討 Canny 邊緣檢測器
設定
讓我們首先從初始設定開始,
向我們的 python 檔案添加兩個依賴項:
import cv2 as cv
from matplotlib import pyplot as plot
第一個匯入是 OpenCV python,這是我們將用來生成 Canny 邊緣和一些補充影像的庫,我們還將使用 matplotlib 來顯示我們的影像,
首先,這是我們將要查找的 Canny 邊緣的影像:

Canny 邊緣演算法需要灰度影像才能正常運行,我們可以在 OpenCV 中將 RGB 影像讀取為灰度,如下所示:
# helper function to easily display our images
def img_show(title, image):
plot.title(title)
plot.xticks([])
plot.yticks([])
plot.imshow(image, cmap="gray")
plot.show()
# read in our original image as grayscale
img = cv.imread("original@2x.jpg", cv.IMREAD_GRAYSCALE)
# show grayscale image using our helper function
img_show("Grayscale Image", img)
我們來創建一個非常簡單的輔助函式,用于使用 matplotlib 顯示我們的影像,使用這個函式,我們可以查看我們的灰度影像:

原始影像的灰度版本
現在我們已經完成了初始設定,接下來讓我們深入研究 Canny 邊緣演算法!
5個基本步驟
Canny邊緣檢測演算法包括五個步驟:
高斯濾波
確定強度梯度
非極大值抑制
雙閾值
滯后邊緣跟蹤
我將詳細解釋每個步驟,
高斯濾波
我們可能聽說過正態分布或高斯分布,這種分布在自然界中始終存在,常用于表示實值隨機變數,
在影像處理中,可以對影像應用高斯濾波器以減少噪聲,模糊的圖片可以直觀地觀察到這個效果,
由于 Canny 邊緣演算法使用導數來尋找影像的強度梯度,因此非常容易受到噪聲的影響,因此,我們通過對圖片應用高斯濾波器來去除噪聲,如果我們不去除噪聲,演算法可能會將影像中的噪聲塊誤認為邊緣并錯誤地標記它們,
OpenCV 使用 sigma = 1 的 5x5 高斯核作為降噪步驟,我已經創建了這個內核的 3D 可視化,可以在下面看到,當應用于我們的影像時,還包含了此過濾器的效果,


5x5 高斯核的 3D 可視化,sigma = 1;應用高斯濾波器的原始影像
盡管高斯濾波影像可能與原始灰度影像相同,但仔細觀察會發現輕微的模糊,尤其是在棕櫚葉的邊緣周圍,我們不想過多地模糊影像;否則,我們可能會丟失影像的細節,
我們可以使用以下代碼輕松生成此影像:
# blurring the image with a 5x5, sigma = 1 Guassian kernel
img_blur = cv.GaussianBlur(img, (5, 5), 1)
確定強度梯度
在對影像進行平滑處理后,Canny 邊緣演算法的第二步是找到圖片的強度梯度,
盡管“強度梯度”這個名詞可能聽起來很復雜,但它只是指邊緣的方向,一條邊實際上可以指向任何方向,但該演算法只查看四個方向以簡化事情,方向是水平、垂直和兩個對角線方向,在數學中,我們將其寫為 [0 ° , 90 ° , 45 ° , 135 ° ],
OpenCV 使用 3x3 Sobel 內核來確定水平方向的導數,然后將其轉置以確定垂直方向的導數,這些導數可用于在所需的四個方向上找到我們的邊緣,
與高斯核一樣,我們也可以在 3D 中可視化 Sobel 核,下邊還包括了 Sobel 過濾影像,


3x3 水平 Sobel 核的 3D 可視化;雙向應用 Sobel 核的高斯模糊影像
在代碼中,我們可以按如下方式生成 Sobel 過濾后的影像:
# obtaining a horizontal and vertical Sobel filtering of the image
img_sobelx = cv.Sobel(img_blur, cv.CV_64F, 1, 0, ksize=3)
img_sobely = cv.Sobel(img_blur, cv.CV_64F, 0, 1, ksize=3)
# image with both horizontal and vertical Sobel kernels applied
img_sobelxy = cv.addWeighted(cv.convertScaleAbs(img_sobelx), 0.5, cv.convertScaleAbs(img_sobely), 0.5, 0)
非極大值抑制
一旦我們找到了強度梯度,我們就可以使用它們來細化我們的邊緣,在這一步之后,結果是一個二值影像,這意味著影像將只包含兩種顏色,黑色和白色,同樣,非最大抑制這個名字聽起來很復雜,實際上這是一個簡單的操作,
我們通過檢查每個像素在其梯度方向上的相鄰像素來確定它是否具有最大強度,從而對每個像素應用非最大抑制,如果像素是最大的,那么我們將其值設定為 1,如果不是,這意味著像素的相鄰像素具有更高的強度,我們將其值設定為 0(抑制它),
雙閾值
有一個小問題:并非所有邊緣都準確地代表了影像的真實邊緣,許多假邊緣是由噪聲和輕微的顏色變化造成的,盡管該演算法的第一步是去除噪聲,但并非所有噪聲都被去除,這是因為選擇 5x5 高斯濾波器是一種折中處理,過濾器去除了大部分明顯的噪聲,但不會去除太多,這就是雙重閾值發揮作用的地方,
我們首先選擇兩個閾值:最小值和最大值,這就是我們所謂的雙閾值,接下來,我們將每個邊緣的強度梯度與兩個閾值進行比較,如果邊緣的強度梯度大于最大閾值,則將其標記為強(或確定)邊緣;相反,如果邊緣的強度梯度小于最小閾值,則將其丟棄,但是,如果邊緣的強度梯度介于最小和最大閾值之間,則將其標記為弱邊緣,
請參考下圖:
閾值區域圖
綠色區域是強度梯度高于最大閾值的地方,這意味著該區域內的任何邊緣都被歸類為強邊緣,類似地,可以在藍色區域內找到弱邊緣,因為該區域位于我們的兩個閾值之間,紅色區域代表梯度低于我們的最小閾值的邊緣,因此,該區域內的任何邊緣都將被丟棄,
滯后邊緣跟蹤
到目前為止,我們已經確定了兩種型別的邊緣:弱邊和強弱,我們知道強邊緣是我們選擇最大閾值的最終結果的一部分,但是,我們不太確定如何處理弱邊緣,Canny 邊緣演算法使用假設來簡化事情,它假設連接到強邊的弱邊本身就是強邊,同樣,未連接到強邊緣的弱邊緣是噪聲或顏色變化,在閾值化的背景關系中,這就是滯后的含義,
現在,讓我們在第 4 步的圖表中添加兩條曲線,每條曲線代表一條邊的梯度值,
添加了漸變曲線的閾值區域圖
由線段 A 和 C 組成的頂部曲線穿過綠色和藍色區域,我們知道綠色區域的邊緣強,藍色區域的邊緣弱,因此,段A是強邊緣,段C是弱邊緣,通過應用滯后邊緣跟蹤,我們將 C 標記為強邊緣,因為它連接到 A,
現在讓我們來看底部曲線,該曲線由段 B 和 D 組成,由于 B 低于最小閾值,它應該已經被抑制了,然而,D 是一個弱邊緣,這意味著它需要進行判斷,通過使用滯后邊緣跟蹤,我們可以看到 D 沒有連接到任何通過綠色區域的線段,這意味著它沒有連接到任何強邊,因此它被丟棄,
這很好,但是演算法如何準確地知道弱邊是否連接到強邊?Canny 邊緣演算法通過考慮每個弱邊緣像素及其周圍的 8 個相鄰像素來確定這一點,如果其相鄰像素中的任何一個是強邊緣的一部分,則認為它連接到強邊緣,因此,該像素保留在我們的最終結果中,相反,如果相鄰像素都不是強邊緣,則假定它不是強邊緣的一部分,因此被抑制,
把它們綁在一起
對我們來說非常容易的是,我們實際上不需要執行任何這些步驟來生成我們的 Canny 邊,OpenCV 將它們捆綁到一個名為 Canny() 的函式中,
通過撰寫以下代碼,我們可以很容易地在影像上呼叫此函式:
# finally, generate canny edges
# extreme examples: high threshold [900, 1000]; low threshold [1, 10]
img_edges = cv.Canny(img, 50, 100)
經過一些實驗,我們分別選擇50和100作為我們的低閾值和高閾值,但是,我們還可以嘗試不同的方法,也許會發現其他閾值會產生更好的結果!

我們最后的 Canny 邊緣
參考文獻:
https://en.wikipedia.org/wiki/Canny_edge_detector
https://docs.opencv.org/master/da/d22/tutorial_py_canny.html
https://scikit-image.org/docs/dev/auto_examples/filters/plot_hysteresis.html
https://unsplash.com/photos/Ow-MNAWRBW4
Github代碼連接:
https://github.com/SeanDuttonJones/opencv-canny-edge
下載1:OpenCV-Contrib擴展模塊中文版教程
在「小白學視覺」公眾號后臺回復:擴展模塊中文教程,即可下載全網第一份OpenCV擴展模塊教程中文版,涵蓋擴展模塊安裝、SFM演算法、立體視覺、目標跟蹤、生物視覺、超解析度處理等二十多章內容,
下載2:Python視覺實戰專案52講
在「小白學視覺」公眾號后臺回復:Python視覺實戰專案,即可下載包括影像分割、口罩檢測、車道線檢測、車輛計數、添加眼線、車牌識別、字符識別、情緒檢測、文本內容提取、面部識別等31個視覺實戰專案,助力快速學校計算機視覺,
下載3:OpenCV實戰專案20講
在「小白學視覺」公眾號后臺回復:OpenCV實戰專案20講,即可下載含有20個基于OpenCV實作20個實戰專案,實作OpenCV學習進階,
交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計算攝影、檢測、分割、識別、醫學影像、GAN、演算法競賽等微信群(以后會逐漸細分),請掃描下面微信號加群,備注:”昵稱+學校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“,請按照格式備注,否則不予通過,添加成功后會根據研究方向邀請進入相關微信群,請勿在群內發送廣告,否則會請出群,謝謝理解~


轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/349753.html
標籤:其他
