天天看點

邊緣檢測之Canny算子

  邊緣檢測一直在用,opencv對這一些個邊緣檢測算子也都做了實作和封裝,而且相信經曆這麼多年,算法都已經優化到了接近極限。以前都是拿來就用,真正去窺探實作細節還是第一次。之是以選擇看canny算子,還是因為個人認為canny算子擁有一些其他算子沒有的優勢,在其他算子的基礎上剔去了邊緣上的多餘點,并且也檢測和實作了邊緣的封閉,是以最友善并适合運用于實際工程。

 canny算子的工作流程其實就四步:

高斯濾波-梯度計算-非極大值抑制-門檻值遲滞(雙門檻值檢測)

①高斯濾波

 印象裡高斯濾波是會平滑圖像細節弱化邊緣的,按理來說濾波處理和邊緣檢測應該是沖突的操作,為什麼canny算子在提取邊緣之前會進行一次高斯濾波呢?個人認為算法是希望在提取邊緣和去噪之間進行折衷,在不丢失圖像的主要邊緣資訊的同時濾除部分高頻噪聲。(不過粗略的看了一下opencv裡canny算子的實作,貌似是沒有高斯濾波這一步的。也有資料說sobel算子本身有高斯濾波的特性了,opencv裡canny算子的梯度計算是用的是sobel算子核心做圖像卷積)網上找的一些大牛們自己實作的canny算子一般都會有高斯濾波這一步。

 高斯濾波的實作細節想必都很熟悉了,就不再贅述。 高斯濾波模闆例:

邊緣檢測之Canny算子
②梯度計算

canny一般用的其他算子的核來做梯度幅值和方向的計算, 比如Roberts:

邊緣檢測之Canny算子

或者Sobel:

邊緣檢測之Canny算子

梯度幅值的計算公式:

G(x,y) = sqrt(Sx^2+Sy^2)

梯度方向計算公式:

R(x,y) = acrtan(Sy/Sx)

梯度的幅值和方向是極大值抑制會用到的資料。

③非極大值抑制

 做完前兩步後其實我們其實已經提取到了圖像的大緻輪廓了,但是将幅值反向投影回灰階空間後可以看到,大多數邊緣呈兩邊暗中間亮的屋脊狀,為了取得單個像素寬度的邊緣,canny算子對圖像的幅值矩陣進行了非極大值抑制。

非極大值一直的工作原理是什麼?引用likezhaobin大神的一段解釋:

 要進行非極大值抑制,就首先要确定像素點C的灰階值在其8值鄰域内是否為最大。下圖中藍色的線條方向為C點的梯度方向,這樣就可以确定其局部的最大值肯定分布在這條線上,也即出了C點外,梯度方向的交點dTmp1和dTmp2這兩個點的值也可能會是局部最大值。是以,判斷C點灰階與這兩個點灰階大小即可判斷C點是否為其鄰域内的局部最大灰階點。如果經過判斷,C點灰階值小于這兩個點中的任一個,那就說明C點不是局部極大值,那麼則可以排除C點為邊緣。這就是非極大值抑制的工作原理。

邊緣檢測之Canny算子

 但是像素點的分布是離散而非線性的,dTmp1和dTmp2兩個交點位置大多數情況下并不實際存在像素點,是以canny算子在做非極大值抑制時比對的像素點是距離dTmp1和dTmp2最近的兩個像素點,也就是下文所說的g1,g2和g3,g4。

非極大值抑制步驟:

1.将梯度方向R(x,y)以就近原則歸類到四個角度類中(0-45,45-90,90-135,135-180)。

2.擷取該點所處的8值領域内其他8個點中距離梯度向量最近的兩個點對(g1,g2)、(g3,g4)。

還是以95-135的梯度向量(上圖)為例,如上圖,藍線為c點的梯度方向,該方向引出的正反兩條射線分别穿過8值領域的兩條邊(紅線),則在這兩條邊上距離射線(藍線)最近的兩個點即為g1,g2及g3,g4。

3.将c點處的梯度幅值分别與g1,g2,g3,g4點做對比,如果小于其中的任何一個,則置c點處幅值為0,否則認為它是潛在邊緣,保留其幅值。

處理完後即可得到一張包含所有潛在邊緣的梯度幅值-灰階映射圖。

④門檻值遲滞

 門檻值遲滞是翻譯過來的叫法(threshold Hysteresis),通俗點可以叫雙門檻值法檢測,目的是去除第三步後結果中的一些噪聲邊緣及一些假邊緣,算法和很簡單:

0.取一高一低兩個門檻值。

1.假如該像素點處灰階值大于高門檻值,保留作為邊緣。

2.假如該像素點處灰階值小于低門檻值,舍棄。

3.假如該像素點處灰階值大于低門檻值小于高門檻值,當其與一個大于高門檻值的像素點相鄰時,保留作為邊緣,否則舍棄。

OK,以上就是canny算子做邊緣檢測的流程啦!