opencv影象處理-------邊緣檢測演算法
利用Canny邊緣檢測運算元進行邊緣檢測的原理及OpenCV程式碼實現
Canny運算元是John Canny在1986年發表的論文中首次提出的邊緣檢測運算元,該運算元檢測效能比較好,應用廣泛。
Canny運算元進行邊緣檢測的原理和步驟如下:
⑴消除噪聲。邊緣檢測的演算法主要是基於影象強度的一階和二階微分操作,但導數通常對噪聲很敏感,邊緣檢測演算法常常需要根據影象源的資料進行預處理操作,因此採用濾波器來改善與噪聲有關的邊緣檢測效能,比如在進行邊緣檢測前,可以對原始資料先作高斯濾波處理。其實不僅對噪聲,如果不做濾波平滑處理,原圖片中不是邊緣但是灰度變化頻率較高的部分也容易被認為是邊緣,這樣導致了邊緣檢測效能的下降。
⑵計算梯度的幅度與方向。OpenCV中的Canny函式是使用Sobel卷積核來計算梯度的幅度與方向的。計算出的幅度與方向作為後面提取影象邊緣的原始資料。
⑶非極大值抑制。非極大值抑制的目的是剔除第⑵部中計算出來的結果中的大部分非邊緣點。其原理是通過畫素的八鄰域來判斷要不要將這個畫素置為邊緣點,如果不置為邊緣點,那麼就置為背景色。判斷的方法如下:
①判斷範圍是畫素的八鄰域,所以是區域性最優判斷法;
②判斷的標準是如果某個畫素在其八鄰域內,既是最大值,梯度值也最大,那麼可判斷該點為畫素邊緣點,否則就不是。如何判斷呢?
首先,梯度值的判斷是很好判斷的,用邊緣檢測微分運算元得到的結果直接比較就可以了,但是最大值的判斷可不是隻比較其旁邊的八個點哦,還要比較另外兩個點,詳情如下:
如果已經判斷出上圖中的C點比其旁邊的8個點的畫素值都大,那麼接下來判斷上圖中dTmp1和dTmp2的值是否也小於C點的值,那麼dTmp1和dTmp2的值怎麼求呢?上圖中藍色的線條方向為C點的梯度方向,這樣就可以確定其區域性的最大值肯定分佈在這條線上,也即除了C點外,梯度方向的交點dTmp1和dTmp2這兩個點的值也可能會是區域性最大值。因此,判斷C點灰度與這兩個點灰度大小即可判斷C點是否為其鄰域內的區域性最大灰度點。如果經過判斷,C點灰度值小於這兩個點中的任一個,那就說明C點不是區域性極大值,那麼則可以排除C點為邊緣。
⑷用滯後閾值演算法求解影象邊緣。上一步對邊緣檢測運算元的結果進行了非極大值抑制,接下來我們用二值化的方法來求解影象邊緣。單閾值處理邊緣效果不好,所以Cannny演算法中採用滯後閾值法求解。滯後閾值法需要設定一個高閾值和一個低閾值,解後按如下法則進行:
第一,如果某一畫素位置的梯度幅值超過高閾值,則畫素被保留為邊緣畫素;
第二,如果某一畫素位置的梯度幅值小於低閾值,則畫素被排除;
第三,如果某一畫素位置的幅值在兩個閾值之間,該畫素僅僅在連線到一個高於高閾值的畫素時被保留。
在以上的法則中,推薦的高閾值與低閾值比在2:1到3:1之間!
通過消除噪聲、計算梯度幅度與方向、非極大值抑制及用滯後閾值演算法求解影象邊緣四個步驟就可實現Canny邊緣檢測。
Canny函式原型如下:
void Canny( InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false );
Image為輸入影象,單通道8bit;
edges為輸出影象,與輸入影象同類型同尺寸;
threshold1為滯後閾值演算法的低閾值;
threshold2為為滯後閾值演算法的高閾值;
apertureSize為Sobel運算元的視窗(卷積核)階數;
L2gradient表示是否使用L2範數來計算影象梯度幅值。
以上為轉載部分----------------------------------------------------------------------------------------------------------------------------
下面記錄一下對第二步中Sobel運算元計算畫素梯度的理解:Sobel運算元是一種典型的用於邊緣檢測的線性濾波器,如果把影象看作二維影象,那麼Sobel運算元就是影象在垂直和水平方向上像灰度變化的速度。