canny運算元是邊緣檢測運算元中最常用的一種,是公認效能優良的一種運算元,常被其它邊緣檢測運算元作為標準運算元進行優劣分析。
canny演算法基本可以分為3個步驟:平滑、梯度計算、基於梯度值及梯度方向的候選點過濾
(1)平滑
影象梯度的計算對雜訊很敏感,因此必須首先對其進行低通濾波。在這裡使用5*5的高斯濾波器,為了提高濾波效率,使用近似的高斯模板(圖1-1)
圖1-1. 5*5的高斯模板
(2)梯度計算
這一步主要通過計算每個畫素x、y方向的梯度,獲得該點的梯度值和梯度方向。在這裡使用一階邊緣檢測微分運算元sobel(圖1-2)
圖1-2. sobel邊緣檢測運算元
對每個點,由公式
具體處理的時候,將角度歸併到0、45、90、135這4個方向
(3)候選點過濾
這一步主要包含2塊內容:基於梯度方向的非最大值抑制、基於雙閾值的候選點剔除及斷點連線
基於梯度方向的非最大值抑制
非最大值抑制主要考慮這種情況:處於邊緣上的點,其鄰域內梯度方向上(正方向和負方向)的點的梯度響應應該比該點小
然而實際中由梯度方向得到的鄰域點的座標往往是浮點值,因此需要對該值進行處理,對映到整數值
在這裡介紹3種處理辦法:
1. 將角度近似處理到0,45,90,135這4個方向,這樣只需要對當前點向左、右、上、下移動就可以了。這種方式計算簡單,但誤差較大
2. 對浮點座標進行插值(圖1-3)
圖1-3. 通過g1,g2 和g3,g4的加權和分別得到兩個浮點座標的梯度值(來自
考慮圖示的情況,有dtemp1 = g1*weight + g2*(1-weight),dtemp2 = g3*weight + g4*(1-weight)。其中weight由x和y方向的梯度值確定:
基於雙閾值的候選點剔除及斷點連線
為了進一步過濾雜訊的影響,非極大值抑制後,canny使用一高一低兩個閾值處理梯度響應矩陣。
1.對響應值大於高閾值的點,直接標記為邊緣點
2.對響應值小於高閾值,但大於低閾值的點,考察其8鄰域,如果存在已被標記的邊緣點,則也標記該點為邊緣點
關於高低閾值的設定,文章統計邊緣點的數目,將邊緣點按梯度響應從小到大排列,取位於第79%的那個點對應的梯度響應值作為高閾值,取其一半為低閾值
typedef struct mysize
_size;
#define _max(a,b) ((a)>(b)?(a):(b))
#define _min(a,b) ((a)
void _edgecanny(unsigned char* img, unsigned char* out, _size imgsize, int lowthreshold, int highthreshold);
templatevoid convolution(unsigned char* srcimg, t1* dstimg, _size imgsize, int* kernel, _size kersize, bool div);
void calcgradangle(int* mx, int* my, float* grad, float* angle, _size imgsize);
void depress(int* mx, int* my, float* grad, float* angle, unsigned char* out, _size imgsize);
void depress_(float* grad, float* angle, unsigned char* out, _size imgsize, int radius);
void doublethreshold(unsigned char* src, float* grad, _size imgsize, int low, int high);
void getthresholds(unsigned char* src, float* grad, _size imgsize, int* high, int* low);
void connectlow(unsigned char* src, float* grad, _size imgsize, int y, int x, int low);
void main()
else if((angle[index]>=135 && angle[index]<180) ||
(angle[index]>=315 && angle[index]<360))
else if((angle[index]>=45 && angle[index]<90) ||
(angle[index]>=225 && angle[index]<270))
else if((angle[index]>=0 && angle[index]<45) ||
(angle[index]>=180 && angle[index]<225))
if(grad[index]>=v12 && grad[index]>=v34)
out[index] = 128;
else
out[index] = 0;
}} }
}void depress_(float* grad, float* angle, unsigned char* out, _size imgsize, int radius)
} }}void doublethreshold(unsigned char* src, float* grad, _size imgsize, int low, int high)
} }for(int i=0; i=pos)
}*low = int(0.5*(*high)+0.5);
}void connectlow(unsigned char* src, float* grad, _size imgsize, int y, int x, int low)
; int ynum[8] = ;
for(int i=0; i<8; i++)}}}
效果((a)為opencv函式結果(閾值取140,70), (b)為對浮點座標插值的效果,(c)和(d)為在浮點座標周圍取4個整數值的效果,前者半徑為1,後者為4)
Canny邊緣檢測
1.canny邊緣檢測基本原理 1 圖象邊緣檢測必須滿足兩個條件 一能有效地抑制雜訊 二必須盡量精確確定邊緣的位置。2 根據對訊雜比與定位乘積進行測度,得到最優化逼近運算元。這就是canny邊緣檢測運算元。3 類似與marr log 邊緣檢測方法,也屬於先平滑後求導數的方法。2.canny邊緣檢測演...
Canny邊緣檢測
canny邊緣檢測是一種非常流行的邊緣檢測演算法,是john canny在1986年提出的。它是乙個多階段的演算法,即由多個步驟構成。1.影象降噪 2.計算影象梯度 3.非極大值抑制 4.閾值篩選 我們就事後諸葛亮,分析下這個步驟的緣由。首先,影象降噪。我們知道梯度運算元可以用於增強影象,本質上是通...
Canny邊緣檢測
canny邊緣檢測演算法 五個步驟 1.高斯模糊 gaussianblur 2.灰度轉換 cvtcolor 3.計算梯度 sobel scharr 4.非最大訊號抑制 5.高低閾值連線輸出二值影象 import cv2 def edge demo image blurred cv2.gaussian...