注意:文章原理還很不完善,僅供本人學習使用;
Canny理論原理
Canny邊緣檢測器是由John F. Canny在1986年提出,Canny被稱為最優檢測器,其目標滿足以下三個主要標准:
- 低錯誤率:對已有的邊界能夠有很好的檢測;
- 良好的定位:即檢測到的邊緣像素和實際邊緣像素之間的距離必須最小化;
- 最小響應:即每邊只有一個響應;
Canny算法主要包含以下五個步驟:
過濾噪聲
使用高斯濾波器去噪,高斯核如下圖所示:
計算圖像梯度
首先,在圖像利用Sobel
算子計算x, y
兩個方向的梯度:
其次,計算梯度的強度和方向:
其中,梯度的方向被四舍五入到[0, 45, 90, 135]這幾個角度;
非最大值抑制算子(NMS)
抑制那些梯度不夠大的像素點,只保留最大的像素點,從而達到瘦邊的目的;
雙閾值算法檢測邊緣和連接邊緣
經過NMS算法后,設置兩個閾值\(T_1, T_2\),通常\(T_1\)是\(T_2\)的\(1/2\)或者\(1/3\);
- 梯度值大於\(T_2\)的像素點稱為強邊緣,保留作為圖像邊緣;
- 梯度值小於\(T_1\)的像素點不是邊緣,舍棄;
- 針對梯度值大於\(T_1\),小於\(T_2\)的像素點,稱為弱邊緣;
針對弱邊緣,需要進一步判定其是否的真正的邊緣像素點;判別的方法就是,當弱邊緣像素點周圍8個領域內存在強邊緣像素時,則該弱邊緣變成強邊緣點,否則不是邊緣點;
OpenCV Canny使用
Canny
API的介紹:
void Canny( InputArray image, OutputArray edges,
double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false );
src
輸入圖像,必須是8-bits;edges
輸出的圖像邊緣threshold1, threshold2
對應於上述的\(T_1, T_2\);apertureSize
是Sobel
算子的大小;L2gradient
表示計算梯度值時是否使用\(L2\)(就是默認的計算方式);
如果設置L2gradient=True
,則梯度值的計算方式為:
\[G = |G_x| + |G_y| \]
使用方式:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
/**
* 邊緣處理
*/
Mat src, srcBlur, srcGray;
const int MAX_THRESHOLD = 255;
int t1_value = 50;
char output_wind[] = "output";
void Canny_Demo(int, void*);
int main(){
// 讀取圖像
src = imread("/home/chen/dataset/lena.jpg");
if (src.empty()){
cout << "could not load image." << endl;
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
GaussianBlur(src, srcBlur, Size(3, 3), 0, 0);
cvtColor(srcBlur, srcGray, COLOR_BGR2GRAY);
namedWindow(output_wind, WINDOW_AUTOSIZE);
createTrackbar("Threshold: ", output_wind, &t1_value, MAX_THRESHOLD, Canny_Demo);
Canny_Demo(0, 0);
waitKey(0);
return 0;
}
void Canny_Demo(int, void*){
Mat edgeOutput;
Canny(srcGray, edgeOutput, t1_value, t1_value*2, 3, false);
imshow(output_wind, edgeOutput);
}
Reference: