/*
*Canny边缘检测
*Canny算法介绍
Canny是边缘检测算法, 在1986年提出的,是一个很好的边缘检测器,很常用也很实用的图像处理方法
五步in cv::Canny
1.高斯模糊-GaussianBlur 所有图像的模糊都是对图像进行降噪,把细微的可能有影响结果的点都给去掉,免得它影响最终算法的结果
2.灰度转换-cvtColor
3.计算梯度-Sobel/Scharr
4.非最大信号抑制 边缘的信号很强,但边缘只能有一个,不能说你这么很宽都是边缘,所以要对非边缘的一些像素进行压制
就是如果在它的方向上面如果它不是最大值的话我们就把它去掉,切向是角度的方向,法向是它跟垂直90度的
方向,在它左右两边如果值都小于当前的这个那么我们就把它去掉
对图像所有的点都做非最大信号抑制
θ取值范围在-π/2到π/2加上π/2就是0到π之间,这个θ就是说我们这个梯度的方向是什么,梯度在向哪个方向上面变化率最大
x方向变化很大的话θ就会很小,就得到变化的趋势向哪一个方向,这就是我们梯度的方向,我们跟梯度垂直的方向上面在它的左边和右边和中间的值相比,
如果都比它小左边和右边都去掉,中间最大值这个保留,这个叫做非最大信号抑制,反正就是把较小的去掉了
5.高低阈值输出二值图像 第四步后都是一些边缘像素了,有的边缘是连接在一起的,有的是各种各样的干扰,它跟边缘没有连起来,通过
高低阈值设置进行一个边缘连接,如果大于最高阈值的像素都要保留下来,如果小于最低阈值的像素都要舍弃,如果在
这两个阈值之间的要对它进行阈值连接,如果这个值有跟它相邻的高的阈值,最终这个像素就跟高的阈值相连并且大于
最小的那个像素值,然后保留并且跟高阈值的连接成一条线,这就是边缘连接,边缘连接之后我们就得到二值图像就输出
a.如果某一像素位置的幅值超过 高 阈值, 该像素被保留为边缘像素。
b.如果某一像素位置的幅值小于 低 阈值, 该像素被排除。
c.如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于 高 阈值的像素时被保留。
Canny 推荐的 高:低 阈值比在 2:1 到3:1之间。
T1, T2为阈值,凡是高于T2的都保留,凡是小于T1都丢弃,从高于T2的像素出发,凡是大于T1而且相互连接的,都保留。最终得到一个输出二值图像。
推荐的高低阈值比值为 T2: T1 = 3:1/2:1其中T2为高阈值,T1为低阈值
API – cv::Canny
Canny(
InputArray src, // 8-bit的输入图像,当时它不支持彩色图像,所以要先把图像转为灰度
OutputArray edges,// 输出边缘图像, 一般都是二值图像,背景是黑色
double threshold1,// 低阈值,常取高阈值的1/2或者1/3
double threshold2,// 高阈值
int aptertureSize,// Soble算子的size,通常3x3,取值3
bool L2gradient // 选择 true表示是L2来归一化,否则用L1归一化, L1表示用Sobel的两个方向的算子取绝对值再相加的和
L2表示用Sobel的两个方向的算子平方和再开根号
)
*/
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat src, gray_src, dst;
int t1_value = 50; //影响Canny的结果是阈值
int max_value = 255; //得出来的应该是二值图像,所以不能再大了
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int, void*);
int main()
{
src = imread("D:/A_Graduation/Pictures/Segmentatio/1.jpg");
imshow("src", src);
cvtColor(src, gray_src, CV_BGR2GRAY);
createTrackbar("Threshold Value: ", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo); //Trackbar寻找最佳阈值
Canny_Demo(0, 0); //call一下Canny
waitKey(0);
return 0;
}
void Canny_Demo(int, void*) {
Mat edge_output;
//首先对它做一个blur
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT); //图像就是平滑之后的图像,降低了噪声
Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);
// dst.create(src.size(), src.type()); //对dst进行初始化
// src.copyTo(dst, edge_output);//第二个参数是mask,加上mask就是说,如果mask是非零的就它就把那个像素拷贝到dst,如果mask是零的话就不要拷贝
//Canny之后它会把一些非零的边缘像素因为是最强的保留下来,只有边缘的像素会被拷贝
//用edge_output作为mask把这些有像素的是1的,二值图像上面是白色的东西给它把原像素拷贝到上面显示,
//所以你看到的出来的结果是彩色的
// imshow(OUTPUT_TITLE, dst);
imshow(OUTPUT_TITLE, ~edge_output);
}