(20)Canny边缘检测

/*
 *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);

}

猜你喜欢

转载自blog.csdn.net/nuc_sheryl/article/details/81068974