該內容爲html
的學習內容算法
Canny 邊緣檢測方法是由 Canny 於1996 年提出的一種公認爲效果較好的邊緣檢測方法。ide
一個好的邊緣檢測方法應該知足三項指標函數
基於此,Canny提出了斷定邊緣檢測算子的3個準則:源碼分析
Canny 算子實現過程共有4(5)個步驟:學習
全部的邊緣都極易受到噪聲的干擾,爲防止檢測結果的誤差較大,有必要使用平滑濾波的方法濾除噪聲。高斯濾波方法是經常使用的濾波方法,二維圖像應用二維高斯函數,它的定義爲網站
式中 σ 表示 高斯函數的標準差。只要把輸入圖像與二維高斯函數進行卷積,便可獲得平滑後的圖像。spa
注:3d
考慮到數字圖像爲離散化的形式,咱們每每把高斯函數轉化爲離散化的高斯內核模板形式,如標準差爲1.4 的模板尺寸爲 5 * 5 的歸一化高斯內涵模板爲:code
尋找圖像的強度梯度 / 計算梯度 / 梯度檢測
梯度是圖像灰度值變化劇烈的地方,它能夠經過 Roberts 算子、Prewitt 算子、Sobel 算子(最經常使用)等最簡單的模板檢測方法獲得。
Sobel 算子是由兩個模板組成:
,
這Sobel算子內核(的兩個模板)分別在水平和垂直方向上對平滑後的圖像進行濾波,以得到水平方向的梯度 Gx 和 垂直方向的梯度 Gy (注:該處的梯度也可稱爲一階導數),最終圖像每一個像素的邊緣梯度 Edge_Gradient 和方向,一般採用歐幾裏計算方法得邊緣梯度幅值(L2範數):
但平時爲了簡化,梯度值也可由曼哈頓距離(L1範數)求得:
梯度幅角 θ 爲:
注:由該公式獲得得梯度幅角是任意值,但咱們須要將其四捨五入到表示垂直、水平和兩個對角線方向的四個角度中的一個,共計 4 個方向 !即 0°、45°、90°、135°;如梯度幅角爲(-22.5,22.5)區間值時,均會四捨五入爲 0° 。
非最大值抑制也成爲非極大值抑制
該步驟的目的是使邊緣細化。
梯度檢測後得到的圖像邊緣較爲模糊,不合符 「 好的邊緣檢測 」 中的第三項:
- 三、每一個邊緣應該由惟一的響應,即獲得單像素寬度的邊緣。
也即,在得到梯度幅度和方向以後,須要完成圖像的全掃描以去除可能不構成邊緣的任何不須要的像素。爲此,在每一個像素處,檢查像素是不是其在梯度方向上的鄰域中的局部最大值。保留具備局部最大值的像素點即爲灰度值變化最劇烈的地方,以下圖所示
上圖中 A 點位於邊緣(垂直方向),其漸變方向與邊緣垂直;B 點和 C 點處於梯度方向。按照非最大值抑制思路,用點 B 和 C 檢查點 A ,看 A 點是否造成局部最大值,如果最大值,it is considered for next stage,若不是局部最大值,A點將會被抑制,即歸零 put to zero。最終目的是獲得 「 細邊 」 單像素的二進制圖像。
注:這裏局部最大值是由在 3*3 的鄰域內的梯度方向上比較梯度值獲得的。
該步驟是決定那些邊緣是邊緣,那些邊緣不是邊緣。
上步驟獲得的邊緣仍存在有 」 假邊緣 「,這是因爲噪聲或顏色變化的影響而產生的非真正邊緣。
這種現象的表現形式是儘管這些邊緣的梯度幅值是局部最大值,但與其餘邊緣比,它們的梯度幅值很小,也就是絕對梯度幅值很小。
爲此,咱們採用滯後閾值處理法。
設置 minVal 和 maxVal 兩個閾值,
具體去留方式算法以下:
邊緣 A 高於 maxVal,所以被視爲 」 肯定邊緣(sure-edge) 「 ;雖然邊(緣)C 低於 maxVal,可是它鏈接到邊(緣) A,所以被視爲有效邊(緣),咱們可得到完成的曲線。對於邊緣 B 而言,其雖然高於 minVal,但它沒有鏈接到任何 」肯定邊緣(sure-edge)「,同時又與邊緣 C 區域相同,所以將被丟棄。該方法也就是所謂的 」 邊緣跟蹤 「 法來判斷弱邊緣是否爲真正的邊緣。
具體計算爲:在弱邊緣的 3*3 區域內,如有強邊緣,則說明該弱邊緣是屬於這個強邊緣的,將被保留,不然將被丟棄。
因此咱們最終獲得的是圖像中的強邊緣(strong edges in the image.)。
Canny 函數的原型爲:
Python:
edges = cv.Canny( image,#input 單通道8-bit灰度圖, threshold1,#滯後閾值法中低閾值minVal threshold2,#滯後閾值法中低閾值maxVal [edges],#output邊緣圖,單通道8位圖,與image大小相同 [apertureSize],#孔徑尺寸,即Sobel算子的尺寸大小,默認值爲3 [L2gradient]#計算梯度幅值L一、L2範數選擇,默認False(L2範式 ) )
OpenCV中的Canny算法的碼源:略
注意:
一、因爲 OpenCV 中 沒有執行經典 Canny 方法中的第一步,即省去了濾波平滑;全部咱們須要事前進行平滑處理。
二、OpenCV 中的 Canny 算法僅遍歷了一遍圖像,就完成了步驟2(梯度計算)和步驟3(非最大值抑制);具體過程是計算當前遍歷行的梯度幅值,同時計算前一行的梯度幅角,並完成 3*3 鄰域內的非最大值抑制。
三、步驟3(非最大值抑制)和步驟4(滯後閾值處理)是交錯在一塊兒計算的。
四、步驟4 中的邊緣追蹤法中,程序是尋找強邊緣的 3*3 鄰域內的弱邊緣的方法,而不是尋找弱邊緣的 3*3 鄰域內的強邊緣。
import numpy as np
import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('img.jpg',0) edges = cv.Canny(img,100,200) plt.subplot(121),plt.imshow(img,cmap = 'gray') plt.title('Original Image'), plt.xticks([]), plt.yticks([]) plt.subplot(122),plt.imshow(edges,cmap = 'gray') plt.title('Edge Image'), plt.xticks([]), plt.yticks([]) plt.show()
來源:Canny Edge Detection(4.0.1) 版本 https://docs.opencv.org/master/da/d22/tutorial_py_canny.html
運行效果:
4 車道線檢測(實際項目)
略