OpenCV-C++ Canny算法介绍
注意:文章原理还很不完善,仅供本人学习使用;
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: