算法介绍
- Canny是边缘检测算法,在1986年提出
- 是一个很好的边缘检测器
- 很常用也很好用的图像处理方法
## 算法实现步骤
- 高斯模糊
GaussianBlur()
- 灰度转换
cvtColor
- 计算梯度
Sobel\Scharr
-
KaTeX parse error: Undefined control sequence: \ at position 75: … \end{bmatrix} \̲ ̲
-
KaTeX parse error: Undefined control sequence: \ at position 75: … \end{bmatrix} \̲ ̲
-
- 非最大信号抑制 横纵方向只留下最大的点,防止边缘线过宽
- 这一步的目的是将模糊(blurred)的边界变得清晰(sharp)。通俗的讲,就是保留了每个像素点上梯度强度的极大值,而删掉其他的值。对于每个像素点,进行如下操作:
- 将其梯度方向近似为以下值中的一个(0,45,90,135,180,225,270,315)(即上下左右和45度方向)角度值=arctan(Gy/Gx)
- 比较该像素点,和其梯度方向正负方向的像素点的梯度强度
- 如果该像素点梯度强度最大则保留,否则抑制(删除,即置为0)
- 参考链接:https://blog.csdn.net/weixin_43410934/article/details/95230479
- 高低阈值输出二值图像
- T1、T2为阈值,凡是高于T2的都保留,凡是小于T1都丢弃,从高于T2的像素出发,凡是大于T1而且相连的,都保留,最终得到一个输出二值图像
- 推荐的高低阈值比值为T2:T1=3:1/2:1,其中T2为高阈值,T1为低阈值
- 低于阈值1的像素点会被认为不是边缘;
- 高于阈值2的像素点会被认为是边缘;
- 在阈值1和阈值2之间的像素点,若与第2步得到的边缘像素点相邻,则被认为是边缘,否则被认为不是边缘
函数API
函数API
void Canny(cv::InputArray src, cv::OutputArray dst,double threshold1, double threshold2,int apertureSize=3,bool L2gradient=false);
参数介绍
- src: 原图像, 单通道灰度图像
- dst: 生成的图像
- threshold1,threshold2:函数的两个阀值1为低阈值2为高阈值
- apertureSize:算子大小,默认为3
- L2gradient:是否采用更精确的方式计算图像梯度,true采用L2方式计算梯度两个方向的梯度平方和再开方,比较消耗CPU,费时长结果精确。
G
=
G
x
2
+
G
y
2
x
G=\sqrt{Gx^2+Gy^2 x}
G=Gx2+Gy2xfalse采用L1方式计算梯度即采用两个方向分别的梯度绝对值和来进行计算,结果不精确但是速度快。
G = ∣ G x ∣ + ∣ G y ∣ G=|Gx|+|Gy| G=∣Gx∣+∣Gy∣
代码
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
using namespace std;
#define Pic_Path "/home/image/Pictures/"
#define Pic_Name "model1.jpg"
cv::Mat gray_src;
int cur_val=50;
int max_val=255;
void canny_demo(int ,void *);
int main(void)
{
string pic = string(Pic_Path) + string(Pic_Name);
cout << pic << endl;
cv::Mat src;
src = cv::imread(pic.c_str());
cv::namedWindow("原始图片",cv::WINDOW_AUTOSIZE);
cv::imshow("原始图片",src);
cv::cvtColor(src,gray_src,CV_BGR2GRAY);
cv::namedWindow("边缘图像",cv::WINDOW_AUTOSIZE);
cv::createTrackbar("调整阈值","边缘图像",&cur_val,max_val,canny_demo);
canny_demo(0,0);
cv::waitKey(0);
cv::destroyAllWindows();
}
void canny_demo(int ,void *)
{
cv::Mat dst;
cv::Canny(gray_src,dst,cur_val,cur_val*2,3,false);
cv::imshow("边缘图像",dst);
}