1. 程式人生 > >數字影象處理---通俗Canny邊緣檢測

數字影象處理---通俗Canny邊緣檢測

0.何謂邊緣

說起邊緣,那肯定是影象中明暗變化比較劇烈的畫素所組成的線條。從視覺的角度來講,我們首先注意到的其實就是一些簡單的線條,然後再由這些簡單的線條組合成更加抽象的概念來使得我們能夠認識出我眼前的是個啥。就好比下面的圖,你光看那個邊緣圖,是不是大概就能看出來原圖裡是個女人?
在這裡插入圖片描述
右邊的邊緣圖其實就是把原圖中的邊緣提取出來之後的圖,從直覺上也能夠看得出來,所謂的邊緣檢測無非就是對整個圖的畫素做畫素級的二分類。要麼是邊緣點(用白色表示),要麼不是邊緣點(用黑色表示)。把這些點展示出來就成了邊緣圖。

當然邊緣檢測的演算法有很多種,這篇部落格就先簡單嗶嗶一下最為經典的邊緣檢測演算法—Canny!!

1.Canny邊緣檢測演算法流程

其實Canny演算法的步驟就那麼幾步:
1.高斯濾波
2.計算影象的梯度和梯度方向
3.非極大值抑制
4.雙閾值篩選邊緣

很明顯第一步無非就是減少影象中的噪聲,增強邊緣檢測的魯棒性。第二步是想把邊緣給強調出來,但是由於強調出來有二義性,所以用第三步來過濾一些邊緣點。但是第三步可能過濾不乾淨,所以就有了第四步的套路來過濾乾淨。so。。。下面就一個一個的來嗶嗶。

2.高斯濾波

高斯濾波和其他的濾波器套路基本上一致,無非就是一個濾波核在原圖上摩擦摩擦,一步一步似爪牙,似魔鬼的步伐。。。所以高斯濾波的效果如何,取決於濾波核的大小和裡面的值。
在這裡插入圖片描述
那現在的主要矛盾就是濾波核裡的值怎麼來確定。其實非常簡單,就是通過這麼一個公式:
在這裡插入圖片描述


這個公式的意圖是啥呢?其實就是個濾波核裡的值儘量的填成一個二維的高斯分佈。我們可以舉個栗子:
1.假設我的濾波核是3*3的
2.假設我的高斯分佈的標準差為1也就是σ=1
3.x和y代表濾波核中各個點相對於中心點的座標,就像醬紫:
在這裡插入圖片描述
有了這些假設之後,我們就能很簡單的把濾波核對應的值給算出來,就像醬紫:
在這裡插入圖片描述
但是這個時候算出來的值有個問題,如果把所有的9個值全加起來不等於1!!!(概率合應該為1)所以我們要對其進行歸一化,讓所有的9個值加起來等於1。其實歸一化很簡單,就是個9個值全加起來也就是(0.0585+0.0965+0.0585+…+0.0585=0.7792),然後把每個值都除以這個0.7792,就能得到歸一化後的濾波核。(這個時候你會發現所有值全加起來等於1)
在這裡插入圖片描述

而且可以腦補一下,如果波濾核的size比較大,然後每個格子裡面的值看成是概率的話。其實就可以腦補成醬紫的圖(很明顯的一個二維高斯分佈):
在這裡插入圖片描述
確定了濾波核的值之後,就可以快樂的濾波了。

3. 計算影象的梯度和梯度的方向

要算影象的梯度,肯定會想到影象的梯度運算元。在Canny中用到的梯度運算元是Sobel運算元,說是運算元,其實就是濾波核。Sobel運算元主要分為兩個,一個是用來計算水平方向的梯度,另一個用來計算豎直方向的梯度。
在這裡插入圖片描述
在這裡插入圖片描述
所以,對原圖用第一個濾波核就能算出影象的水平方向的梯度,用第二個濾波核就能算出影象的豎直方向的梯度。

有了兩個方向的梯度之後,其實就能算出影象的梯度和梯度的方向了。因為已經有了水平和豎直了,要算總的梯度,無非就是勾股定理嘛~~~~

在這裡插入圖片描述
也就是說
影象的梯度值 = 開根號(豎直方向的梯度幅值的平方+水平方向的梯度幅值的平方)

影象的方向 = arctan(豎直方向的梯度幅值/水平方向的梯度幅值)

4. 非極大值抑制

假設現在拿到了梯度方向的圖是醬紫:
在這裡插入圖片描述
梯度幅值的圖是醬紫:
在這裡插入圖片描述
那如果要做非極大值抑制,就還需要個東西,就是這個:
在這裡插入圖片描述
這個表達的意思非常簡單,中間的方塊可以看成是一個3*3的區域,然後線代表的是角度。比如(-1,1)這個點的角度是45度,(0, 1)這個點的角度是0度。那這個東西有啥用呢,舉個栗子:
如果我要對梯度幅值圖裡第2行第2列的那個點(值是144)做非極大值抑制,那我就看我對應的方向的值是多少,很明顯是26。那26很明顯和45度更加接近,所以我要做非極大值抑制的時候所要對比的梯度幅值的點就是45度那根線所對應的點,也就是5和3。此時可以看出,144>5並且144>3,所以144是個極大值點,所以這個點就不會被抑制。

那如果我要對梯度幅值圖裡第5行第2列的點(值是178)做非極大值抑制,那很明顯它的方向也就是角度是7度,7度離0度更近,所以我要做非極大值抑制的時候所要對比的梯度幅值的點就是0度那根線所對應的點,也就是180和14。此時可以看出,178<180並且178>14,所以178不是個極大值點,所以這個點就要被捨棄,把他賦成0。

很明顯,對整個圖做完非極大值抑制之後,是極大值的點得到了保留,不是極大值的點就都賦成了0。

5.雙閾值篩選邊緣

我們要做邊緣檢測目的是把邊緣點設定成255,非邊緣點設定成0。但做完非極大值抑制之後,圖中的點雖然有一部分已經被抑制成了0。但我們還不知道應該把剩下的哪些點設定成邊緣點。那有的童鞋可能會覺得,我設個閾值不就好了?我梯度值大於某個閾值我就認為是邊緣點。這樣當然可以,但是效果不會太好。所以前輩們擼了個雙閾值篩選邊緣的套路。套路如圖:
在這裡插入圖片描述
套路呢從圖就能很容易的看出來,就是會有兩個閾值A和B(A<B),如果我當前點的梯度值比A還小那我就認為不是邊緣點,如果比B還大那肯定是邊緣點。這個很容易理解。那介於A和B的點呢?Canny的策略是如果我這種介於AB之間的點他與大於B的點是聯通的,那我就認為這個點事邊緣點,否則就不是。這個套路其實很天朝的XX考試很相似,我考試的分數如果比分數線低,那肯定GG。如果我的分數比分數線高出很多,那就美滋滋。如果我的分數比較中庸,那我可能就會去找關係找大腿,如果關係夠硬,那我可能就美滋滋了。
在這裡插入圖片描述

OK,這樣一套流程下來,Canny邊緣檢測就做完了,希望這篇部落格對想了解Canny演算法大致流程的童鞋有一定的幫助。也歡迎各位大佬吐槽。